Home | History | Annotate | Download | only in nfs
      1      0       stevel /*
      2      0       stevel  * CDDL HEADER START
      3      0       stevel  *
      4      0       stevel  * The contents of this file are subject to the terms of the
      5   1676          jpk  * Common Development and Distribution License (the "License").
      6   1676          jpk  * You may not use this file except in compliance with the License.
      7      0       stevel  *
      8      0       stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9      0       stevel  * or http://www.opensolaris.org/os/licensing.
     10      0       stevel  * See the License for the specific language governing permissions
     11      0       stevel  * and limitations under the License.
     12      0       stevel  *
     13      0       stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14      0       stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15      0       stevel  * If applicable, add the following below this CDDL HEADER, with the
     16      0       stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17      0       stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18      0       stevel  *
     19      0       stevel  * CDDL HEADER END
     20      0       stevel  */
     21      0       stevel /*
     22   8662       Jordan  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     23      0       stevel  * Use is subject to license terms.
     24      0       stevel  */
     25      0       stevel 
     26      0       stevel /*
     27      0       stevel  *	Copyright (c) 1983,1984,1985,1986,1987,1988,1989  AT&T.
     28      0       stevel  *	All Rights Reserved
     29      0       stevel  */
     30      0       stevel 
     31      0       stevel #include <sys/param.h>
     32      0       stevel #include <sys/types.h>
     33      0       stevel #include <sys/systm.h>
     34      0       stevel #include <sys/cred.h>
     35      0       stevel #include <sys/buf.h>
     36      0       stevel #include <sys/vfs.h>
     37   3898          rsb #include <sys/vfs_opreg.h>
     38      0       stevel #include <sys/vnode.h>
     39      0       stevel #include <sys/uio.h>
     40      0       stevel #include <sys/errno.h>
     41      0       stevel #include <sys/sysmacros.h>
     42      0       stevel #include <sys/statvfs.h>
     43      0       stevel #include <sys/kmem.h>
     44      0       stevel #include <sys/dirent.h>
     45      0       stevel #include <sys/cmn_err.h>
     46      0       stevel #include <sys/debug.h>
     47      0       stevel #include <sys/systeminfo.h>
     48      0       stevel #include <sys/flock.h>
     49      0       stevel #include <sys/pathname.h>
     50      0       stevel #include <sys/nbmlock.h>
     51      0       stevel #include <sys/share.h>
     52      0       stevel #include <sys/atomic.h>
     53      0       stevel #include <sys/policy.h>
     54      0       stevel #include <sys/fem.h>
     55   1676          jpk #include <sys/sdt.h>
     56   2035        calum #include <sys/ddi.h>
     57   8662       Jordan #include <sys/zone.h>
     58      0       stevel 
     59      0       stevel #include <rpc/types.h>
     60      0       stevel #include <rpc/auth.h>
     61      0       stevel #include <rpc/rpcsec_gss.h>
     62      0       stevel #include <rpc/svc.h>
     63      0       stevel 
     64      0       stevel #include <nfs/nfs.h>
     65      0       stevel #include <nfs/export.h>
     66   7961      Natalie #include <nfs/nfs_cmd.h>
     67      0       stevel #include <nfs/lm.h>
     68      0       stevel #include <nfs/nfs4.h>
     69      0       stevel 
     70      0       stevel #include <sys/strsubr.h>
     71      0       stevel #include <sys/strsun.h>
     72      0       stevel 
     73      0       stevel #include <inet/common.h>
     74      0       stevel #include <inet/ip.h>
     75      0       stevel #include <inet/ip6.h>
     76   1676          jpk 
     77   1676          jpk #include <sys/tsol/label.h>
     78   1676          jpk #include <sys/tsol/tndb.h>
     79      0       stevel 
     80      0       stevel #define	RFS4_MAXLOCK_TRIES 4	/* Try to get the lock this many times */
     81      0       stevel static int rfs4_maxlock_tries = RFS4_MAXLOCK_TRIES;
     82      0       stevel #define	RFS4_LOCK_DELAY 10	/* Milliseconds */
     83   7387       Robert static clock_t  rfs4_lock_delay = RFS4_LOCK_DELAY;
     84   7387       Robert extern struct svc_ops rdma_svc_ops;
     85      0       stevel /* End of Tunables */
     86   7387       Robert 
     87   7387       Robert static int rdma_setup_read_data4(READ4args *, READ4res *);
     88      0       stevel 
     89      0       stevel /*
     90      0       stevel  * Used to bump the stateid4.seqid value and show changes in the stateid
     91      0       stevel  */
     92      0       stevel #define	next_stateid(sp) (++(sp)->bits.chgseq)
     93      0       stevel 
     94      0       stevel /*
     95      0       stevel  * RFS4_MINLEN_ENTRY4: XDR-encoded size of smallest possible dirent.
     96      0       stevel  *	This is used to return NFS4ERR_TOOSMALL when clients specify
     97      0       stevel  *	maxcount that isn't large enough to hold the smallest possible
     98      0       stevel  *	XDR encoded dirent.
     99      0       stevel  *
    100      0       stevel  *	    sizeof cookie (8 bytes) +
    101      0       stevel  *	    sizeof name_len (4 bytes) +
    102      0       stevel  *	    sizeof smallest (padded) name (4 bytes) +
    103      0       stevel  *	    sizeof bitmap4_len (12 bytes) +   NOTE: we always encode len=2 bm4
    104      0       stevel  *	    sizeof attrlist4_len (4 bytes) +
    105      0       stevel  *	    sizeof next boolean (4 bytes)
    106      0       stevel  *
    107      0       stevel  * RFS4_MINLEN_RDDIR4: XDR-encoded size of READDIR op reply containing
    108      0       stevel  * the smallest possible entry4 (assumes no attrs requested).
    109      0       stevel  *	sizeof nfsstat4 (4 bytes) +
    110      0       stevel  *	sizeof verifier4 (8 bytes) +
    111      0       stevel  *	sizeof entry4list bool (4 bytes) +
    112      0       stevel  *	sizeof entry4 	(36 bytes) +
    113      0       stevel  *	sizeof eof bool  (4 bytes)
    114      0       stevel  *
    115      0       stevel  * RFS4_MINLEN_RDDIR_BUF: minimum length of buffer server will provide to
    116      0       stevel  *	VOP_READDIR.  Its value is the size of the maximum possible dirent
    117      0       stevel  *	for solaris.  The DIRENT64_RECLEN macro returns	the size of dirent
    118      0       stevel  *	required for a given name length.  MAXNAMELEN is the maximum
    119      0       stevel  *	filename length allowed in Solaris.  The first two DIRENT64_RECLEN()
    120      0       stevel  *	macros are to allow for . and .. entries -- just a minor tweak to try
    121      0       stevel  *	and guarantee that buffer we give to VOP_READDIR will be large enough
    122      0       stevel  *	to hold ., .., and the largest possible solaris dirent64.
    123      0       stevel  */
    124      0       stevel #define	RFS4_MINLEN_ENTRY4 36
    125      0       stevel #define	RFS4_MINLEN_RDDIR4 (4 + NFS4_VERIFIER_SIZE + 4 + RFS4_MINLEN_ENTRY4 + 4)
    126      0       stevel #define	RFS4_MINLEN_RDDIR_BUF \
    127      0       stevel 	(DIRENT64_RECLEN(1) + DIRENT64_RECLEN(2) + DIRENT64_RECLEN(MAXNAMELEN))
    128      0       stevel 
    129      0       stevel /*
    130      0       stevel  * It would be better to pad to 4 bytes since that's what XDR would do,
    131      0       stevel  * but the dirents UFS gives us are already padded to 8, so just take
    132      0       stevel  * what we're given.  Dircount is only a hint anyway.  Currently the
    133      0       stevel  * solaris kernel is ASCII only, so there's no point in calling the
    134      0       stevel  * UTF8 functions.
    135      0       stevel  *
    136      0       stevel  * dirent64: named padded to provide 8 byte struct alignment
    137      0       stevel  *	d_ino(8) + d_off(8) + d_reclen(2) + d_name(namelen + null(1) + pad)
    138      0       stevel  *
    139      0       stevel  * cookie: uint64_t   +  utf8namelen: uint_t  +   utf8name padded to 8 bytes
    140      0       stevel  *
    141      0       stevel  */
    142      0       stevel #define	DIRENT64_TO_DIRCOUNT(dp) \
    143      0       stevel 	(3 * BYTES_PER_XDR_UNIT + DIRENT64_NAMELEN((dp)->d_reclen))
    144      0       stevel 
    145      0       stevel time_t rfs4_start_time;			/* Initialized in rfs4_srvrinit */
    146      0       stevel 
    147      0       stevel static sysid_t lockt_sysid;		/* dummy sysid for all LOCKT calls */
    148      0       stevel 
    149   7387       Robert u_longlong_t	nfs4_srv_caller_id;
    150   7387       Robert uint_t		nfs4_srv_vkey = 0;
    151      0       stevel 
    152      0       stevel verifier4	Write4verf;
    153      0       stevel verifier4	Readdir4verf;
    154      0       stevel 
    155   7387       Robert void	rfs4_init_compound_state(struct compound_state *);
    156      0       stevel 
    157      0       stevel static void	nullfree(caddr_t);
    158      0       stevel static void	rfs4_op_inval(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    159      0       stevel 			struct compound_state *);
    160      0       stevel static void	rfs4_op_access(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    161      0       stevel 			struct compound_state *);
    162      0       stevel static void	rfs4_op_close(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    163      0       stevel 			struct compound_state *);
    164      0       stevel static void	rfs4_op_commit(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    165      0       stevel 			struct compound_state *);
    166      0       stevel static void	rfs4_op_create(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    167      0       stevel 			struct compound_state *);
    168      0       stevel static void	rfs4_op_create_free(nfs_resop4 *resop);
    169      0       stevel static void	rfs4_op_delegreturn(nfs_argop4 *, nfs_resop4 *,
    170   5647         samf 			struct svc_req *, struct compound_state *);
    171   5647         samf static void	rfs4_op_delegpurge(nfs_argop4 *, nfs_resop4 *,
    172   5647         samf 			struct svc_req *, struct compound_state *);
    173      0       stevel static void	rfs4_op_getattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    174      0       stevel 			struct compound_state *);
    175      0       stevel static void	rfs4_op_getattr_free(nfs_resop4 *);
    176      0       stevel static void	rfs4_op_getfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    177      0       stevel 			struct compound_state *);
    178      0       stevel static void	rfs4_op_getfh_free(nfs_resop4 *);
    179      0       stevel static void	rfs4_op_illegal(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    180      0       stevel 			struct compound_state *);
    181      0       stevel static void	rfs4_op_link(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    182      0       stevel 			struct compound_state *);
    183      0       stevel static void	rfs4_op_lock(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    184      0       stevel 			struct compound_state *);
    185      0       stevel static void	lock_denied_free(nfs_resop4 *);
    186      0       stevel static void	rfs4_op_locku(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    187      0       stevel 			struct compound_state *);
    188      0       stevel static void	rfs4_op_lockt(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    189      0       stevel 			struct compound_state *);
    190      0       stevel static void	rfs4_op_lookup(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    191      0       stevel 			struct compound_state *);
    192      0       stevel static void	rfs4_op_lookupp(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    193      0       stevel 			struct compound_state *);
    194      0       stevel static void	rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop,
    195      0       stevel 				struct svc_req *req, struct compound_state *cs);
    196      0       stevel static void	rfs4_op_nverify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    197      0       stevel 			struct compound_state *);
    198      0       stevel static void	rfs4_op_open(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    199      0       stevel 			struct compound_state *);
    200      0       stevel static void	rfs4_op_open_confirm(nfs_argop4 *, nfs_resop4 *,
    201      0       stevel 			struct svc_req *, struct compound_state *);
    202      0       stevel static void	rfs4_op_open_downgrade(nfs_argop4 *, nfs_resop4 *,
    203      0       stevel 			struct svc_req *, struct compound_state *);
    204      0       stevel static void	rfs4_op_putfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    205      0       stevel 			struct compound_state *);
    206      0       stevel static void	rfs4_op_putpubfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    207      0       stevel 			struct compound_state *);
    208      0       stevel static void	rfs4_op_putrootfh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    209      0       stevel 			struct compound_state *);
    210      0       stevel static void	rfs4_op_read(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    211      0       stevel 			struct compound_state *);
    212      0       stevel static void	rfs4_op_read_free(nfs_resop4 *);
    213      0       stevel static void	rfs4_op_readdir_free(nfs_resop4 *resop);
    214      0       stevel static void	rfs4_op_readlink(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    215      0       stevel 			struct compound_state *);
    216      0       stevel static void	rfs4_op_readlink_free(nfs_resop4 *);
    217      0       stevel static void	rfs4_op_release_lockowner(nfs_argop4 *, nfs_resop4 *,
    218      0       stevel 			struct svc_req *, struct compound_state *);
    219      0       stevel static void	rfs4_op_remove(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    220      0       stevel 			struct compound_state *);
    221      0       stevel static void	rfs4_op_rename(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    222      0       stevel 			struct compound_state *);
    223      0       stevel static void	rfs4_op_renew(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    224      0       stevel 			struct compound_state *);
    225      0       stevel static void	rfs4_op_restorefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    226      0       stevel 			struct compound_state *);
    227      0       stevel static void	rfs4_op_savefh(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    228      0       stevel 			struct compound_state *);
    229      0       stevel static void	rfs4_op_setattr(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    230      0       stevel 			struct compound_state *);
    231      0       stevel static void	rfs4_op_verify(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    232      0       stevel 			struct compound_state *);
    233      0       stevel static void	rfs4_op_write(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    234      0       stevel 			struct compound_state *);
    235      0       stevel static void	rfs4_op_setclientid(nfs_argop4 *, nfs_resop4 *,
    236      0       stevel 			struct svc_req *, struct compound_state *);
    237      0       stevel static void	rfs4_op_setclientid_confirm(nfs_argop4 *, nfs_resop4 *,
    238      0       stevel 			struct svc_req *req, struct compound_state *);
    239      0       stevel static void	rfs4_op_secinfo(nfs_argop4 *, nfs_resop4 *, struct svc_req *,
    240      0       stevel 			struct compound_state *);
    241      0       stevel static void	rfs4_op_secinfo_free(nfs_resop4 *);
    242      0       stevel 
    243      0       stevel static nfsstat4 check_open_access(uint32_t,
    244      0       stevel 				struct compound_state *, struct svc_req *);
    245      0       stevel nfsstat4 rfs4_client_sysid(rfs4_client_t *, sysid_t *);
    246      0       stevel void rfs4_ss_clid(rfs4_client_t *, struct svc_req *);
    247      0       stevel 
    248      0       stevel /*
    249      0       stevel  * translation table for attrs
    250      0       stevel  */
    251      0       stevel struct nfs4_ntov_table {
    252      0       stevel 	union nfs4_attr_u *na;
    253      0       stevel 	uint8_t amap[NFS4_MAXNUM_ATTRS];
    254      0       stevel 	int attrcnt;
    255      0       stevel 	bool_t vfsstat;
    256      0       stevel };
    257      0       stevel 
    258      0       stevel static void	nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp);
    259      0       stevel static void	nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
    260      0       stevel 				    struct nfs4_svgetit_arg *sargp);
    261      0       stevel 
    262      0       stevel static nfsstat4	do_rfs4_set_attrs(bitmap4 *resp, fattr4 *fattrp,
    263      0       stevel 		    struct compound_state *cs, struct nfs4_svgetit_arg *sargp,
    264      0       stevel 		    struct nfs4_ntov_table *ntovp, nfs4_attr_cmd_t cmd);
    265      0       stevel 
    266   7387       Robert fem_t		*deleg_rdops;
    267   7387       Robert fem_t		*deleg_wrops;
    268   7387       Robert 
    269   7387       Robert rfs4_servinst_t *rfs4_cur_servinst = NULL;	/* current server instance */
    270   7387       Robert kmutex_t	rfs4_servinst_lock;	/* protects linked list */
    271      0       stevel int		rfs4_seen_first_compound;	/* set first time we see one */
    272      0       stevel 
    273      0       stevel /*
    274      0       stevel  * NFS4 op dispatch table
    275      0       stevel  */
    276      0       stevel 
    277      0       stevel struct rfsv4disp {
    278      0       stevel 	void	(*dis_proc)();		/* proc to call */
    279      0       stevel 	void	(*dis_resfree)();	/* frees space allocated by proc */
    280      0       stevel 	int	dis_flags;		/* RPC_IDEMPOTENT, etc... */
    281      0       stevel };
    282      0       stevel 
    283      0       stevel static struct rfsv4disp rfsv4disptab[] = {
    284      0       stevel 	/*
    285      0       stevel 	 * NFS VERSION 4
    286      0       stevel 	 */
    287      0       stevel 
    288      0       stevel 	/* RFS_NULL = 0 */
    289      0       stevel 	{rfs4_op_illegal, nullfree, 0},
    290      0       stevel 
    291      0       stevel 	/* UNUSED = 1 */
    292      0       stevel 	{rfs4_op_illegal, nullfree, 0},
    293      0       stevel 
    294      0       stevel 	/* UNUSED = 2 */
    295      0       stevel 	{rfs4_op_illegal, nullfree, 0},
    296      0       stevel 
    297      0       stevel 	/* OP_ACCESS = 3 */
    298      0       stevel 	{rfs4_op_access, nullfree, RPC_IDEMPOTENT},
    299      0       stevel 
    300      0       stevel 	/* OP_CLOSE = 4 */
    301      0       stevel 	{rfs4_op_close, nullfree, 0},
    302      0       stevel 
    303      0       stevel 	/* OP_COMMIT = 5 */
    304      0       stevel 	{rfs4_op_commit, nullfree, RPC_IDEMPOTENT},
    305      0       stevel 
    306      0       stevel 	/* OP_CREATE = 6 */
    307      0       stevel 	{rfs4_op_create, nullfree, 0},
    308      0       stevel 
    309      0       stevel 	/* OP_DELEGPURGE = 7 */
    310   5647         samf 	{rfs4_op_delegpurge, nullfree, 0},
    311      0       stevel 
    312      0       stevel 	/* OP_DELEGRETURN = 8 */
    313      0       stevel 	{rfs4_op_delegreturn, nullfree, 0},
    314      0       stevel 
    315      0       stevel 	/* OP_GETATTR = 9 */
    316      0       stevel 	{rfs4_op_getattr, rfs4_op_getattr_free, RPC_IDEMPOTENT},
    317      0       stevel 
    318      0       stevel 	/* OP_GETFH = 10 */
    319      0       stevel 	{rfs4_op_getfh, rfs4_op_getfh_free, RPC_ALL},
    320      0       stevel 
    321      0       stevel 	/* OP_LINK = 11 */
    322      0       stevel 	{rfs4_op_link, nullfree, 0},
    323      0       stevel 
    324      0       stevel 	/* OP_LOCK = 12 */
    325      0       stevel 	{rfs4_op_lock, lock_denied_free, 0},
    326      0       stevel 
    327      0       stevel 	/* OP_LOCKT = 13 */
    328      0       stevel 	{rfs4_op_lockt, lock_denied_free, 0},
    329      0       stevel 
    330      0       stevel 	/* OP_LOCKU = 14 */
    331      0       stevel 	{rfs4_op_locku, nullfree, 0},
    332      0       stevel 
    333      0       stevel 	/* OP_LOOKUP = 15 */
    334   7387       Robert 	{rfs4_op_lookup, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
    335      0       stevel 
    336      0       stevel 	/* OP_LOOKUPP = 16 */
    337   7387       Robert 	{rfs4_op_lookupp, nullfree, (RPC_IDEMPOTENT | RPC_PUBLICFH_OK)},
    338      0       stevel 
    339      0       stevel 	/* OP_NVERIFY = 17 */
    340      0       stevel 	{rfs4_op_nverify, nullfree, RPC_IDEMPOTENT},
    341      0       stevel 
    342      0       stevel 	/* OP_OPEN = 18 */
    343      0       stevel 	{rfs4_op_open, rfs4_free_reply, 0},
    344      0       stevel 
    345      0       stevel 	/* OP_OPENATTR = 19 */
    346      0       stevel 	{rfs4_op_openattr, nullfree, 0},
    347      0       stevel 
    348      0       stevel 	/* OP_OPEN_CONFIRM = 20 */
    349      0       stevel 	{rfs4_op_open_confirm, nullfree, 0},
    350      0       stevel 
    351      0       stevel 	/* OP_OPEN_DOWNGRADE = 21 */
    352      0       stevel 	{rfs4_op_open_downgrade, nullfree, 0},
    353      0       stevel 
    354      0       stevel 	/* OP_OPEN_PUTFH = 22 */
    355      0       stevel 	{rfs4_op_putfh, nullfree, RPC_ALL},
    356      0       stevel 
    357      0       stevel 	/* OP_PUTPUBFH = 23 */
    358      0       stevel 	{rfs4_op_putpubfh, nullfree, RPC_ALL},
    359      0       stevel 
    360      0       stevel 	/* OP_PUTROOTFH = 24 */
    361      0       stevel 	{rfs4_op_putrootfh, nullfree, RPC_ALL},
    362      0       stevel 
    363      0       stevel 	/* OP_READ = 25 */
    364      0       stevel 	{rfs4_op_read, rfs4_op_read_free, RPC_IDEMPOTENT},
    365      0       stevel 
    366      0       stevel 	/* OP_READDIR = 26 */
    367      0       stevel 	{rfs4_op_readdir, rfs4_op_readdir_free, RPC_IDEMPOTENT},
    368      0       stevel 
    369      0       stevel 	/* OP_READLINK = 27 */
    370      0       stevel 	{rfs4_op_readlink, rfs4_op_readlink_free, RPC_IDEMPOTENT},
    371      0       stevel 
    372      0       stevel 	/* OP_REMOVE = 28 */
    373      0       stevel 	{rfs4_op_remove, nullfree, 0},
    374      0       stevel 
    375      0       stevel 	/* OP_RENAME = 29 */
    376      0       stevel 	{rfs4_op_rename, nullfree, 0},
    377      0       stevel 
    378      0       stevel 	/* OP_RENEW = 30 */
    379      0       stevel 	{rfs4_op_renew, nullfree, 0},
    380      0       stevel 
    381      0       stevel 	/* OP_RESTOREFH = 31 */
    382      0       stevel 	{rfs4_op_restorefh, nullfree, RPC_ALL},
    383      0       stevel 
    384      0       stevel 	/* OP_SAVEFH = 32 */
    385      0       stevel 	{rfs4_op_savefh, nullfree, RPC_ALL},
    386      0       stevel 
    387      0       stevel 	/* OP_SECINFO = 33 */
    388      0       stevel 	{rfs4_op_secinfo, rfs4_op_secinfo_free, 0},
    389      0       stevel 
    390      0       stevel 	/* OP_SETATTR = 34 */
    391      0       stevel 	{rfs4_op_setattr, nullfree, 0},
    392      0       stevel 
    393      0       stevel 	/* OP_SETCLIENTID = 35 */
    394      0       stevel 	{rfs4_op_setclientid, nullfree, 0},
    395      0       stevel 
    396      0       stevel 	/* OP_SETCLIENTID_CONFIRM = 36 */
    397      0       stevel 	{rfs4_op_setclientid_confirm, nullfree, 0},
    398      0       stevel 
    399      0       stevel 	/* OP_VERIFY = 37 */
    400      0       stevel 	{rfs4_op_verify, nullfree, RPC_IDEMPOTENT},
    401      0       stevel 
    402      0       stevel 	/* OP_WRITE = 38 */
    403      0       stevel 	{rfs4_op_write, nullfree, 0},
    404      0       stevel 
    405      0       stevel 	/* OP_RELEASE_LOCKOWNER = 39 */
    406      0       stevel 	{rfs4_op_release_lockowner, nullfree, 0},
    407      0       stevel };
    408      0       stevel 
    409      0       stevel static uint_t rfsv4disp_cnt = sizeof (rfsv4disptab) / sizeof (rfsv4disptab[0]);
    410      0       stevel 
    411      0       stevel #define	OP_ILLEGAL_IDX (rfsv4disp_cnt)
    412      0       stevel 
    413      0       stevel #ifdef DEBUG
    414      0       stevel 
    415   7387       Robert int		rfs4_fillone_debug = 0;
    416   7387       Robert int		rfs4_no_stub_access = 1;
    417   7387       Robert int		rfs4_rddir_debug = 0;
    418   7387       Robert 
    419   7387       Robert static char    *rfs4_op_string[] = {
    420      0       stevel 	"rfs4_op_null",
    421      0       stevel 	"rfs4_op_1 unused",
    422      0       stevel 	"rfs4_op_2 unused",
    423      0       stevel 	"rfs4_op_access",
    424      0       stevel 	"rfs4_op_close",
    425      0       stevel 	"rfs4_op_commit",
    426      0       stevel 	"rfs4_op_create",
    427      0       stevel 	"rfs4_op_delegpurge",
    428      0       stevel 	"rfs4_op_delegreturn",
    429      0       stevel 	"rfs4_op_getattr",
    430      0       stevel 	"rfs4_op_getfh",
    431      0       stevel 	"rfs4_op_link",
    432      0       stevel 	"rfs4_op_lock",
    433      0       stevel 	"rfs4_op_lockt",
    434      0       stevel 	"rfs4_op_locku",
    435      0       stevel 	"rfs4_op_lookup",
    436      0       stevel 	"rfs4_op_lookupp",
    437      0       stevel 	"rfs4_op_nverify",
    438      0       stevel 	"rfs4_op_open",
    439      0       stevel 	"rfs4_op_openattr",
    440      0       stevel 	"rfs4_op_open_confirm",
    441      0       stevel 	"rfs4_op_open_downgrade",
    442      0       stevel 	"rfs4_op_putfh",
    443      0       stevel 	"rfs4_op_putpubfh",
    444      0       stevel 	"rfs4_op_putrootfh",
    445      0       stevel 	"rfs4_op_read",
    446      0       stevel 	"rfs4_op_readdir",
    447      0       stevel 	"rfs4_op_readlink",
    448      0       stevel 	"rfs4_op_remove",
    449      0       stevel 	"rfs4_op_rename",
    450      0       stevel 	"rfs4_op_renew",
    451      0       stevel 	"rfs4_op_restorefh",
    452      0       stevel 	"rfs4_op_savefh",
    453      0       stevel 	"rfs4_op_secinfo",
    454      0       stevel 	"rfs4_op_setattr",
    455      0       stevel 	"rfs4_op_setclientid",
    456      0       stevel 	"rfs4_op_setclient_confirm",
    457      0       stevel 	"rfs4_op_verify",
    458      0       stevel 	"rfs4_op_write",
    459      0       stevel 	"rfs4_op_release_lockowner",
    460      0       stevel 	"rfs4_op_illegal"
    461      0       stevel };
    462      0       stevel #endif
    463      0       stevel 
    464   7387       Robert void	rfs4_ss_chkclid(rfs4_client_t *);
    465   7387       Robert 
    466   7387       Robert extern size_t   strlcpy(char *dst, const char *src, size_t dstsize);
    467   2035        calum 
    468      0       stevel #ifdef	nextdp
    469      0       stevel #undef nextdp
    470      0       stevel #endif
    471      0       stevel #define	nextdp(dp)	((struct dirent64 *)((char *)(dp) + (dp)->d_reclen))
    472      0       stevel 
    473      0       stevel static const fs_operation_def_t nfs4_rd_deleg_tmpl[] = {
    474   5599      jwahlig 	VOPNAME_OPEN,		{ .femop_open = deleg_rd_open },
    475   5599      jwahlig 	VOPNAME_WRITE,		{ .femop_write = deleg_rd_write },
    476   5599      jwahlig 	VOPNAME_SETATTR,	{ .femop_setattr = deleg_rd_setattr },
    477   3898          rsb 	VOPNAME_RWLOCK,		{ .femop_rwlock = deleg_rd_rwlock },
    478   5599      jwahlig 	VOPNAME_SPACE,		{ .femop_space = deleg_rd_space },
    479   5599      jwahlig 	VOPNAME_SETSECATTR,	{ .femop_setsecattr = deleg_rd_setsecattr },
    480   5599      jwahlig 	VOPNAME_VNEVENT,	{ .femop_vnevent = deleg_rd_vnevent },
    481   3898          rsb 	NULL,			NULL
    482      0       stevel };
    483      0       stevel static const fs_operation_def_t nfs4_wr_deleg_tmpl[] = {
    484   5599      jwahlig 	VOPNAME_OPEN,		{ .femop_open = deleg_wr_open },
    485   5599      jwahlig 	VOPNAME_READ,		{ .femop_read = deleg_wr_read },
    486   5599      jwahlig 	VOPNAME_WRITE,		{ .femop_write = deleg_wr_write },
    487   5599      jwahlig 	VOPNAME_SETATTR,	{ .femop_setattr = deleg_wr_setattr },
    488   3898          rsb 	VOPNAME_RWLOCK,		{ .femop_rwlock = deleg_wr_rwlock },
    489   5599      jwahlig 	VOPNAME_SPACE,		{ .femop_space = deleg_wr_space },
    490   5599      jwahlig 	VOPNAME_SETSECATTR,	{ .femop_setsecattr = deleg_wr_setsecattr },
    491   5599      jwahlig 	VOPNAME_VNEVENT,	{ .femop_vnevent = deleg_wr_vnevent },
    492   3898          rsb 	NULL,			NULL
    493      0       stevel };
    494      0       stevel 
    495      0       stevel int
    496      0       stevel rfs4_srvrinit(void)
    497      0       stevel {
    498      0       stevel 	timespec32_t verf;
    499      0       stevel 	int error;
    500      0       stevel 	extern void rfs4_attr_init();
    501      0       stevel 	extern krwlock_t rfs4_deleg_policy_lock;
    502      0       stevel 
    503      0       stevel 	/*
    504      0       stevel 	 * The following algorithm attempts to find a unique verifier
    505      0       stevel 	 * to be used as the write verifier returned from the server
    506      0       stevel 	 * to the client.  It is important that this verifier change
    507      0       stevel 	 * whenever the server reboots.  Of secondary importance, it
    508      0       stevel 	 * is important for the verifier to be unique between two
    509      0       stevel 	 * different servers.
    510      0       stevel 	 *
    511      0       stevel 	 * Thus, an attempt is made to use the system hostid and the
    512      0       stevel 	 * current time in seconds when the nfssrv kernel module is
    513      0       stevel 	 * loaded.  It is assumed that an NFS server will not be able
    514      0       stevel 	 * to boot and then to reboot in less than a second.  If the
    515      0       stevel 	 * hostid has not been set, then the current high resolution
    516      0       stevel 	 * time is used.  This will ensure different verifiers each
    517      0       stevel 	 * time the server reboots and minimize the chances that two
    518      0       stevel 	 * different servers will have the same verifier.
    519      0       stevel 	 * XXX - this is broken on LP64 kernels.
    520      0       stevel 	 */
    521   8662       Jordan 	verf.tv_sec = (time_t)zone_get_hostid(NULL);
    522      0       stevel 	if (verf.tv_sec != 0) {
    523      0       stevel 		verf.tv_nsec = gethrestime_sec();
    524      0       stevel 	} else {
    525      0       stevel 		timespec_t tverf;
    526      0       stevel 
    527      0       stevel 		gethrestime(&tverf);
    528      0       stevel 		verf.tv_sec = (time_t)tverf.tv_sec;
    529      0       stevel 		verf.tv_nsec = tverf.tv_nsec;
    530      0       stevel 	}
    531      0       stevel 
    532      0       stevel 	Write4verf = *(uint64_t *)&verf;
    533      0       stevel 
    534      0       stevel 	rfs4_attr_init();
    535      0       stevel 	mutex_init(&rfs4_deleg_lock, NULL, MUTEX_DEFAULT, NULL);
    536      0       stevel 
    537      0       stevel 	/* Used to manage create/destroy of server state */
    538      0       stevel 	mutex_init(&rfs4_state_lock, NULL, MUTEX_DEFAULT, NULL);
    539      0       stevel 
    540      0       stevel 	/* Used to manage access to server instance linked list */
    541      0       stevel 	mutex_init(&rfs4_servinst_lock, NULL, MUTEX_DEFAULT, NULL);
    542      0       stevel 
    543      0       stevel 	/* Used to manage access to rfs4_deleg_policy */
    544      0       stevel 	rw_init(&rfs4_deleg_policy_lock, NULL, RW_DEFAULT, NULL);
    545      0       stevel 
    546      0       stevel 	error = fem_create("deleg_rdops", nfs4_rd_deleg_tmpl, &deleg_rdops);
    547      0       stevel 	if (error != 0) {
    548      0       stevel 		rfs4_disable_delegation();
    549      0       stevel 	} else {
    550      0       stevel 		error = fem_create("deleg_wrops", nfs4_wr_deleg_tmpl,
    551   5050      jwahlig 		    &deleg_wrops);
    552      0       stevel 		if (error != 0) {
    553      0       stevel 			rfs4_disable_delegation();
    554      0       stevel 			fem_free(deleg_rdops);
    555      0       stevel 		}
    556      0       stevel 	}
    557      0       stevel 
    558      0       stevel 	nfs4_srv_caller_id = fs_new_caller_id();
    559      0       stevel 
    560      0       stevel 	lockt_sysid = lm_alloc_sysidt();
    561   5050      jwahlig 
    562   5050      jwahlig 	vsd_create(&nfs4_srv_vkey, NULL);
    563      0       stevel 
    564      0       stevel 	return (0);
    565      0       stevel }
    566      0       stevel 
    567      0       stevel void
    568      0       stevel rfs4_srvrfini(void)
    569      0       stevel {
    570      0       stevel 	extern krwlock_t rfs4_deleg_policy_lock;
    571      0       stevel 
    572      0       stevel 	if (lockt_sysid != LM_NOSYSID) {
    573      0       stevel 		lm_free_sysidt(lockt_sysid);
    574      0       stevel 		lockt_sysid = LM_NOSYSID;
    575      0       stevel 	}
    576      0       stevel 
    577      0       stevel 	mutex_destroy(&rfs4_deleg_lock);
    578      0       stevel 	mutex_destroy(&rfs4_state_lock);
    579      0       stevel 	rw_destroy(&rfs4_deleg_policy_lock);
    580      0       stevel 
    581      0       stevel 	fem_free(deleg_rdops);
    582      0       stevel 	fem_free(deleg_wrops);
    583      0       stevel }
    584      0       stevel 
    585      0       stevel void
    586      0       stevel rfs4_init_compound_state(struct compound_state *cs)
    587      0       stevel {
    588      0       stevel 	bzero(cs, sizeof (*cs));
    589      0       stevel 	cs->cont = TRUE;
    590      0       stevel 	cs->access = CS_ACCESS_DENIED;
    591      0       stevel 	cs->deleg = FALSE;
    592      0       stevel 	cs->mandlock = FALSE;
    593      0       stevel 	cs->fh.nfs_fh4_val = cs->fhbuf;
    594      0       stevel }
    595      0       stevel 
    596      0       stevel void
    597      0       stevel rfs4_grace_start(rfs4_servinst_t *sip)
    598      0       stevel {
    599      0       stevel 	rw_enter(&sip->rwlock, RW_WRITER);
    600  11066       rafael 	sip->start_time = (time_t)TICK_TO_SEC(ddi_get_lbolt());
    601      0       stevel 	sip->grace_period = rfs4_grace_period;
    602      0       stevel 	rw_exit(&sip->rwlock);
    603      0       stevel }
    604      0       stevel 
    605      0       stevel /*
    606      0       stevel  * returns true if the instance's grace period has never been started
    607      0       stevel  */
    608      0       stevel int
    609      0       stevel rfs4_servinst_grace_new(rfs4_servinst_t *sip)
    610      0       stevel {
    611      0       stevel 	time_t start_time;
    612      0       stevel 
    613      0       stevel 	rw_enter(&sip->rwlock, RW_READER);
    614      0       stevel 	start_time = sip->start_time;
    615      0       stevel 	rw_exit(&sip->rwlock);
    616      0       stevel 
    617      0       stevel 	return (start_time == 0);
    618      0       stevel }
    619      0       stevel 
    620      0       stevel /*
    621      0       stevel  * Indicates if server instance is within the
    622      0       stevel  * grace period.
    623      0       stevel  */
    624      0       stevel int
    625      0       stevel rfs4_servinst_in_grace(rfs4_servinst_t *sip)
    626      0       stevel {
    627      0       stevel 	time_t grace_expiry;
    628      0       stevel 
    629      0       stevel 	rw_enter(&sip->rwlock, RW_READER);
    630      0       stevel 	grace_expiry = sip->start_time + sip->grace_period;
    631      0       stevel 	rw_exit(&sip->rwlock);
    632      0       stevel 
    633  11066       rafael 	return (((time_t)TICK_TO_SEC(ddi_get_lbolt())) < grace_expiry);
    634      0       stevel }
    635      0       stevel 
    636      0       stevel int
    637      0       stevel rfs4_clnt_in_grace(rfs4_client_t *cp)
    638      0       stevel {
    639   9885       Robert 	ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
    640   9885       Robert 
    641   9885       Robert 	return (rfs4_servinst_in_grace(cp->rc_server_instance));
    642      0       stevel }
    643      0       stevel 
    644      0       stevel /*
    645      0       stevel  * reset all currently active grace periods
    646      0       stevel  */
    647      0       stevel void
    648      0       stevel rfs4_grace_reset_all(void)
    649      0       stevel {
    650      0       stevel 	rfs4_servinst_t *sip;
    651      0       stevel 
    652      0       stevel 	mutex_enter(&rfs4_servinst_lock);
    653   2035        calum 	for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev)
    654   2035        calum 		if (rfs4_servinst_in_grace(sip))
    655      0       stevel 			rfs4_grace_start(sip);
    656      0       stevel 	mutex_exit(&rfs4_servinst_lock);
    657      0       stevel }
    658      0       stevel 
    659      0       stevel /*
    660      0       stevel  * start any new instances' grace periods
    661      0       stevel  */
    662      0       stevel void
    663      0       stevel rfs4_grace_start_new(void)
    664      0       stevel {
    665      0       stevel 	rfs4_servinst_t *sip;
    666      0       stevel 
    667      0       stevel 	mutex_enter(&rfs4_servinst_lock);
    668   2035        calum 	for (sip = rfs4_cur_servinst; sip != NULL; sip = sip->prev)
    669      0       stevel 		if (rfs4_servinst_grace_new(sip))
    670      0       stevel 			rfs4_grace_start(sip);
    671      0       stevel 	mutex_exit(&rfs4_servinst_lock);
    672   2035        calum }
    673   2035        calum 
    674   2035        calum static rfs4_dss_path_t *
    675   2035        calum rfs4_dss_newpath(rfs4_servinst_t *sip, char *path, unsigned index)
    676   2035        calum {
    677   2035        calum 	size_t len;
    678   2035        calum 	rfs4_dss_path_t *dss_path;
    679   2035        calum 
    680   2035        calum 	dss_path = kmem_alloc(sizeof (rfs4_dss_path_t), KM_SLEEP);
    681   2035        calum 
    682   2035        calum 	/*
    683   2035        calum 	 * Take a copy of the string, since the original may be overwritten.
    684   2035        calum 	 * Sadly, no strdup() in the kernel.
    685   2035        calum 	 */
    686   2035        calum 	/* allow for NUL */
    687   2035        calum 	len = strlen(path) + 1;
    688   2035        calum 	dss_path->path = kmem_alloc(len, KM_SLEEP);
    689   2035        calum 	(void) strlcpy(dss_path->path, path, len);
    690   2035        calum 
    691   2035        calum 	/* associate with servinst */
    692   2035        calum 	dss_path->sip = sip;
    693   2035        calum 	dss_path->index = index;
    694   2035        calum 
    695   2035        calum 	/*
    696   2035        calum 	 * Add to list of served paths.
    697   2035        calum 	 * No locking required, as we're only ever called at startup.
    698   2035        calum 	 */
    699   2035        calum 	if (rfs4_dss_pathlist == NULL) {
    700   2035        calum 		/* this is the first dss_path_t */
    701   2035        calum 
    702   2035        calum 		/* needed for insque/remque */
    703   2035        calum 		dss_path->next = dss_path->prev = dss_path;
    704   2035        calum 
    705   2035        calum 		rfs4_dss_pathlist = dss_path;
    706   2035        calum 	} else {
    707   2035        calum 		insque(dss_path, rfs4_dss_pathlist);
    708   2035        calum 	}
    709   2035        calum 
    710   2035        calum 	return (dss_path);
    711      0       stevel }
    712      0       stevel 
    713      0       stevel /*
    714      0       stevel  * Create a new server instance, and make it the currently active instance.
    715      0       stevel  * Note that starting the grace period too early will reduce the clients'
    716      0       stevel  * recovery window.
    717      0       stevel  */
    718      0       stevel void
    719   2035        calum rfs4_servinst_create(int start_grace, int dss_npaths, char **dss_paths)
    720   2035        calum {
    721   2035        calum 	unsigned i;
    722      0       stevel 	rfs4_servinst_t *sip;
    723   2035        calum 	rfs4_oldstate_t *oldstate;
    724      0       stevel 
    725      0       stevel 	sip = kmem_alloc(sizeof (rfs4_servinst_t), KM_SLEEP);
    726      0       stevel 	rw_init(&sip->rwlock, NULL, RW_DEFAULT, NULL);
    727      0       stevel 
    728      0       stevel 	sip->start_time = (time_t)0;
    729      0       stevel 	sip->grace_period = (time_t)0;
    730      0       stevel 	sip->next = NULL;
    731      0       stevel 	sip->prev = NULL;
    732      0       stevel 
    733   2035        calum 	rw_init(&sip->oldstate_lock, NULL, RW_DEFAULT, NULL);
    734   2035        calum 	/*
    735   2035        calum 	 * This initial dummy entry is required to setup for insque/remque.
    736   2035        calum 	 * It must be skipped over whenever the list is traversed.
    737   2035        calum 	 */
    738   2035        calum 	oldstate = kmem_alloc(sizeof (rfs4_oldstate_t), KM_SLEEP);
    739   2035        calum 	/* insque/remque require initial list entry to be self-terminated */
    740   2035        calum 	oldstate->next = oldstate;
    741   2035        calum 	oldstate->prev = oldstate;
    742   2035        calum 	sip->oldstate = oldstate;
    743   2035        calum 
    744   2035        calum 
    745   2035        calum 	sip->dss_npaths = dss_npaths;
    746   2035        calum 	sip->dss_paths = kmem_alloc(dss_npaths *
    747   2035        calum 	    sizeof (rfs4_dss_path_t *), KM_SLEEP);
    748   2035        calum 
    749   2035        calum 	for (i = 0; i < dss_npaths; i++) {
    750   2035        calum 		sip->dss_paths[i] = rfs4_dss_newpath(sip, dss_paths[i], i);
    751   2035        calum 	}
    752   2035        calum 
    753      0       stevel 	mutex_enter(&rfs4_servinst_lock);
    754   2035        calum 	if (rfs4_cur_servinst != NULL) {
    755      0       stevel 		/* add to linked list */
    756      0       stevel 		sip->prev = rfs4_cur_servinst;
    757      0       stevel 		rfs4_cur_servinst->next = sip;
    758      0       stevel 	}
    759      0       stevel 	if (start_grace)
    760      0       stevel 		rfs4_grace_start(sip);
    761      0       stevel 	/* make the new instance "current" */
    762      0       stevel 	rfs4_cur_servinst = sip;
    763   2035        calum 
    764      0       stevel 	mutex_exit(&rfs4_servinst_lock);
    765      0       stevel }
    766      0       stevel 
    767      0       stevel /*
    768      0       stevel  * In future, we might add a rfs4_servinst_destroy(sip) but, for now, destroy
    769      0       stevel  * all instances directly.
    770      0       stevel  */
    771      0       stevel void
    772      0       stevel rfs4_servinst_destroy_all(void)
    773      0       stevel {
    774      0       stevel 	rfs4_servinst_t *sip, *prev, *current;
    775      0       stevel #ifdef DEBUG
    776      0       stevel 	int n = 0;
    777      0       stevel #endif
    778      0       stevel 
    779      0       stevel 	mutex_enter(&rfs4_servinst_lock);
    780      0       stevel 	ASSERT(rfs4_cur_servinst != NULL);
    781      0       stevel 	current = rfs4_cur_servinst;
    782      0       stevel 	rfs4_cur_servinst = NULL;
    783      0       stevel 	for (sip = current; sip != NULL; sip = prev) {
    784      0       stevel 		prev = sip->prev;
    785      0       stevel 		rw_destroy(&sip->rwlock);
    786   2035        calum 		if (sip->oldstate)
    787   2035        calum 			kmem_free(sip->oldstate, sizeof (rfs4_oldstate_t));
    788   2035        calum 		if (sip->dss_paths)
    789   2035        calum 			kmem_free(sip->dss_paths,
    790   2035        calum 			    sip->dss_npaths * sizeof (rfs4_dss_path_t *));
    791      0       stevel 		kmem_free(sip, sizeof (rfs4_servinst_t));
    792      0       stevel #ifdef DEBUG
    793      0       stevel 		n++;
    794      0       stevel #endif
    795      0       stevel 	}
    796      0       stevel 	mutex_exit(&rfs4_servinst_lock);
    797      0       stevel }
    798      0       stevel 
    799      0       stevel /*
    800      0       stevel  * Assign the current server instance to a client_t.
    801   9885       Robert  * Should be called with cp->rc_dbe held.
    802      0       stevel  */
    803      0       stevel void
    804      0       stevel rfs4_servinst_assign(rfs4_client_t *cp, rfs4_servinst_t *sip)
    805      0       stevel {
    806   9885       Robert 	ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
    807      0       stevel 
    808      0       stevel 	/*
    809      0       stevel 	 * The lock ensures that if the current instance is in the process
    810      0       stevel 	 * of changing, we will see the new one.
    811      0       stevel 	 */
    812      0       stevel 	mutex_enter(&rfs4_servinst_lock);
    813   9885       Robert 	cp->rc_server_instance = sip;
    814      0       stevel 	mutex_exit(&rfs4_servinst_lock);
    815      0       stevel }
    816      0       stevel 
    817      0       stevel rfs4_servinst_t *
    818      0       stevel rfs4_servinst(rfs4_client_t *cp)
    819      0       stevel {
    820   9885       Robert 	ASSERT(rfs4_dbe_refcnt(cp->rc_dbe) > 0);
    821   9885       Robert 
    822   9885       Robert 	return (cp->rc_server_instance);
    823      0       stevel }
    824      0       stevel 
    825      0       stevel /* ARGSUSED */
    826      0       stevel static void
    827      0       stevel nullfree(caddr_t resop)
    828      0       stevel {
    829      0       stevel }
    830      0       stevel 
    831      0       stevel /*
    832      0       stevel  * This is a fall-through for invalid or not implemented (yet) ops
    833      0       stevel  */
    834      0       stevel /* ARGSUSED */
    835      0       stevel static void
    836      0       stevel rfs4_op_inval(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
    837      0       stevel 	struct compound_state *cs)
    838      0       stevel {
    839      0       stevel 	*cs->statusp = *((nfsstat4 *)&(resop)->nfs_resop4_u) = NFS4ERR_INVAL;
    840      0       stevel }
    841      0       stevel 
    842      0       stevel /*
    843      0       stevel  * Check if the security flavor, nfsnum, is in the flavor_list.
    844      0       stevel  */
    845      0       stevel bool_t
    846      0       stevel in_flavor_list(int nfsnum, int *flavor_list, int count)
    847      0       stevel {
    848      0       stevel 	int i;
    849      0       stevel 
    850      0       stevel 	for (i = 0; i < count; i++) {
    851      0       stevel 		if (nfsnum == flavor_list[i])
    852      0       stevel 			return (TRUE);
    853      0       stevel 	}
    854      0       stevel 	return (FALSE);
    855      0       stevel }
    856      0       stevel 
    857      0       stevel /*
    858      0       stevel  * Used by rfs4_op_secinfo to get the security information from the
    859      0       stevel  * export structure associated with the component.
    860      0       stevel  */
    861      0       stevel /* ARGSUSED */
    862      0       stevel static nfsstat4
    863      0       stevel do_rfs4_op_secinfo(struct compound_state *cs, char *nm, SECINFO4res *resp)
    864      0       stevel {
    865      0       stevel 	int error, different_export = 0;
    866      0       stevel 	vnode_t *dvp, *vp, *tvp;
    867      0       stevel 	struct exportinfo *exi = NULL;
    868      0       stevel 	fid_t fid;
    869      0       stevel 	uint_t count, i;
    870      0       stevel 	secinfo4 *resok_val;
    871      0       stevel 	struct secinfo *secp;
    872   5050      jwahlig 	seconfig_t *si;
    873      0       stevel 	bool_t did_traverse;
    874      0       stevel 	int dotdot, walk;
    875      0       stevel 
    876      0       stevel 	dvp = cs->vp;
    877      0       stevel 	dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
    878      0       stevel 
    879      0       stevel 	/*
    880      0       stevel 	 * If dotdotting, then need to check whether it's above the
    881      0       stevel 	 * root of a filesystem, or above an export point.
    882      0       stevel 	 */
    883      0       stevel 	if (dotdot) {
    884      0       stevel 
    885      0       stevel 		/*
    886      0       stevel 		 * If dotdotting at the root of a filesystem, then
    887      0       stevel 		 * need to traverse back to the mounted-on filesystem
    888      0       stevel 		 * and do the dotdot lookup there.
    889      0       stevel 		 */
    890      0       stevel 		if (cs->vp->v_flag & VROOT) {
    891      0       stevel 
    892      0       stevel 			/*
    893      0       stevel 			 * If at the system root, then can
    894      0       stevel 			 * go up no further.
    895      0       stevel 			 */
    896      0       stevel 			if (VN_CMP(dvp, rootdir))
    897      0       stevel 				return (puterrno4(ENOENT));
    898      0       stevel 
    899      0       stevel 			/*
    900      0       stevel 			 * Traverse back to the mounted-on filesystem
    901      0       stevel 			 */
    902      0       stevel 			dvp = untraverse(cs->vp);
    903      0       stevel 
    904      0       stevel 			/*
    905      0       stevel 			 * Set the different_export flag so we remember
    906      0       stevel 			 * to pick up a new exportinfo entry for
    907      0       stevel 			 * this new filesystem.
    908      0       stevel 			 */
    909      0       stevel 			different_export = 1;
    910      0       stevel 		} else {
    911      0       stevel 
    912      0       stevel 			/*
    913      0       stevel 			 * If dotdotting above an export point then set
    914      0       stevel 			 * the different_export to get new export info.
    915      0       stevel 			 */
    916      0       stevel 			different_export = nfs_exported(cs->exi, cs->vp);
    917      0       stevel 		}
    918      0       stevel 	}
    919      0       stevel 
    920      0       stevel 	/*
    921      0       stevel 	 * Get the vnode for the component "nm".
    922      0       stevel 	 */
    923   5331          amw 	error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cs->cr,
    924   5331          amw 	    NULL, NULL, NULL);
    925      0       stevel 	if (error)
    926      0       stevel 		return (puterrno4(error));
    927      0       stevel 
    928      0       stevel 	/*
    929      0       stevel 	 * If the vnode is in a pseudo filesystem, or if the security flavor
    930      0       stevel 	 * used in the request is valid but not an explicitly shared flavor,
    931      0       stevel 	 * or the access bit indicates that this is a limited access,
    932      0       stevel 	 * check whether this vnode is visible.
    933      0       stevel 	 */
    934      0       stevel 	if (!different_export &&
    935      0       stevel 	    (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
    936      0       stevel 	    cs->access & CS_ACCESS_LIMITED)) {
    937      0       stevel 		if (! nfs_visible(cs->exi, vp, &different_export)) {
    938      0       stevel 			VN_RELE(vp);
    939      0       stevel 			return (puterrno4(ENOENT));
    940      0       stevel 		}
    941      0       stevel 	}
    942      0       stevel 
    943      0       stevel 	/*
    944      0       stevel 	 * If it's a mountpoint, then traverse it.
    945      0       stevel 	 */
    946      0       stevel 	if (vn_ismntpt(vp)) {
    947      0       stevel 		tvp = vp;
    948      0       stevel 		if ((error = traverse(&tvp)) != 0) {
    949      0       stevel 			VN_RELE(vp);
    950      0       stevel 			return (puterrno4(error));
    951      0       stevel 		}
    952      0       stevel 		/* remember that we had to traverse mountpoint */
    953      0       stevel 		did_traverse = TRUE;
    954      0       stevel 		vp = tvp;
    955      0       stevel 		different_export = 1;
    956      0       stevel 	} else if (vp->v_vfsp != dvp->v_vfsp) {
    957      0       stevel 		/*
    958      0       stevel 		 * If vp isn't a mountpoint and the vfs ptrs aren't the same,
    959      0       stevel 		 * then vp is probably an LOFS object.  We don't need the
    960      0       stevel 		 * realvp, we just need to know that we might have crossed
    961      0       stevel 		 * a server fs boundary and need to call checkexport4.
    962      0       stevel 		 * (LOFS lookup hides server fs mountpoints, and actually calls
    963      0       stevel 		 * traverse)
    964      0       stevel 		 */
    965      0       stevel 		different_export = 1;
    966      0       stevel 		did_traverse = FALSE;
    967      0       stevel 	}
    968      0       stevel 
    969      0       stevel 	/*
    970      0       stevel 	 * Get the export information for it.
    971      0       stevel 	 */
    972      0       stevel 	if (different_export) {
    973      0       stevel 
    974      0       stevel 		bzero(&fid, sizeof (fid));
    975      0       stevel 		fid.fid_len = MAXFIDSZ;
    976      0       stevel 		error = vop_fid_pseudo(vp, &fid);
    977      0       stevel 		if (error) {
    978      0       stevel 			VN_RELE(vp);
    979      0       stevel 			return (puterrno4(error));
    980      0       stevel 		}
    981      0       stevel 
    982      0       stevel 		if (dotdot)
    983      0       stevel 			exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
    984      0       stevel 		else
    985      0       stevel 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
    986      0       stevel 
    987      0       stevel 		if (exi == NULL) {
    988      0       stevel 			if (did_traverse == TRUE) {
    989      0       stevel 				/*
    990      0       stevel 				 * If this vnode is a mounted-on vnode,
    991      0       stevel 				 * but the mounted-on file system is not
    992      0       stevel 				 * exported, send back the secinfo for
    993      0       stevel 				 * the exported node that the mounted-on
    994      0       stevel 				 * vnode lives in.
    995      0       stevel 				 */
    996      0       stevel 				exi = cs->exi;
    997      0       stevel 			} else {
    998      0       stevel 				VN_RELE(vp);
    999      0       stevel 				return (puterrno4(EACCES));
   1000      0       stevel 			}
   1001      0       stevel 		}
   1002      0       stevel 	} else {
   1003      0       stevel 		exi = cs->exi;
   1004      0       stevel 	}
   1005      0       stevel 	ASSERT(exi != NULL);
   1006      0       stevel 
   1007      0       stevel 
   1008      0       stevel 	/*
   1009      0       stevel 	 * Create the secinfo result based on the security information
   1010      0       stevel 	 * from the exportinfo structure (exi).
   1011      0       stevel 	 *
   1012      0       stevel 	 * Return all flavors for a pseudo node.
   1013      0       stevel 	 * For a real export node, return the flavor that the client
   1014      0       stevel 	 * has access with.
   1015      0       stevel 	 */
   1016      0       stevel 	ASSERT(RW_LOCK_HELD(&exported_lock));
   1017      0       stevel 	if (PSEUDO(exi)) {
   1018      0       stevel 		count = exi->exi_export.ex_seccnt; /* total sec count */
   1019      0       stevel 		resok_val = kmem_alloc(count * sizeof (secinfo4), KM_SLEEP);
   1020      0       stevel 		secp = exi->exi_export.ex_secinfo;
   1021      0       stevel 
   1022      0       stevel 		for (i = 0; i < count; i++) {
   1023   5050      jwahlig 			si = &secp[i].s_secinfo;
   1024   5050      jwahlig 			resok_val[i].flavor = si->sc_rpcnum;
   1025   5050      jwahlig 			if (resok_val[i].flavor == RPCSEC_GSS) {
   1026   5050      jwahlig 				rpcsec_gss_info *info;
   1027   5050      jwahlig 
   1028   5050      jwahlig 				info = &resok_val[i].flavor_info;
   1029   5050      jwahlig 				info->qop = si->sc_qop;
   1030   5050      jwahlig 				info->service = (rpc_gss_svc_t)si->sc_service;
   1031   5050      jwahlig 
   1032   5050      jwahlig 				/* get oid opaque data */
   1033   5050      jwahlig 				info->oid.sec_oid4_len =
   1034   5050      jwahlig 				    si->sc_gss_mech_type->length;
   1035   5050      jwahlig 				info->oid.sec_oid4_val = kmem_alloc(
   1036   5050      jwahlig 				    si->sc_gss_mech_type->length, KM_SLEEP);
   1037   5050      jwahlig 				bcopy(
   1038   5050      jwahlig 				    si->sc_gss_mech_type->elements,
   1039   5050      jwahlig 				    info->oid.sec_oid4_val,
   1040   5050      jwahlig 				    info->oid.sec_oid4_len);
   1041   5050      jwahlig 			}
   1042      0       stevel 		}
   1043      0       stevel 		resp->SECINFO4resok_len = count;
   1044      0       stevel 		resp->SECINFO4resok_val = resok_val;
   1045      0       stevel 	} else {
   1046      0       stevel 		int ret_cnt = 0, k = 0;
   1047      0       stevel 		int *flavor_list;
   1048      0       stevel 
   1049      0       stevel 		count = exi->exi_export.ex_seccnt; /* total sec count */
   1050      0       stevel 		secp = exi->exi_export.ex_secinfo;
   1051      0       stevel 
   1052      0       stevel 		flavor_list = kmem_alloc(count * sizeof (int), KM_SLEEP);
   1053      0       stevel 		/* find out which flavors to return */
   1054      0       stevel 		for (i = 0; i < count; i ++) {
   1055      0       stevel 			int access, flavor, perm;
   1056      0       stevel 
   1057      0       stevel 			flavor = secp[i].s_secinfo.sc_nfsnum;
   1058      0       stevel 			perm = secp[i].s_flags;
   1059      0       stevel 
   1060      0       stevel 			access = nfsauth4_secinfo_access(exi, cs->req,
   1061   5050      jwahlig 			    flavor, perm);
   1062      0       stevel 
   1063      0       stevel 			if (! (access & NFSAUTH_DENIED) &&
   1064      0       stevel 			    ! (access & NFSAUTH_WRONGSEC)) {
   1065      0       stevel 				flavor_list[ret_cnt] = flavor;
   1066      0       stevel 				ret_cnt++;
   1067      0       stevel 			}
   1068      0       stevel 		}
   1069      0       stevel 
   1070      0       stevel 		/* Create the returning SECINFO value */
   1071      0       stevel 		resok_val = kmem_alloc(ret_cnt * sizeof (secinfo4), KM_SLEEP);
   1072      0       stevel 
   1073      0       stevel 		for (i = 0; i < count; i++) {
   1074   5647         samf 			/*
   1075   5647         samf 			 * If the flavor is in the flavor list,
   1076   5647         samf 			 * fill in resok_val.
   1077   5647         samf 			 */
   1078   5050      jwahlig 			si = &secp[i].s_secinfo;
   1079   5050      jwahlig 			if (in_flavor_list(si->sc_nfsnum,
   1080   5050      jwahlig 			    flavor_list, ret_cnt)) {
   1081   5050      jwahlig 				resok_val[k].flavor = si->sc_rpcnum;
   1082   5050      jwahlig 				if (resok_val[k].flavor == RPCSEC_GSS) {
   1083   5050      jwahlig 					rpcsec_gss_info *info;
   1084   5050      jwahlig 
   1085   5050      jwahlig 					info = &resok_val[k].flavor_info;
   1086   5050      jwahlig 					info->qop = si->sc_qop;
   1087   5050      jwahlig 					info->service = (rpc_gss_svc_t)
   1088   5050      jwahlig 					    si->sc_service;
   1089   5050      jwahlig 
   1090   5050      jwahlig 					/* get oid opaque data */
   1091   5050      jwahlig 					info->oid.sec_oid4_len =
   1092   5050      jwahlig 					    si->sc_gss_mech_type->length;
   1093   5050      jwahlig 					info->oid.sec_oid4_val = kmem_alloc(
   1094   5050      jwahlig 					    si->sc_gss_mech_type->length,
   1095   5050      jwahlig 					    KM_SLEEP);
   1096   5050      jwahlig 					bcopy(si->sc_gss_mech_type->elements,
   1097   5050      jwahlig 					    info->oid.sec_oid4_val,
   1098   5050      jwahlig 					    info->oid.sec_oid4_len);
   1099   5050      jwahlig 				}
   1100   5050      jwahlig 				k++;
   1101   5050      jwahlig 			}
   1102   5647         samf 			if (k >= ret_cnt)
   1103   5647         samf 				break;
   1104      0       stevel 		}
   1105      0       stevel 		resp->SECINFO4resok_len = ret_cnt;
   1106      0       stevel 		resp->SECINFO4resok_val = resok_val;
   1107      0       stevel 		kmem_free(flavor_list, count * sizeof (int));
   1108      0       stevel 	}
   1109      0       stevel 
   1110      0       stevel 	VN_RELE(vp);
   1111      0       stevel 	return (NFS4_OK);
   1112      0       stevel }
   1113      0       stevel 
   1114      0       stevel /*
   1115      0       stevel  * SECINFO (Operation 33): Obtain required security information on
   1116      0       stevel  * the component name in the format of (security-mechanism-oid, qop, service)
   1117      0       stevel  * triplets.
   1118      0       stevel  */
   1119      0       stevel /* ARGSUSED */
   1120      0       stevel static void
   1121      0       stevel rfs4_op_secinfo(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1122   9885       Robert     struct compound_state *cs)
   1123      0       stevel {
   1124   5647         samf 	SECINFO4args *args = &argop->nfs_argop4_u.opsecinfo;
   1125      0       stevel 	SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
   1126   5647         samf 	utf8string *utfnm = &args->name;
   1127      0       stevel 	uint_t len;
   1128      0       stevel 	char *nm;
   1129   7961      Natalie 	struct sockaddr *ca;
   1130   7961      Natalie 	char *name = NULL;
   1131      0       stevel 
   1132   5647         samf 	DTRACE_NFSV4_2(op__secinfo__start, struct compound_state *, cs,
   1133   5647         samf 	    SECINFO4args *, args);
   1134   5647         samf 
   1135      0       stevel 	/*
   1136      0       stevel 	 * Current file handle (cfh) should have been set before getting
   1137      0       stevel 	 * into this function. If not, return error.
   1138      0       stevel 	 */
   1139      0       stevel 	if (cs->vp == NULL) {
   1140      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1141   5647         samf 		goto out;
   1142      0       stevel 	}
   1143      0       stevel 
   1144      0       stevel 	if (cs->vp->v_type != VDIR) {
   1145      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   1146   5647         samf 		goto out;
   1147      0       stevel 	}
   1148      0       stevel 
   1149      0       stevel 	/*
   1150      0       stevel 	 * Verify the component name. If failed, error out, but
   1151      0       stevel 	 * do not error out if the component name is a "..".
   1152      0       stevel 	 * SECINFO will return its parents secinfo data for SECINFO "..".
   1153      0       stevel 	 */
   1154      0       stevel 	if (!utf8_dir_verify(utfnm)) {
   1155      0       stevel 		if (utfnm->utf8string_len != 2 ||
   1156   5050      jwahlig 		    utfnm->utf8string_val[0] != '.' ||
   1157   5050      jwahlig 		    utfnm->utf8string_val[1] != '.') {
   1158      0       stevel 			*cs->statusp = resp->status = NFS4ERR_INVAL;
   1159   5647         samf 			goto out;
   1160      0       stevel 		}
   1161      0       stevel 	}
   1162      0       stevel 
   1163      0       stevel 	nm = utf8_to_str(utfnm, &len, NULL);
   1164      0       stevel 	if (nm == NULL) {
   1165      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1166   5647         samf 		goto out;
   1167      0       stevel 	}
   1168      0       stevel 
   1169      0       stevel 	if (len > MAXNAMELEN) {
   1170      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1171      0       stevel 		kmem_free(nm, len);
   1172   5647         samf 		goto out;
   1173      0       stevel 	}
   1174   7961      Natalie 	/* If necessary, convert to UTF-8 for illbehaved clients */
   1175   7961      Natalie 
   1176   7961      Natalie 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   1177   7961      Natalie 	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
   1178   7961      Natalie 	    MAXPATHLEN  + 1);
   1179   7961      Natalie 
   1180   7961      Natalie 	if (name == NULL) {
   1181   7961      Natalie 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1182   7961      Natalie 		kmem_free(nm, len);
   1183   7961      Natalie 		goto out;
   1184   7961      Natalie 	}
   1185   7961      Natalie 
   1186   7961      Natalie 
   1187   7961      Natalie 	*cs->statusp = resp->status = do_rfs4_op_secinfo(cs, name, resp);
   1188   7961      Natalie 
   1189   7961      Natalie 	if (name != nm)
   1190   7961      Natalie 		kmem_free(name, MAXPATHLEN + 1);
   1191      0       stevel 	kmem_free(nm, len);
   1192   5647         samf 
   1193   5647         samf out:
   1194   5647         samf 	DTRACE_NFSV4_2(op__secinfo__done, struct compound_state *, cs,
   1195   5647         samf 	    SECINFO4res *, resp);
   1196      0       stevel }
   1197      0       stevel 
   1198      0       stevel /*
   1199      0       stevel  * Free SECINFO result.
   1200      0       stevel  */
   1201      0       stevel /* ARGSUSED */
   1202      0       stevel static void
   1203      0       stevel rfs4_op_secinfo_free(nfs_resop4 *resop)
   1204      0       stevel {
   1205      0       stevel 	SECINFO4res *resp = &resop->nfs_resop4_u.opsecinfo;
   1206      0       stevel 	int count, i;
   1207      0       stevel 	secinfo4 *resok_val;
   1208      0       stevel 
   1209      0       stevel 	/* If this is not an Ok result, nothing to free. */
   1210      0       stevel 	if (resp->status != NFS4_OK) {
   1211      0       stevel 		return;
   1212      0       stevel 	}
   1213      0       stevel 
   1214      0       stevel 	count = resp->SECINFO4resok_len;
   1215      0       stevel 	resok_val = resp->SECINFO4resok_val;
   1216      0       stevel 
   1217      0       stevel 	for (i = 0; i < count; i++) {
   1218   5050      jwahlig 		if (resok_val[i].flavor == RPCSEC_GSS) {
   1219   5050      jwahlig 			rpcsec_gss_info *info;
   1220   5050      jwahlig 
   1221   5050      jwahlig 			info = &resok_val[i].flavor_info;
   1222   5050      jwahlig 			kmem_free(info->oid.sec_oid4_val,
   1223   5050      jwahlig 			    info->oid.sec_oid4_len);
   1224   5050      jwahlig 		}
   1225      0       stevel 	}
   1226      0       stevel 	kmem_free(resok_val, count * sizeof (secinfo4));
   1227      0       stevel 	resp->SECINFO4resok_len = 0;
   1228      0       stevel 	resp->SECINFO4resok_val = NULL;
   1229      0       stevel }
   1230      0       stevel 
   1231      0       stevel /* ARGSUSED */
   1232      0       stevel static void
   1233      0       stevel rfs4_op_access(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1234   9885       Robert     struct compound_state *cs)
   1235      0       stevel {
   1236      0       stevel 	ACCESS4args *args = &argop->nfs_argop4_u.opaccess;
   1237      0       stevel 	ACCESS4res *resp = &resop->nfs_resop4_u.opaccess;
   1238      0       stevel 	int error;
   1239      0       stevel 	vnode_t *vp;
   1240      0       stevel 	struct vattr va;
   1241      0       stevel 	int checkwriteperm;
   1242      0       stevel 	cred_t *cr = cs->cr;
   1243   1676          jpk 	bslabel_t *clabel, *slabel;
   1244   1676          jpk 	ts_label_t *tslabel;
   1245   1676          jpk 	boolean_t admin_low_client;
   1246      0       stevel 
   1247   5647         samf 	DTRACE_NFSV4_2(op__access__start, struct compound_state *, cs,
   1248   5647         samf 	    ACCESS4args *, args);
   1249   5647         samf 
   1250      0       stevel #if 0	/* XXX allow access even if !cs->access. Eventually only pseudo fs */
   1251      0       stevel 	if (cs->access == CS_ACCESS_DENIED) {
   1252      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1253   5647         samf 		goto out;
   1254      0       stevel 	}
   1255      0       stevel #endif
   1256      0       stevel 	if (cs->vp == NULL) {
   1257      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1258   5647         samf 		goto out;
   1259      0       stevel 	}
   1260      0       stevel 
   1261      0       stevel 	ASSERT(cr != NULL);
   1262      0       stevel 
   1263      0       stevel 	vp = cs->vp;
   1264      0       stevel 
   1265      0       stevel 	/*
   1266      0       stevel 	 * If the file system is exported read only, it is not appropriate
   1267      0       stevel 	 * to check write permissions for regular files and directories.
   1268      0       stevel 	 * Special files are interpreted by the client, so the underlying
   1269      0       stevel 	 * permissions are sent back to the client for interpretation.
   1270      0       stevel 	 */
   1271      0       stevel 	if (rdonly4(cs->exi, cs->vp, req) &&
   1272   5050      jwahlig 	    (vp->v_type == VREG || vp->v_type == VDIR))
   1273      0       stevel 		checkwriteperm = 0;
   1274      0       stevel 	else
   1275      0       stevel 		checkwriteperm = 1;
   1276      0       stevel 
   1277      0       stevel 	/*
   1278      0       stevel 	 * XXX
   1279      0       stevel 	 * We need the mode so that we can correctly determine access
   1280      0       stevel 	 * permissions relative to a mandatory lock file.  Access to
   1281      0       stevel 	 * mandatory lock files is denied on the server, so it might
   1282      0       stevel 	 * as well be reflected to the server during the open.
   1283      0       stevel 	 */
   1284      0       stevel 	va.va_mask = AT_MODE;
   1285   5331          amw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
   1286      0       stevel 	if (error) {
   1287      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1288   5647         samf 		goto out;
   1289      0       stevel 	}
   1290      0       stevel 	resp->access = 0;
   1291      0       stevel 	resp->supported = 0;
   1292      0       stevel 
   1293   1676          jpk 	if (is_system_labeled()) {
   1294   1676          jpk 		ASSERT(req->rq_label != NULL);
   1295   1676          jpk 		clabel = req->rq_label;
   1296   1676          jpk 		DTRACE_PROBE2(tx__rfs4__log__info__opaccess__clabel, char *,
   1297   1676          jpk 		    "got client label from request(1)",
   1298   1676          jpk 		    struct svc_req *, req);
   1299   1676          jpk 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
   1300   9871      Jarrett 			if ((tslabel = nfs_getflabel(vp, cs->exi)) == NULL) {
   1301   1676          jpk 				*cs->statusp = resp->status = puterrno4(EACCES);
   1302   5647         samf 				goto out;
   1303   1676          jpk 			}
   1304   1676          jpk 			slabel = label2bslabel(tslabel);
   1305   1676          jpk 			DTRACE_PROBE3(tx__rfs4__log__info__opaccess__slabel,
   1306   1676          jpk 			    char *, "got server label(1) for vp(2)",
   1307   1676          jpk 			    bslabel_t *, slabel, vnode_t *, vp);
   1308   1676          jpk 
   1309   1676          jpk 			admin_low_client = B_FALSE;
   1310   1676          jpk 		} else
   1311   1676          jpk 			admin_low_client = B_TRUE;
   1312   1676          jpk 	}
   1313   1676          jpk 
   1314      0       stevel 	if (args->access & ACCESS4_READ) {
   1315   5331          amw 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
   1316   1676          jpk 		if (!error && !MANDLOCK(vp, va.va_mode) &&
   1317   1676          jpk 		    (!is_system_labeled() || admin_low_client ||
   1318   1676          jpk 		    bldominates(clabel, slabel)))
   1319      0       stevel 			resp->access |= ACCESS4_READ;
   1320      0       stevel 		resp->supported |= ACCESS4_READ;
   1321      0       stevel 	}
   1322      0       stevel 	if ((args->access & ACCESS4_LOOKUP) && vp->v_type == VDIR) {
   1323   5331          amw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
   1324   1676          jpk 		if (!error && (!is_system_labeled() || admin_low_client ||
   1325   1676          jpk 		    bldominates(clabel, slabel)))
   1326      0       stevel 			resp->access |= ACCESS4_LOOKUP;
   1327      0       stevel 		resp->supported |= ACCESS4_LOOKUP;
   1328      0       stevel 	}
   1329      0       stevel 	if (checkwriteperm &&
   1330      0       stevel 	    (args->access & (ACCESS4_MODIFY|ACCESS4_EXTEND))) {
   1331   5331          amw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
   1332   1676          jpk 		if (!error && !MANDLOCK(vp, va.va_mode) &&
   1333   1676          jpk 		    (!is_system_labeled() || admin_low_client ||
   1334   1676          jpk 		    blequal(clabel, slabel)))
   1335      0       stevel 			resp->access |=
   1336   7387       Robert 			    (args->access & (ACCESS4_MODIFY | ACCESS4_EXTEND));
   1337   7387       Robert 		resp->supported |= (ACCESS4_MODIFY | ACCESS4_EXTEND);
   1338      0       stevel 	}
   1339      0       stevel 
   1340      0       stevel 	if (checkwriteperm &&
   1341      0       stevel 	    (args->access & ACCESS4_DELETE) && vp->v_type == VDIR) {
   1342   5331          amw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
   1343   1676          jpk 		if (!error && (!is_system_labeled() || admin_low_client ||
   1344   1676          jpk 		    blequal(clabel, slabel)))
   1345      0       stevel 			resp->access |= ACCESS4_DELETE;
   1346      0       stevel 		resp->supported |= ACCESS4_DELETE;
   1347      0       stevel 	}
   1348      0       stevel 	if (args->access & ACCESS4_EXECUTE && vp->v_type != VDIR) {
   1349   5331          amw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
   1350   1676          jpk 		if (!error && !MANDLOCK(vp, va.va_mode) &&
   1351   1676          jpk 		    (!is_system_labeled() || admin_low_client ||
   1352   1676          jpk 		    bldominates(clabel, slabel)))
   1353      0       stevel 			resp->access |= ACCESS4_EXECUTE;
   1354      0       stevel 		resp->supported |= ACCESS4_EXECUTE;
   1355      0       stevel 	}
   1356   1676          jpk 
   1357   1676          jpk 	if (is_system_labeled() && !admin_low_client)
   1358   1676          jpk 		label_rele(tslabel);
   1359      0       stevel 
   1360      0       stevel 	*cs->statusp = resp->status = NFS4_OK;
   1361   5647         samf out:
   1362   5647         samf 	DTRACE_NFSV4_2(op__access__done, struct compound_state *, cs,
   1363   5647         samf 	    ACCESS4res *, resp);
   1364      0       stevel }
   1365      0       stevel 
   1366      0       stevel /* ARGSUSED */
   1367      0       stevel static void
   1368      0       stevel rfs4_op_commit(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1369   9885       Robert     struct compound_state *cs)
   1370      0       stevel {
   1371      0       stevel 	COMMIT4args *args = &argop->nfs_argop4_u.opcommit;
   1372      0       stevel 	COMMIT4res *resp = &resop->nfs_resop4_u.opcommit;
   1373      0       stevel 	int error;
   1374      0       stevel 	vnode_t *vp = cs->vp;
   1375      0       stevel 	cred_t *cr = cs->cr;
   1376      0       stevel 	vattr_t va;
   1377      0       stevel 
   1378   5647         samf 	DTRACE_NFSV4_2(op__commit__start, struct compound_state *, cs,
   1379   5647         samf 	    COMMIT4args *, args);
   1380   5647         samf 
   1381      0       stevel 	if (vp == NULL) {
   1382      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1383   5647         samf 		goto out;
   1384   5647         samf 	}
   1385   5647         samf 	if (cs->access == CS_ACCESS_DENIED) {
   1386   5647         samf 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1387   5647         samf 		goto out;
   1388      0       stevel 	}
   1389      0       stevel 
   1390      0       stevel 	if (args->offset + args->count < args->offset) {
   1391      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1392   5647         samf 		goto out;
   1393      0       stevel 	}
   1394      0       stevel 
   1395      0       stevel 	va.va_mask = AT_UID;
   1396   5331          amw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
   1397      0       stevel 
   1398      0       stevel 	/*
   1399      0       stevel 	 * If we can't get the attributes, then we can't do the
   1400      0       stevel 	 * right access checking.  So, we'll fail the request.
   1401      0       stevel 	 */
   1402      0       stevel 	if (error) {
   1403      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1404   5647         samf 		goto out;
   1405      0       stevel 	}
   1406      0       stevel 	if (rdonly4(cs->exi, cs->vp, req)) {
   1407      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ROFS;
   1408   5647         samf 		goto out;
   1409      0       stevel 	}
   1410      0       stevel 
   1411      0       stevel 	if (vp->v_type != VREG) {
   1412      0       stevel 		if (vp->v_type == VDIR)
   1413      0       stevel 			resp->status = NFS4ERR_ISDIR;
   1414      0       stevel 		else
   1415      0       stevel 			resp->status = NFS4ERR_INVAL;
   1416      0       stevel 		*cs->statusp = resp->status;
   1417   5647         samf 		goto out;
   1418      0       stevel 	}
   1419      0       stevel 
   1420      0       stevel 	if (crgetuid(cr) != va.va_uid &&
   1421   5331          amw 	    (error = VOP_ACCESS(vp, VWRITE, 0, cs->cr, NULL))) {
   1422   5331          amw 		*cs->statusp = resp->status = puterrno4(error);
   1423   5647         samf 		goto out;
   1424   5331          amw 	}
   1425   5331          amw 
   1426   5331          amw 	error = VOP_PUTPAGE(vp, args->offset, args->count, 0, cr, NULL);
   1427      0       stevel 	if (!error)
   1428   5331          amw 		error = VOP_FSYNC(vp, FNODSYNC, cr, NULL);
   1429      0       stevel 
   1430      0       stevel 	if (error) {
   1431      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1432   5647         samf 		goto out;
   1433      0       stevel 	}
   1434      0       stevel 
   1435      0       stevel 	*cs->statusp = resp->status = NFS4_OK;
   1436      0       stevel 	resp->writeverf = Write4verf;
   1437   5647         samf out:
   1438   5647         samf 	DTRACE_NFSV4_2(op__commit__done, struct compound_state *, cs,
   1439   5647         samf 	    COMMIT4res *, resp);
   1440      0       stevel }
   1441      0       stevel 
   1442      0       stevel /*
   1443      0       stevel  * rfs4_op_mknod is called from rfs4_op_create after all initial verification
   1444      0       stevel  * was completed. It does the nfsv4 create for special files.
   1445      0       stevel  */
   1446      0       stevel /* ARGSUSED */
   1447      0       stevel static vnode_t *
   1448      0       stevel do_rfs4_op_mknod(CREATE4args *args, CREATE4res *resp, struct svc_req *req,
   1449   9885       Robert     struct compound_state *cs, vattr_t *vap, char *nm)
   1450      0       stevel {
   1451      0       stevel 	int error;
   1452      0       stevel 	cred_t *cr = cs->cr;
   1453      0       stevel 	vnode_t *dvp = cs->vp;
   1454      0       stevel 	vnode_t *vp = NULL;
   1455      0       stevel 	int mode;
   1456      0       stevel 	enum vcexcl excl;
   1457      0       stevel 
   1458      0       stevel 	switch (args->type) {
   1459      0       stevel 	case NF4CHR:
   1460      0       stevel 	case NF4BLK:
   1461      0       stevel 		if (secpolicy_sys_devices(cr) != 0) {
   1462      0       stevel 			*cs->statusp = resp->status = NFS4ERR_PERM;
   1463      0       stevel 			return (NULL);
   1464      0       stevel 		}
   1465      0       stevel 		if (args->type == NF4CHR)
   1466      0       stevel 			vap->va_type = VCHR;
   1467      0       stevel 		else
   1468      0       stevel 			vap->va_type = VBLK;
   1469      0       stevel 		vap->va_rdev = makedevice(args->ftype4_u.devdata.specdata1,
   1470   5050      jwahlig 		    args->ftype4_u.devdata.specdata2);
   1471      0       stevel 		vap->va_mask |= AT_RDEV;
   1472      0       stevel 		break;
   1473      0       stevel 	case NF4SOCK:
   1474      0       stevel 		vap->va_type = VSOCK;
   1475      0       stevel 		break;
   1476      0       stevel 	case NF4FIFO:
   1477      0       stevel 		vap->va_type = VFIFO;
   1478      0       stevel 		break;
   1479      0       stevel 	default:
   1480      0       stevel 		*cs->statusp = resp->status = NFS4ERR_BADTYPE;
   1481      0       stevel 		return (NULL);
   1482      0       stevel 	}
   1483      0       stevel 
   1484      0       stevel 	/*
   1485      0       stevel 	 * Must specify the mode.
   1486      0       stevel 	 */
   1487      0       stevel 	if (!(vap->va_mask & AT_MODE)) {
   1488      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1489      0       stevel 		return (NULL);
   1490      0       stevel 	}
   1491      0       stevel 
   1492      0       stevel 	excl = EXCL;
   1493      0       stevel 
   1494      0       stevel 	mode = 0;
   1495      0       stevel 
   1496   5331          amw 	error = VOP_CREATE(dvp, nm, vap, excl, mode, &vp, cr, 0, NULL, NULL);
   1497      0       stevel 	if (error) {
   1498      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1499      0       stevel 		return (NULL);
   1500      0       stevel 	}
   1501      0       stevel 	return (vp);
   1502      0       stevel }
   1503      0       stevel 
   1504      0       stevel /*
   1505      0       stevel  * nfsv4 create is used to create non-regular files. For regular files,
   1506      0       stevel  * use nfsv4 open.
   1507      0       stevel  */
   1508      0       stevel /* ARGSUSED */
   1509      0       stevel static void
   1510      0       stevel rfs4_op_create(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1511   9885       Robert     struct compound_state *cs)
   1512      0       stevel {
   1513      0       stevel 	CREATE4args *args = &argop->nfs_argop4_u.opcreate;
   1514      0       stevel 	CREATE4res *resp = &resop->nfs_resop4_u.opcreate;
   1515      0       stevel 	int error;
   1516      0       stevel 	struct vattr bva, iva, iva2, ava, *vap;
   1517      0       stevel 	cred_t *cr = cs->cr;
   1518      0       stevel 	vnode_t *dvp = cs->vp;
   1519      0       stevel 	vnode_t *vp = NULL;
   1520   6402      gt29601 	vnode_t *realvp;
   1521      0       stevel 	char *nm, *lnm;
   1522      0       stevel 	uint_t len, llen;
   1523      0       stevel 	int syncval = 0;
   1524      0       stevel 	struct nfs4_svgetit_arg sarg;
   1525      0       stevel 	struct nfs4_ntov_table ntov;
   1526      0       stevel 	struct statvfs64 sb;
   1527      0       stevel 	nfsstat4 status;
   1528   7961      Natalie 	struct sockaddr *ca;
   1529   7961      Natalie 	char *name = NULL;
   1530   7961      Natalie 	char *lname = NULL;
   1531      0       stevel 
   1532   5647         samf 	DTRACE_NFSV4_2(op__create__start, struct compound_state *, cs,
   1533   5647         samf 	    CREATE4args *, args);
   1534   5647         samf 
   1535      0       stevel 	resp->attrset = 0;
   1536      0       stevel 
   1537      0       stevel 	if (dvp == NULL) {
   1538      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   1539   5647         samf 		goto out;
   1540      0       stevel 	}
   1541      0       stevel 
   1542      0       stevel 	/*
   1543      0       stevel 	 * If there is an unshared filesystem mounted on this vnode,
   1544      0       stevel 	 * do not allow to create an object in this directory.
   1545      0       stevel 	 */
   1546      0       stevel 	if (vn_ismntpt(dvp)) {
   1547      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1548   5647         samf 		goto out;
   1549      0       stevel 	}
   1550      0       stevel 
   1551      0       stevel 	/* Verify that type is correct */
   1552      0       stevel 	switch (args->type) {
   1553      0       stevel 	case NF4LNK:
   1554      0       stevel 	case NF4BLK:
   1555      0       stevel 	case NF4CHR:
   1556      0       stevel 	case NF4SOCK:
   1557      0       stevel 	case NF4FIFO:
   1558      0       stevel 	case NF4DIR:
   1559      0       stevel 		break;
   1560      0       stevel 	default:
   1561      0       stevel 		*cs->statusp = resp->status = NFS4ERR_BADTYPE;
   1562   5647         samf 		goto out;
   1563      0       stevel 	};
   1564      0       stevel 
   1565      0       stevel 	if (cs->access == CS_ACCESS_DENIED) {
   1566      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   1567   5647         samf 		goto out;
   1568      0       stevel 	}
   1569      0       stevel 	if (dvp->v_type != VDIR) {
   1570      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   1571   5647         samf 		goto out;
   1572      0       stevel 	}
   1573      0       stevel 	if (!utf8_dir_verify(&args->objname)) {
   1574      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1575   5647         samf 		goto out;
   1576      0       stevel 	}
   1577      0       stevel 
   1578      0       stevel 	if (rdonly4(cs->exi, cs->vp, req)) {
   1579      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ROFS;
   1580   5647         samf 		goto out;
   1581      0       stevel 	}
   1582      0       stevel 
   1583      0       stevel 	/*
   1584      0       stevel 	 * Name of newly created object
   1585      0       stevel 	 */
   1586      0       stevel 	nm = utf8_to_fn(&args->objname, &len, NULL);
   1587      0       stevel 	if (nm == NULL) {
   1588      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1589   5647         samf 		goto out;
   1590      0       stevel 	}
   1591      0       stevel 
   1592      0       stevel 	if (len > MAXNAMELEN) {
   1593      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1594      0       stevel 		kmem_free(nm, len);
   1595   5647         samf 		goto out;
   1596      0       stevel 	}
   1597      0       stevel 
   1598   7961      Natalie 	/* If necessary, convert to UTF-8 for poorly behaved clients */
   1599   7961      Natalie 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   1600   7961      Natalie 	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
   1601   7961      Natalie 	    MAXPATHLEN  + 1);
   1602   7961      Natalie 
   1603   7961      Natalie 	if (name == NULL) {
   1604   7961      Natalie 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   1605   7961      Natalie 		kmem_free(nm, len);
   1606   7961      Natalie 		goto out;
   1607   7961      Natalie 	}
   1608   7961      Natalie 
   1609      0       stevel 	resp->attrset = 0;
   1610      0       stevel 
   1611      0       stevel 	sarg.sbp = &sb;
   1612      0       stevel 	nfs4_ntov_table_init(&ntov);
   1613      0       stevel 
   1614      0       stevel 	status = do_rfs4_set_attrs(&resp->attrset,
   1615   5050      jwahlig 	    &args->createattrs, cs, &sarg, &ntov, NFS4ATTR_SETIT);
   1616      0       stevel 
   1617      0       stevel 	if (sarg.vap->va_mask == 0 && status == NFS4_OK)
   1618      0       stevel 		status = NFS4ERR_INVAL;
   1619      0       stevel 
   1620      0       stevel 	if (status != NFS4_OK) {
   1621      0       stevel 		*cs->statusp = resp->status = status;
   1622      0       stevel 		kmem_free(nm, len);
   1623      0       stevel 		nfs4_ntov_table_free(&ntov, &sarg);
   1624      0       stevel 		resp->attrset = 0;
   1625   5647         samf 		goto out;
   1626      0       stevel 	}
   1627      0       stevel 
   1628      0       stevel 	/* Get "before" change value */
   1629      0       stevel 	bva.va_mask = AT_CTIME|AT_SEQ;
   1630   5331          amw 	error = VOP_GETATTR(dvp, &bva, 0, cr, NULL);
   1631      0       stevel 	if (error) {
   1632      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1633      0       stevel 		kmem_free(nm, len);
   1634      0       stevel 		nfs4_ntov_table_free(&ntov, &sarg);
   1635      0       stevel 		resp->attrset = 0;
   1636   5647         samf 		goto out;
   1637      0       stevel 	}
   1638      0       stevel 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bva.va_ctime)
   1639      0       stevel 
   1640      0       stevel 	vap = sarg.vap;
   1641      0       stevel 
   1642      0       stevel 	/*
   1643      0       stevel 	 * Set default initial values for attributes when not specified
   1644      0       stevel 	 * in createattrs.
   1645      0       stevel 	 */
   1646      0       stevel 	if ((vap->va_mask & AT_UID) == 0) {
   1647      0       stevel 		vap->va_uid = crgetuid(cr);
   1648      0       stevel 		vap->va_mask |= AT_UID;
   1649      0       stevel 	}
   1650      0       stevel 	if ((vap->va_mask & AT_GID) == 0) {
   1651      0       stevel 		vap->va_gid = crgetgid(cr);
   1652      0       stevel 		vap->va_mask |= AT_GID;
   1653      0       stevel 	}
   1654      0       stevel 
   1655      0       stevel 	vap->va_mask |= AT_TYPE;
   1656      0       stevel 	switch (args->type) {
   1657      0       stevel 	case NF4DIR:
   1658      0       stevel 		vap->va_type = VDIR;
   1659      0       stevel 		if ((vap->va_mask & AT_MODE) == 0) {
   1660      0       stevel 			vap->va_mode = 0700;	/* default: owner rwx only */
   1661      0       stevel 			vap->va_mask |= AT_MODE;
   1662      0       stevel 		}
   1663   5331          amw 		error = VOP_MKDIR(dvp, nm, vap, &vp, cr, NULL, 0, NULL);
   1664      0       stevel 		if (error)
   1665      0       stevel 			break;
   1666      0       stevel 
   1667      0       stevel 		/*
   1668      0       stevel 		 * Get the initial "after" sequence number, if it fails,
   1669      0       stevel 		 * set to zero
   1670      0       stevel 		 */
   1671      0       stevel 		iva.va_mask = AT_SEQ;
   1672   5331          amw 		if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
   1673      0       stevel 			iva.va_seq = 0;
   1674      0       stevel 		break;
   1675      0       stevel 	case NF4LNK:
   1676      0       stevel 		vap->va_type = VLNK;
   1677      0       stevel 		if ((vap->va_mask & AT_MODE) == 0) {
   1678      0       stevel 			vap->va_mode = 0700;	/* default: owner rwx only */
   1679      0       stevel 			vap->va_mask |= AT_MODE;
   1680      0       stevel 		}
   1681      0       stevel 
   1682      0       stevel 		/*
   1683      0       stevel 		 * symlink names must be treated as data
   1684      0       stevel 		 */
   1685      0       stevel 		lnm = utf8_to_str(&args->ftype4_u.linkdata, &llen, NULL);
   1686      0       stevel 
   1687      0       stevel 		if (lnm == NULL) {
   1688      0       stevel 			*cs->statusp = resp->status = NFS4ERR_INVAL;
   1689   7961      Natalie 			if (name != nm)
   1690   7961      Natalie 				kmem_free(name, MAXPATHLEN + 1);
   1691      0       stevel 			kmem_free(nm, len);
   1692      0       stevel 			nfs4_ntov_table_free(&ntov, &sarg);
   1693      0       stevel 			resp->attrset = 0;
   1694   5647         samf 			goto out;
   1695      0       stevel 		}
   1696      0       stevel 
   1697      0       stevel 		if (llen > MAXPATHLEN) {
   1698      0       stevel 			*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   1699   7961      Natalie 			if (name != nm)
   1700   7961      Natalie 				kmem_free(name, MAXPATHLEN + 1);
   1701      0       stevel 			kmem_free(nm, len);
   1702      0       stevel 			kmem_free(lnm, llen);
   1703      0       stevel 			nfs4_ntov_table_free(&ntov, &sarg);
   1704      0       stevel 			resp->attrset = 0;
   1705   5647         samf 			goto out;
   1706      0       stevel 		}
   1707      0       stevel 
   1708   7961      Natalie 		lname = nfscmd_convname(ca, cs->exi, lnm,
   1709   7961      Natalie 		    NFSCMD_CONV_INBOUND, MAXPATHLEN  + 1);
   1710   7961      Natalie 
   1711   7961      Natalie 		if (lname == NULL) {
   1712   7961      Natalie 			*cs->statusp = resp->status = NFS4ERR_SERVERFAULT;
   1713   7961      Natalie 			if (name != nm)
   1714   7961      Natalie 				kmem_free(name, MAXPATHLEN + 1);
   1715   7961      Natalie 			kmem_free(nm, len);
   1716   7961      Natalie 			kmem_free(lnm, llen);
   1717   7961      Natalie 			nfs4_ntov_table_free(&ntov, &sarg);
   1718   7961      Natalie 			resp->attrset = 0;
   1719   7961      Natalie 			goto out;
   1720   7961      Natalie 		}
   1721   7961      Natalie 
   1722   5331          amw 		error = VOP_SYMLINK(dvp, nm, vap, lnm, cr, NULL, 0);
   1723   7961      Natalie 		if (lname != lnm)
   1724   7961      Natalie 			kmem_free(lname, MAXPATHLEN + 1);
   1725      0       stevel 		if (lnm != NULL)
   1726      0       stevel 			kmem_free(lnm, llen);
   1727      0       stevel 		if (error)
   1728      0       stevel 			break;
   1729      0       stevel 
   1730      0       stevel 		/*
   1731      0       stevel 		 * Get the initial "after" sequence number, if it fails,
   1732      0       stevel 		 * set to zero
   1733      0       stevel 		 */
   1734      0       stevel 		iva.va_mask = AT_SEQ;
   1735   5331          amw 		if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
   1736      0       stevel 			iva.va_seq = 0;
   1737      0       stevel 
   1738   5331          amw 		error = VOP_LOOKUP(dvp, nm, &vp, NULL, 0, NULL, cr,
   1739   5331          amw 		    NULL, NULL, NULL);
   1740      0       stevel 		if (error)
   1741      0       stevel 			break;
   1742      0       stevel 
   1743      0       stevel 		/*
   1744      0       stevel 		 * va_seq is not safe over VOP calls, check it again
   1745      0       stevel 		 * if it has changed zero out iva to force atomic = FALSE.
   1746      0       stevel 		 */
   1747      0       stevel 		iva2.va_mask = AT_SEQ;
   1748   5331          amw 		if (VOP_GETATTR(dvp, &iva2, 0, cs->cr, NULL) ||
   1749   5050      jwahlig 		    iva2.va_seq != iva.va_seq)
   1750      0       stevel 			iva.va_seq = 0;
   1751      0       stevel 		break;
   1752      0       stevel 	default:
   1753      0       stevel 		/*
   1754      0       stevel 		 * probably a special file.
   1755      0       stevel 		 */
   1756      0       stevel 		if ((vap->va_mask & AT_MODE) == 0) {
   1757      0       stevel 			vap->va_mode = 0600;	/* default: owner rw only */
   1758      0       stevel 			vap->va_mask |= AT_MODE;
   1759      0       stevel 		}
   1760      0       stevel 		syncval = FNODSYNC;
   1761      0       stevel 		/*
   1762      0       stevel 		 * We know this will only generate one VOP call
   1763      0       stevel 		 */
   1764      0       stevel 		vp = do_rfs4_op_mknod(args, resp, req, cs, vap, nm);
   1765      0       stevel 
   1766      0       stevel 		if (vp == NULL) {
   1767   7961      Natalie 			if (name != nm)
   1768   7961      Natalie 				kmem_free(name, MAXPATHLEN + 1);
   1769      0       stevel 			kmem_free(nm, len);
   1770      0       stevel 			nfs4_ntov_table_free(&ntov, &sarg);
   1771      0       stevel 			resp->attrset = 0;
   1772   5647         samf 			goto out;
   1773      0       stevel 		}
   1774      0       stevel 
   1775      0       stevel 		/*
   1776      0       stevel 		 * Get the initial "after" sequence number, if it fails,
   1777      0       stevel 		 * set to zero
   1778      0       stevel 		 */
   1779      0       stevel 		iva.va_mask = AT_SEQ;
   1780   5331          amw 		if (VOP_GETATTR(dvp, &iva, 0, cs->cr, NULL))
   1781      0       stevel 			iva.va_seq = 0;
   1782      0       stevel 
   1783      0       stevel 		break;
   1784      0       stevel 	}
   1785   7961      Natalie 	if (name != nm)
   1786   7961      Natalie 		kmem_free(name, MAXPATHLEN + 1);
   1787      0       stevel 	kmem_free(nm, len);
   1788      0       stevel 
   1789      0       stevel 	if (error) {
   1790      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1791      0       stevel 	}
   1792      0       stevel 
   1793      0       stevel 	/*
   1794      0       stevel 	 * Force modified data and metadata out to stable storage.
   1795      0       stevel 	 */
   1796   5331          amw 	(void) VOP_FSYNC(dvp, 0, cr, NULL);
   1797      0       stevel 
   1798      0       stevel 	if (resp->status != NFS4_OK) {
   1799      0       stevel 		if (vp != NULL)
   1800      0       stevel 			VN_RELE(vp);
   1801      0       stevel 		nfs4_ntov_table_free(&ntov, &sarg);
   1802      0       stevel 		resp->attrset = 0;
   1803   5647         samf 		goto out;
   1804      0       stevel 	}
   1805      0       stevel 
   1806      0       stevel 	/*
   1807      0       stevel 	 * Finish setup of cinfo response, "before" value already set.
   1808      0       stevel 	 * Get "after" change value, if it fails, simply return the
   1809      0       stevel 	 * before value.
   1810      0       stevel 	 */
   1811      0       stevel 	ava.va_mask = AT_CTIME|AT_SEQ;
   1812   5331          amw 	if (VOP_GETATTR(dvp, &ava, 0, cr, NULL)) {
   1813      0       stevel 		ava.va_ctime = bva.va_ctime;
   1814      0       stevel 		ava.va_seq = 0;
   1815      0       stevel 	}
   1816      0       stevel 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, ava.va_ctime);
   1817      0       stevel 
   1818      0       stevel 	/*
   1819      0       stevel 	 * True verification that object was created with correct
   1820      0       stevel 	 * attrs is impossible.  The attrs could have been changed
   1821      0       stevel 	 * immediately after object creation.  If attributes did
   1822      0       stevel 	 * not verify, the only recourse for the server is to
   1823      0       stevel 	 * destroy the object.  Maybe if some attrs (like gid)
   1824      0       stevel 	 * are set incorrectly, the object should be destroyed;
   1825      0       stevel 	 * however, seems bad as a default policy.  Do we really
   1826      0       stevel 	 * want to destroy an object over one of the times not
   1827      0       stevel 	 * verifying correctly?  For these reasons, the server
   1828      0       stevel 	 * currently sets bits in attrset for createattrs
   1829      0       stevel 	 * that were set; however, no verification is done.
   1830      0       stevel 	 *
   1831      0       stevel 	 * vmask_to_nmask accounts for vattr bits set on create
   1832      0       stevel 	 *	[do_rfs4_set_attrs() only sets resp bits for
   1833      0       stevel 	 *	 non-vattr/vfs bits.]
   1834      0       stevel 	 * Mask off any bits set by default so as not to return
   1835      0       stevel 	 * more attrset bits than were requested in createattrs
   1836      0       stevel 	 */
   1837      0       stevel 	nfs4_vmask_to_nmask(sarg.vap->va_mask, &resp->attrset);
   1838      0       stevel 	resp->attrset &= args->createattrs.attrmask;
   1839      0       stevel 	nfs4_ntov_table_free(&ntov, &sarg);
   1840      0       stevel 
   1841      0       stevel 	error = makefh4(&cs->fh, vp, cs->exi);
   1842      0       stevel 	if (error) {
   1843      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   1844      0       stevel 	}
   1845      0       stevel 
   1846      0       stevel 	/*
   1847      0       stevel 	 * The cinfo.atomic = TRUE only if we got no errors, we have
   1848      0       stevel 	 * non-zero va_seq's, and it has incremented by exactly one
   1849      0       stevel 	 * during the creation and it didn't change during the VOP_LOOKUP
   1850      0       stevel 	 * or VOP_FSYNC.
   1851      0       stevel 	 */
   1852      0       stevel 	if (!error && bva.va_seq && iva.va_seq && ava.va_seq &&
   1853   5050      jwahlig 	    iva.va_seq == (bva.va_seq + 1) && iva.va_seq == ava.va_seq)
   1854      0       stevel 		resp->cinfo.atomic = TRUE;
   1855      0       stevel 	else
   1856      0       stevel 		resp->cinfo.atomic = FALSE;
   1857      0       stevel 
   1858   6402      gt29601 	/*
   1859   6402      gt29601 	 * Force modified metadata out to stable storage.
   1860   6402      gt29601 	 *
   1861   6402      gt29601 	 * if a underlying vp exists, pass it to VOP_FSYNC
   1862   6402      gt29601 	 */
   1863   6402      gt29601 	if (VOP_REALVP(vp, &realvp, NULL) == 0)
   1864   6402      gt29601 		(void) VOP_FSYNC(realvp, syncval, cr, NULL);
   1865   6402      gt29601 	else
   1866   6402      gt29601 		(void) VOP_FSYNC(vp, syncval, cr, NULL);
   1867      0       stevel 
   1868      0       stevel 	if (resp->status != NFS4_OK) {
   1869      0       stevel 		VN_RELE(vp);
   1870   5647         samf 		goto out;
   1871      0       stevel 	}
   1872      0       stevel 	if (cs->vp)
   1873      0       stevel 		VN_RELE(cs->vp);
   1874      0       stevel 
   1875      0       stevel 	cs->vp = vp;
   1876      0       stevel 	*cs->statusp = resp->status = NFS4_OK;
   1877   5647         samf out:
   1878   5647         samf 	DTRACE_NFSV4_2(op__create__done, struct compound_state *, cs,
   1879   5647         samf 	    CREATE4res *, resp);
   1880   5647         samf }
   1881   5647         samf 
   1882   5647         samf /*ARGSUSED*/
   1883   5647         samf static void
   1884   5647         samf rfs4_op_delegpurge(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1885   5647         samf     struct compound_state *cs)
   1886   5647         samf {
   1887   5647         samf 	DTRACE_NFSV4_2(op__delegpurge__start, struct compound_state *, cs,
   1888   5647         samf 	    DELEGPURGE4args *, &argop->nfs_argop4_u.opdelegpurge);
   1889   5647         samf 
   1890   5647         samf 	rfs4_op_inval(argop, resop, req, cs);
   1891   5647         samf 
   1892   5647         samf 	DTRACE_NFSV4_2(op__delegpurge__done, struct compound_state *, cs,
   1893   5647         samf 	    DELEGPURGE4res *, &resop->nfs_resop4_u.opdelegpurge);
   1894   5647         samf }
   1895      0       stevel 
   1896      0       stevel /*ARGSUSED*/
   1897      0       stevel static void
   1898      0       stevel rfs4_op_delegreturn(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   1899   9885       Robert     struct compound_state *cs)
   1900      0       stevel {
   1901      0       stevel 	DELEGRETURN4args *args = &argop->nfs_argop4_u.opdelegreturn;
   1902      0       stevel 	DELEGRETURN4res *resp = &resop->nfs_resop4_u.opdelegreturn;
   1903      0       stevel 	rfs4_deleg_state_t *dsp;
   1904      0       stevel 	nfsstat4 status;
   1905      0       stevel 
   1906   5647         samf 	DTRACE_NFSV4_2(op__delegreturn__start, struct compound_state *, cs,
   1907   5647         samf 	    DELEGRETURN4args *, args);
   1908   5647         samf 
   1909      0       stevel 	status = rfs4_get_deleg_state(&args->deleg_stateid, &dsp);
   1910      0       stevel 	resp->status = *cs->statusp = status;
   1911      0       stevel 	if (status != NFS4_OK)
   1912   5647         samf 		goto out;
   1913      0       stevel 
   1914      0       stevel 	/* Ensure specified filehandle matches */
   1915   9885       Robert 	if (cs->vp != dsp->rds_finfo->rf_vp) {
   1916      0       stevel 		resp->status = *cs->statusp = NFS4ERR_BAD_STATEID;
   1917      0       stevel 	} else
   1918      0       stevel 		rfs4_return_deleg(dsp, FALSE);
   1919      0       stevel 
   1920   9885       Robert 	rfs4_update_lease(dsp->rds_client);
   1921      0       stevel 
   1922      0       stevel 	rfs4_deleg_state_rele(dsp);
   1923   5647         samf out:
   1924   5647         samf 	DTRACE_NFSV4_2(op__delegreturn__done, struct compound_state *, cs,
   1925   5647         samf 	    DELEGRETURN4res *, resp);
   1926      0       stevel }
   1927      0       stevel 
   1928      0       stevel /*
   1929      0       stevel  * Check to see if a given "flavor" is an explicitly shared flavor.
   1930      0       stevel  * The assumption of this routine is the "flavor" is already a valid
   1931      0       stevel  * flavor in the secinfo list of "exi".
   1932      0       stevel  *
   1933      0       stevel  *	e.g.
   1934      0       stevel  *		# share -o sec=flavor1 /export
   1935      0       stevel  *		# share -o sec=flavor2 /export/home
   1936      0       stevel  *
   1937      0       stevel  *		flavor2 is not an explicitly shared flavor for /export,
   1938      0       stevel  *		however it is in the secinfo list for /export thru the
   1939      0       stevel  *		server namespace setup.
   1940      0       stevel  */
   1941      0       stevel int
   1942      0       stevel is_exported_sec(int flavor, struct exportinfo *exi)
   1943      0       stevel {
   1944      0       stevel 	int	i;
   1945      0       stevel 	struct secinfo *sp;
   1946      0       stevel 
   1947      0       stevel 	sp = exi->exi_export.ex_secinfo;
   1948      0       stevel 	for (i = 0; i < exi->exi_export.ex_seccnt; i++) {
   1949      0       stevel 		if (flavor == sp[i].s_secinfo.sc_nfsnum ||
   1950      0       stevel 		    sp[i].s_secinfo.sc_nfsnum == AUTH_NONE) {
   1951      0       stevel 			return (SEC_REF_EXPORTED(&sp[i]));
   1952      0       stevel 		}
   1953      0       stevel 	}
   1954      0       stevel 
   1955      0       stevel 	/* Should not reach this point based on the assumption */
   1956      0       stevel 	return (0);
   1957      0       stevel }
   1958      0       stevel 
   1959      0       stevel /*
   1960      0       stevel  * Check if the security flavor used in the request matches what is
   1961      0       stevel  * required at the export point or at the root pseudo node (exi_root).
   1962      0       stevel  *
   1963      0       stevel  * returns 1 if there's a match or if exported with AUTH_NONE; 0 otherwise.
   1964      0       stevel  *
   1965      0       stevel  */
   1966      0       stevel static int
   1967      0       stevel secinfo_match_or_authnone(struct compound_state *cs)
   1968      0       stevel {
   1969      0       stevel 	int	i;
   1970      0       stevel 	struct secinfo *sp;
   1971      0       stevel 
   1972      0       stevel 	/*
   1973      0       stevel 	 * Check cs->nfsflavor (from the request) against
   1974      0       stevel 	 * the current export data in cs->exi.
   1975      0       stevel 	 */
   1976      0       stevel 	sp = cs->exi->exi_export.ex_secinfo;
   1977      0       stevel 	for (i = 0; i < cs->exi->exi_export.ex_seccnt; i++) {
   1978      0       stevel 		if (cs->nfsflavor == sp[i].s_secinfo.sc_nfsnum ||
   1979      0       stevel 		    sp[i].s_secinfo.sc_nfsnum == AUTH_NONE)
   1980      0       stevel 			return (1);
   1981      0       stevel 	}
   1982      0       stevel 
   1983      0       stevel 	return (0);
   1984      0       stevel }
   1985      0       stevel 
   1986      0       stevel /*
   1987      0       stevel  * Check the access authority for the client and return the correct error.
   1988      0       stevel  */
   1989      0       stevel nfsstat4
   1990      0       stevel call_checkauth4(struct compound_state *cs, struct svc_req *req)
   1991      0       stevel {
   1992      0       stevel 	int	authres;
   1993      0       stevel 
   1994      0       stevel 	/*
   1995      0       stevel 	 * First, check if the security flavor used in the request
   1996      0       stevel 	 * are among the flavors set in the server namespace.
   1997      0       stevel 	 */
   1998      0       stevel 	if (!secinfo_match_or_authnone(cs)) {
   1999      0       stevel 		*cs->statusp = NFS4ERR_WRONGSEC;
   2000      0       stevel 		return (*cs->statusp);
   2001      0       stevel 	}
   2002      0       stevel 
   2003      0       stevel 	authres = checkauth4(cs, req);
   2004      0       stevel 
   2005      0       stevel 	if (authres > 0) {
   2006      0       stevel 		*cs->statusp = NFS4_OK;
   2007      0       stevel 		if (! (cs->access & CS_ACCESS_LIMITED))
   2008      0       stevel 			cs->access = CS_ACCESS_OK;
   2009      0       stevel 	} else if (authres == 0) {
   2010      0       stevel 		*cs->statusp = NFS4ERR_ACCESS;
   2011      0       stevel 	} else if (authres == -2) {
   2012      0       stevel 		*cs->statusp = NFS4ERR_WRONGSEC;
   2013      0       stevel 	} else {
   2014      0       stevel 		*cs->statusp = NFS4ERR_DELAY;
   2015      0       stevel 	}
   2016      0       stevel 	return (*cs->statusp);
   2017      0       stevel }
   2018      0       stevel 
   2019      0       stevel /*
   2020      0       stevel  * bitmap4_to_attrmask is called by getattr and readdir.
   2021      0       stevel  * It sets up the vattr mask and determines whether vfsstat call is needed
   2022      0       stevel  * based on the input bitmap.
   2023      0       stevel  * Returns nfsv4 status.
   2024      0       stevel  */
   2025      0       stevel static nfsstat4
   2026      0       stevel bitmap4_to_attrmask(bitmap4 breq, struct nfs4_svgetit_arg *sargp)
   2027      0       stevel {
   2028      0       stevel 	int i;
   2029      0       stevel 	uint_t	va_mask;
   2030      0       stevel 	struct statvfs64 *sbp = sargp->sbp;
   2031      0       stevel 
   2032      0       stevel 	sargp->sbp = NULL;
   2033      0       stevel 	sargp->flag = 0;
   2034      0       stevel 	sargp->rdattr_error = NFS4_OK;
   2035      0       stevel 	sargp->mntdfid_set = FALSE;
   2036      0       stevel 	if (sargp->cs->vp)
   2037      0       stevel 		sargp->xattr = get_fh4_flag(&sargp->cs->fh,
   2038   5050      jwahlig 		    FH4_ATTRDIR | FH4_NAMEDATTR);
   2039      0       stevel 	else
   2040      0       stevel 		sargp->xattr = 0;
   2041      0       stevel 
   2042      0       stevel 	/*
   2043      0       stevel 	 * Set rdattr_error_req to true if return error per
   2044      0       stevel 	 * failed entry rather than fail the readdir.
   2045      0       stevel 	 */
   2046      0       stevel 	if (breq & FATTR4_RDATTR_ERROR_MASK)
   2047      0       stevel 		sargp->rdattr_error_req = 1;
   2048      0       stevel 	else
   2049      0       stevel 		sargp->rdattr_error_req = 0;
   2050      0       stevel 
   2051      0       stevel 	/*
   2052      0       stevel 	 * generate the va_mask
   2053      0       stevel 	 * Handle the easy cases first
   2054      0       stevel 	 */
   2055      0       stevel 	switch (breq) {
   2056      0       stevel 	case NFS4_NTOV_ATTR_MASK:
   2057      0       stevel 		sargp->vap->va_mask = NFS4_NTOV_ATTR_AT_MASK;
   2058      0       stevel 		return (NFS4_OK);
   2059      0       stevel 
   2060      0       stevel 	case NFS4_FS_ATTR_MASK:
   2061      0       stevel 		sargp->vap->va_mask = NFS4_FS_ATTR_AT_MASK;
   2062      0       stevel 		sargp->sbp = sbp;
   2063      0       stevel 		return (NFS4_OK);
   2064      0       stevel 
   2065      0       stevel 	case NFS4_NTOV_ATTR_CACHE_MASK:
   2066      0       stevel 		sargp->vap->va_mask = NFS4_NTOV_ATTR_CACHE_AT_MASK;
   2067      0       stevel 		return (NFS4_OK);
   2068      0       stevel 
   2069      0       stevel 	case FATTR4_LEASE_TIME_MASK:
   2070      0       stevel 		sargp->vap->va_mask = 0;
   2071      0       stevel 		return (NFS4_OK);
   2072      0       stevel 
   2073      0       stevel 	default:
   2074      0       stevel 		va_mask = 0;
   2075      0       stevel 		for (i = 0; i < nfs4_ntov_map_size; i++) {
   2076      0       stevel 			if ((breq & nfs4_ntov_map[i].fbit) &&
   2077   5050      jwahlig 			    nfs4_ntov_map[i].vbit)
   2078      0       stevel 				va_mask |= nfs4_ntov_map[i].vbit;
   2079      0       stevel 		}
   2080      0       stevel 
   2081      0       stevel 		/*
   2082      0       stevel 		 * Check is vfsstat is needed
   2083      0       stevel 		 */
   2084      0       stevel 		if (breq & NFS4_FS_ATTR_MASK)
   2085      0       stevel 			sargp->sbp = sbp;
   2086      0       stevel 
   2087      0       stevel 		sargp->vap->va_mask = va_mask;
   2088      0       stevel 		return (NFS4_OK);
   2089      0       stevel 	}
   2090      0       stevel 	/* NOTREACHED */
   2091      0       stevel }
   2092      0       stevel 
   2093      0       stevel /*
   2094      0       stevel  * bitmap4_get_sysattrs is called by getattr and readdir.
   2095      0       stevel  * It calls both VOP_GETATTR and VFS_STATVFS calls to get the attrs.
   2096      0       stevel  * Returns nfsv4 status.
   2097      0       stevel  */
   2098      0       stevel static nfsstat4
   2099      0       stevel bitmap4_get_sysattrs(struct nfs4_svgetit_arg *sargp)
   2100      0       stevel {
   2101      0       stevel 	int error;
   2102      0       stevel 	struct compound_state *cs = sargp->cs;
   2103      0       stevel 	vnode_t *vp = cs->vp;
   2104      0       stevel 
   2105      0       stevel 	if (sargp->sbp != NULL) {
   2106      0       stevel 		if (error = VFS_STATVFS(vp->v_vfsp, sargp->sbp)) {
   2107      0       stevel 			sargp->sbp = NULL;	/* to identify error */
   2108      0       stevel 			return (puterrno4(error));
   2109      0       stevel 		}
   2110      0       stevel 	}
   2111      0       stevel 
   2112      0       stevel 	return (rfs4_vop_getattr(vp, sargp->vap, 0, cs->cr));
   2113      0       stevel }
   2114      0       stevel 
   2115      0       stevel static void
   2116      0       stevel nfs4_ntov_table_init(struct nfs4_ntov_table *ntovp)
   2117      0       stevel {
   2118      0       stevel 	ntovp->na = kmem_zalloc(sizeof (union nfs4_attr_u) * nfs4_ntov_map_size,
   2119   5050      jwahlig 	    KM_SLEEP);
   2120      0       stevel 	ntovp->attrcnt = 0;
   2121      0       stevel 	ntovp->vfsstat = FALSE;
   2122      0       stevel }
   2123      0       stevel 
   2124      0       stevel static void
   2125      0       stevel nfs4_ntov_table_free(struct nfs4_ntov_table *ntovp,
   2126   9885       Robert     struct nfs4_svgetit_arg *sargp)
   2127      0       stevel {
   2128      0       stevel 	int i;
   2129      0       stevel 	union nfs4_attr_u *na;
   2130      0       stevel 	uint8_t *amap;
   2131      0       stevel 
   2132      0       stevel 	/*
   2133      0       stevel 	 * XXX Should do the same checks for whether the bit is set
   2134      0       stevel 	 */
   2135      0       stevel 	for (i = 0, na = ntovp->na, amap = ntovp->amap;
   2136   5050      jwahlig 	    i < ntovp->attrcnt; i++, na++, amap++) {
   2137      0       stevel 		(void) (*nfs4_ntov_map[*amap].sv_getit)(
   2138   5050      jwahlig 		    NFS4ATTR_FREEIT, sargp, na);
   2139      0       stevel 	}
   2140      0       stevel 	if ((sargp->op == NFS4ATTR_SETIT) || (sargp->op == NFS4ATTR_VERIT)) {
   2141      0       stevel 		/*
   2142      0       stevel 		 * xdr_free for getattr will be done later
   2143      0       stevel 		 */
   2144      0       stevel 		for (i = 0, na = ntovp->na, amap = ntovp->amap;
   2145   5050      jwahlig 		    i < ntovp->attrcnt; i++, na++, amap++) {
   2146      0       stevel 			xdr_free(nfs4_ntov_map[*amap].xfunc, (caddr_t)na);
   2147      0       stevel 		}
   2148      0       stevel 	}
   2149      0       stevel 	kmem_free(ntovp->na, sizeof (union nfs4_attr_u) * nfs4_ntov_map_size);
   2150      0       stevel }
   2151      0       stevel 
   2152      0       stevel /*
   2153      0       stevel  * do_rfs4_op_getattr gets the system attrs and converts into fattr4.
   2154      0       stevel  */
   2155      0       stevel static nfsstat4
   2156      0       stevel do_rfs4_op_getattr(bitmap4 breq, fattr4 *fattrp,
   2157   9885       Robert     struct nfs4_svgetit_arg *sargp)
   2158      0       stevel {
   2159      0       stevel 	int error = 0;
   2160      0       stevel 	int i, k;
   2161      0       stevel 	struct nfs4_ntov_table ntov;
   2162      0       stevel 	XDR xdr;
   2163      0       stevel 	ulong_t xdr_size;
   2164      0       stevel 	char *xdr_attrs;
   2165      0       stevel 	nfsstat4 status = NFS4_OK;
   2166      0       stevel 	nfsstat4 prev_rdattr_error = sargp->rdattr_error;
   2167      0       stevel 	union nfs4_attr_u *na;
   2168      0       stevel 	uint8_t *amap;
   2169      0       stevel 
   2170      0       stevel 	sargp->op = NFS4ATTR_GETIT;
   2171      0       stevel 	sargp->flag = 0;
   2172      0       stevel 
   2173      0       stevel 	fattrp->attrmask = 0;
   2174      0       stevel 	/* if no bits requested, then return empty fattr4 */
   2175      0       stevel 	if (breq == 0) {
   2176      0       stevel 		fattrp->attrlist4_len = 0;
   2177      0       stevel 		fattrp->attrlist4 = NULL;
   2178      0       stevel 		return (NFS4_OK);
   2179      0       stevel 	}
   2180      0       stevel 
   2181      0       stevel 	/*
   2182      0       stevel 	 * return NFS4ERR_INVAL when client requests write-only attrs
   2183      0       stevel 	 */
   2184      0       stevel 	if (breq & (FATTR4_TIME_ACCESS_SET_MASK | FATTR4_TIME_MODIFY_SET_MASK))
   2185      0       stevel 		return (NFS4ERR_INVAL);
   2186      0       stevel 
   2187      0       stevel 	nfs4_ntov_table_init(&ntov);
   2188      0       stevel 	na = ntov.na;
   2189      0       stevel 	amap = ntov.amap;
   2190      0       stevel 
   2191      0       stevel 	/*
   2192      0       stevel 	 * Now loop to get or verify the attrs
   2193      0       stevel 	 */
   2194      0       stevel 	for (i = 0; i < nfs4_ntov_map_size; i++) {
   2195      0       stevel 		if (breq & nfs4_ntov_map[i].fbit) {
   2196      0       stevel 			if ((*nfs4_ntov_map[i].sv_getit)(
   2197   5050      jwahlig 			    NFS4ATTR_SUPPORTED, sargp, NULL) == 0) {
   2198      0       stevel 
   2199      0       stevel 				error = (*nfs4_ntov_map[i].sv_getit)(
   2200   5050      jwahlig 				    NFS4ATTR_GETIT, sargp, na);
   2201      0       stevel 
   2202      0       stevel 				/*
   2203      0       stevel 				 * Possible error values:
   2204      0       stevel 				 * >0 if sv_getit failed to
   2205      0       stevel 				 * get the attr; 0 if succeeded;
   2206      0       stevel 				 * <0 if rdattr_error and the
   2207      0       stevel 				 * attribute cannot be returned.
   2208      0       stevel 				 */
   2209      0       stevel 				if (error && !(sargp->rdattr_error_req))
   2210      0       stevel 					goto done;
   2211      0       stevel 				/*
   2212      0       stevel 				 * If error then just for entry
   2213      0       stevel 				 */
   2214      0       stevel 				if (error == 0) {
   2215      0       stevel 					fattrp->attrmask |=
   2216   5050      jwahlig 					    nfs4_ntov_map[i].fbit;
   2217      0       stevel 					*amap++ =
   2218   5050      jwahlig 					    (uint8_t)nfs4_ntov_map[i].nval;
   2219      0       stevel 					na++;
   2220      0       stevel 					(ntov.attrcnt)++;
   2221      0       stevel 				} else if ((error > 0) &&
   2222   5050      jwahlig 				    (sargp->rdattr_error == NFS4_OK)) {
   2223      0       stevel 					sargp->rdattr_error = puterrno4(error);
   2224      0       stevel 				}
   2225      0       stevel 				error = 0;
   2226      0       stevel 			}
   2227      0       stevel 		}
   2228      0       stevel 	}
   2229      0       stevel 
   2230      0       stevel 	/*
   2231      0       stevel 	 * If rdattr_error was set after the return value for it was assigned,
   2232      0       stevel 	 * update it.
   2233      0       stevel 	 */
   2234      0       stevel 	if (prev_rdattr_error != sargp->rdattr_error) {
   2235      0       stevel 		na = ntov.na;
   2236      0       stevel 		amap = ntov.amap;
   2237      0       stevel 		for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
   2238      0       stevel 			k = *amap;
   2239      0       stevel 			if (k < FATTR4_RDATTR_ERROR) {
   2240      0       stevel 				continue;
   2241      0       stevel 			}
   2242      0       stevel 			if ((k == FATTR4_RDATTR_ERROR) &&
   2243      0       stevel 			    ((*nfs4_ntov_map[k].sv_getit)(
   2244   5050      jwahlig 			    NFS4ATTR_SUPPORTED, sargp, NULL) == 0)) {
   2245      0       stevel 
   2246      0       stevel 				(void) (*nfs4_ntov_map[k].sv_getit)(
   2247   5050      jwahlig 				    NFS4ATTR_GETIT, sargp, na);
   2248      0       stevel 			}
   2249      0       stevel 			break;
   2250      0       stevel 		}
   2251      0       stevel 	}
   2252      0       stevel 
   2253      0       stevel 	xdr_size = 0;
   2254      0       stevel 	na = ntov.na;
   2255      0       stevel 	amap = ntov.amap;
   2256      0       stevel 	for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
   2257      0       stevel 		xdr_size += xdr_sizeof(nfs4_ntov_map[*amap].xfunc, na);
   2258      0       stevel 	}
   2259      0       stevel 
   2260      0       stevel 	fattrp->attrlist4_len = xdr_size;
   2261      0       stevel 	if (xdr_size) {
   2262      0       stevel 		/* freed by rfs4_op_getattr_free() */
   2263      0       stevel 		fattrp->attrlist4 = xdr_attrs = kmem_zalloc(xdr_size, KM_SLEEP);
   2264      0       stevel 
   2265      0       stevel 		xdrmem_create(&xdr, xdr_attrs, xdr_size, XDR_ENCODE);
   2266      0       stevel 
   2267      0       stevel 		na = ntov.na;
   2268      0       stevel 		amap = ntov.amap;
   2269      0       stevel 		for (i = 0; i < ntov.attrcnt; i++, na++, amap++) {
   2270      0       stevel 			if (!(*nfs4_ntov_map[*amap].xfunc)(&xdr, na)) {
   2271   7387       Robert 				DTRACE_PROBE1(nfss__e__getattr4_encfail,
   2272   7387       Robert 				    int, *amap);
   2273      0       stevel 				status = NFS4ERR_SERVERFAULT;
   2274      0       stevel 				break;
   2275      0       stevel 			}
   2276      0       stevel 		}
   2277      0       stevel 		/* xdrmem_destroy(&xdrs); */	/* NO-OP */
   2278      0       stevel 	} else {
   2279      0       stevel 		fattrp->attrlist4 = NULL;
   2280      0       stevel 	}
   2281      0       stevel done:
   2282      0       stevel 
   2283      0       stevel 	nfs4_ntov_table_free(&ntov, sargp);
   2284      0       stevel 
   2285      0       stevel 	if (error != 0)
   2286      0       stevel 		status = puterrno4(error);
   2287      0       stevel 
   2288      0       stevel 	return (status);
   2289      0       stevel }
   2290      0       stevel 
   2291      0       stevel /* ARGSUSED */
   2292      0       stevel static void
   2293      0       stevel rfs4_op_getattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2294   9885       Robert     struct compound_state *cs)
   2295      0       stevel {
   2296      0       stevel 	GETATTR4args *args = &argop->nfs_argop4_u.opgetattr;
   2297      0       stevel 	GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
   2298      0       stevel 	struct nfs4_svgetit_arg sarg;
   2299      0       stevel 	struct statvfs64 sb;
   2300      0       stevel 	nfsstat4 status;
   2301      0       stevel 
   2302   5647         samf 	DTRACE_NFSV4_2(op__getattr__start, struct compound_state *, cs,
   2303   5647         samf 	    GETATTR4args *, args);
   2304   5647         samf 
   2305   5647         samf 	if (cs->vp == NULL) {
   2306   5647         samf 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2307   5647         samf 		goto out;
   2308   5647         samf 	}
   2309   5647         samf 
   2310   5647         samf 	if (cs->access == CS_ACCESS_DENIED) {
   2311   5647         samf 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   2312   5647         samf 		goto out;
   2313      0       stevel 	}
   2314      0       stevel 
   2315      0       stevel 	sarg.sbp = &sb;
   2316      0       stevel 	sarg.cs = cs;
   2317      0       stevel 
   2318      0       stevel 	status = bitmap4_to_attrmask(args->attr_request, &sarg);
   2319      0       stevel 	if (status == NFS4_OK) {
   2320      0       stevel 		status = bitmap4_get_sysattrs(&sarg);
   2321      0       stevel 		if (status == NFS4_OK)
   2322      0       stevel 			status = do_rfs4_op_getattr(args->attr_request,
   2323   5050      jwahlig 			    &resp->obj_attributes, &sarg);
   2324      0       stevel 	}
   2325      0       stevel 	*cs->statusp = resp->status = status;
   2326   5647         samf out:
   2327   5647         samf 	DTRACE_NFSV4_2(op__getattr__done, struct compound_state *, cs,
   2328   5647         samf 	    GETATTR4res *, resp);
   2329      0       stevel }
   2330      0       stevel 
   2331      0       stevel static void
   2332      0       stevel rfs4_op_getattr_free(nfs_resop4 *resop)
   2333      0       stevel {
   2334      0       stevel 	GETATTR4res *resp = &resop->nfs_resop4_u.opgetattr;
   2335      0       stevel 
   2336      0       stevel 	nfs4_fattr4_free(&resp->obj_attributes);
   2337      0       stevel }
   2338      0       stevel 
   2339      0       stevel /* ARGSUSED */
   2340      0       stevel static void
   2341      0       stevel rfs4_op_getfh(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2342   9885       Robert     struct compound_state *cs)
   2343      0       stevel {
   2344      0       stevel 	GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
   2345      0       stevel 
   2346   5647         samf 	DTRACE_NFSV4_1(op__getfh__start, struct compound_state *, cs);
   2347   5647         samf 
   2348   5647         samf 	if (cs->vp == NULL) {
   2349   5647         samf 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2350   5647         samf 		goto out;
   2351   5647         samf 	}
   2352   5647         samf 	if (cs->access == CS_ACCESS_DENIED) {
   2353   5647         samf 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   2354   5647         samf 		goto out;
   2355      0       stevel 	}
   2356      0       stevel 
   2357      0       stevel 	resp->object.nfs_fh4_val =
   2358   5050      jwahlig 	    kmem_alloc(cs->fh.nfs_fh4_len, KM_SLEEP);
   2359      0       stevel 	nfs_fh4_copy(&cs->fh, &resp->object);
   2360      0       stevel 	*cs->statusp = resp->status = NFS4_OK;
   2361   5647         samf out:
   2362   5647         samf 	DTRACE_NFSV4_2(op__getfh__done, struct compound_state *, cs,
   2363   5647         samf 	    GETFH4res *, resp);
   2364      0       stevel }
   2365      0       stevel 
   2366      0       stevel static void
   2367      0       stevel rfs4_op_getfh_free(nfs_resop4 *resop)
   2368      0       stevel {
   2369      0       stevel 	GETFH4res *resp = &resop->nfs_resop4_u.opgetfh;
   2370      0       stevel 
   2371      0       stevel 	if (resp->status == NFS4_OK &&
   2372      0       stevel 	    resp->object.nfs_fh4_val != NULL) {
   2373      0       stevel 		kmem_free(resp->object.nfs_fh4_val, resp->object.nfs_fh4_len);
   2374      0       stevel 		resp->object.nfs_fh4_val = NULL;
   2375      0       stevel 		resp->object.nfs_fh4_len = 0;
   2376      0       stevel 	}
   2377      0       stevel }
   2378      0       stevel 
   2379      0       stevel /*
   2380      0       stevel  * illegal: args: void
   2381      0       stevel  *	    res : status (NFS4ERR_OP_ILLEGAL)
   2382      0       stevel  */
   2383      0       stevel /* ARGSUSED */
   2384      0       stevel static void
   2385      0       stevel rfs4_op_illegal(nfs_argop4 *argop, nfs_resop4 *resop,
   2386   9885       Robert     struct svc_req *req, struct compound_state *cs)
   2387      0       stevel {
   2388      0       stevel 	ILLEGAL4res *resp = &resop->nfs_resop4_u.opillegal;
   2389      0       stevel 
   2390      0       stevel 	resop->resop = OP_ILLEGAL;
   2391      0       stevel 	*cs->statusp = resp->status = NFS4ERR_OP_ILLEGAL;
   2392      0       stevel }
   2393      0       stevel 
   2394      0       stevel /*
   2395      0       stevel  * link: args: SAVED_FH: file, CURRENT_FH: target directory
   2396      0       stevel  *	 res: status. If success - CURRENT_FH unchanged, return change_info
   2397      0       stevel  */
   2398      0       stevel /* ARGSUSED */
   2399      0       stevel static void
   2400      0       stevel rfs4_op_link(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2401   9885       Robert     struct compound_state *cs)
   2402      0       stevel {
   2403      0       stevel 	LINK4args *args = &argop->nfs_argop4_u.oplink;
   2404      0       stevel 	LINK4res *resp = &resop->nfs_resop4_u.oplink;
   2405      0       stevel 	int error;
   2406      0       stevel 	vnode_t *vp;
   2407      0       stevel 	vnode_t *dvp;
   2408      0       stevel 	struct vattr bdva, idva, adva;
   2409      0       stevel 	char *nm;
   2410      0       stevel 	uint_t  len;
   2411   7961      Natalie 	struct sockaddr *ca;
   2412   7961      Natalie 	char *name = NULL;
   2413      0       stevel 
   2414   5647         samf 	DTRACE_NFSV4_2(op__link__start, struct compound_state *, cs,
   2415   5647         samf 	    LINK4args *, args);
   2416   5647         samf 
   2417      0       stevel 	/* SAVED_FH: source object */
   2418      0       stevel 	vp = cs->saved_vp;
   2419      0       stevel 	if (vp == NULL) {
   2420      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2421   5647         samf 		goto out;
   2422      0       stevel 	}
   2423      0       stevel 
   2424      0       stevel 	/* CURRENT_FH: target directory */
   2425      0       stevel 	dvp = cs->vp;
   2426      0       stevel 	if (dvp == NULL) {
   2427      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2428   5647         samf 		goto out;
   2429      0       stevel 	}
   2430      0       stevel 
   2431      0       stevel 	/*
   2432      0       stevel 	 * If there is a non-shared filesystem mounted on this vnode,
   2433      0       stevel 	 * do not allow to link any file in this directory.
   2434      0       stevel 	 */
   2435      0       stevel 	if (vn_ismntpt(dvp)) {
   2436      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   2437   5647         samf 		goto out;
   2438   5647         samf 	}
   2439   5647         samf 
   2440   5647         samf 	if (cs->access == CS_ACCESS_DENIED) {
   2441   5647         samf 		*cs->statusp = resp->status = NFS4ERR_ACCESS;
   2442   5647         samf 		goto out;
   2443      0       stevel 	}
   2444      0       stevel 
   2445      0       stevel 	/* Check source object's type validity */
   2446      0       stevel 	if (vp->v_type == VDIR) {
   2447      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ISDIR;
   2448   5647         samf 		goto out;
   2449      0       stevel 	}
   2450      0       stevel 
   2451      0       stevel 	/* Check target directory's type */
   2452      0       stevel 	if (dvp->v_type != VDIR) {
   2453      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   2454   5647         samf 		goto out;
   2455      0       stevel 	}
   2456      0       stevel 
   2457      0       stevel 	if (cs->saved_exi != cs->exi) {
   2458      0       stevel 		*cs->statusp = resp->status = NFS4ERR_XDEV;
   2459   5647         samf 		goto out;
   2460      0       stevel 	}
   2461      0       stevel 
   2462      0       stevel 	if (!utf8_dir_verify(&args->newname)) {
   2463      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2464   5647         samf 		goto out;
   2465      0       stevel 	}
   2466      0       stevel 
   2467      0       stevel 	nm = utf8_to_fn(&args->newname, &len, NULL);
   2468      0       stevel 	if (nm == NULL) {
   2469      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2470   5647         samf 		goto out;
   2471      0       stevel 	}
   2472      0       stevel 
   2473      0       stevel 	if (len > MAXNAMELEN) {
   2474      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   2475      0       stevel 		kmem_free(nm, len);
   2476   5647         samf 		goto out;
   2477      0       stevel 	}
   2478      0       stevel 
   2479      0       stevel 	if (rdonly4(cs->exi, cs->vp, req)) {
   2480      0       stevel 		*cs->statusp = resp->status = NFS4ERR_ROFS;
   2481      0       stevel 		kmem_free(nm, len);
   2482   5647         samf 		goto out;
   2483      0       stevel 	}
   2484      0       stevel 
   2485      0       stevel 	/* Get "before" change value */
   2486      0       stevel 	bdva.va_mask = AT_CTIME|AT_SEQ;
   2487   5331          amw 	error = VOP_GETATTR(dvp, &bdva, 0, cs->cr, NULL);
   2488      0       stevel 	if (error) {
   2489      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   2490      0       stevel 		kmem_free(nm, len);
   2491   5647         samf 		goto out;
   2492      0       stevel 	}
   2493      0       stevel 
   2494   7961      Natalie 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   2495   7961      Natalie 	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
   2496   7961      Natalie 	    MAXPATHLEN  + 1);
   2497   7961      Natalie 
   2498   7961      Natalie 	if (name == NULL) {
   2499   7961      Natalie 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2500   7961      Natalie 		kmem_free(nm, len);
   2501   7961      Natalie 		goto out;
   2502   7961      Natalie 	}
   2503   7961      Natalie 
   2504      0       stevel 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.before, bdva.va_ctime)
   2505      0       stevel 
   2506   7961      Natalie 	error = VOP_LINK(dvp, vp, name, cs->cr, NULL, 0);
   2507   7961      Natalie 
   2508   7961      Natalie 	if (nm != name)
   2509   7961      Natalie 		kmem_free(name, MAXPATHLEN + 1);
   2510      0       stevel 	kmem_free(nm, len);
   2511      0       stevel 
   2512      0       stevel 	/*
   2513      0       stevel 	 * Get the initial "after" sequence number, if it fails, set to zero
   2514      0       stevel 	 */
   2515      0       stevel 	idva.va_mask = AT_SEQ;
   2516   5331          amw 	if (VOP_GETATTR(dvp, &idva, 0, cs->cr, NULL))
   2517      0       stevel 		idva.va_seq = 0;
   2518      0       stevel 
   2519      0       stevel 	/*
   2520      0       stevel 	 * Force modified data and metadata out to stable storage.
   2521      0       stevel 	 */
   2522   5331          amw 	(void) VOP_FSYNC(vp, FNODSYNC, cs->cr, NULL);
   2523   5331          amw 	(void) VOP_FSYNC(dvp, 0, cs->cr, NULL);
   2524      0       stevel 
   2525      0       stevel 	if (error) {
   2526      0       stevel 		*cs->statusp = resp->status = puterrno4(error);
   2527   5647         samf 		goto out;
   2528      0       stevel 	}
   2529      0       stevel 
   2530      0       stevel 	/*
   2531      0       stevel 	 * Get "after" change value, if it fails, simply return the
   2532      0       stevel 	 * before value.
   2533      0       stevel 	 */
   2534      0       stevel 	adva.va_mask = AT_CTIME|AT_SEQ;
   2535   5331          amw 	if (VOP_GETATTR(dvp, &adva, 0, cs->cr, NULL)) {
   2536      0       stevel 		adva.va_ctime = bdva.va_ctime;
   2537      0       stevel 		adva.va_seq = 0;
   2538      0       stevel 	}
   2539      0       stevel 
   2540      0       stevel 	NFS4_SET_FATTR4_CHANGE(resp->cinfo.after, adva.va_ctime)
   2541      0       stevel 
   2542      0       stevel 	/*
   2543      0       stevel 	 * The cinfo.atomic = TRUE only if we have
   2544      0       stevel 	 * non-zero va_seq's, and it has incremented by exactly one
   2545      0       stevel 	 * during the VOP_LINK and it didn't change during the VOP_FSYNC.
   2546      0       stevel 	 */
   2547      0       stevel 	if (bdva.va_seq && idva.va_seq && adva.va_seq &&
   2548   5050      jwahlig 	    idva.va_seq == (bdva.va_seq + 1) && idva.va_seq == adva.va_seq)
   2549      0       stevel 		resp->cinfo.atomic = TRUE;
   2550      0       stevel 	else
   2551      0       stevel 		resp->cinfo.atomic = FALSE;
   2552      0       stevel 
   2553      0       stevel 	*cs->statusp = resp->status = NFS4_OK;
   2554   5647         samf out:
   2555   5647         samf 	DTRACE_NFSV4_2(op__link__done, struct compound_state *, cs,
   2556   5647         samf 	    LINK4res *, resp);
   2557      0       stevel }
   2558      0       stevel 
   2559      0       stevel /*
   2560      0       stevel  * Used by rfs4_op_lookup and rfs4_op_lookupp to do the actual work.
   2561      0       stevel  */
   2562      0       stevel 
   2563      0       stevel /* ARGSUSED */
   2564      0       stevel static nfsstat4
   2565      0       stevel do_rfs4_op_lookup(char *nm, uint_t buflen, struct svc_req *req,
   2566   9885       Robert     struct compound_state *cs)
   2567      0       stevel {
   2568      0       stevel 	int error;
   2569      0       stevel 	int different_export = 0;
   2570      0       stevel 	vnode_t *vp, *tvp, *pre_tvp = NULL, *oldvp = NULL;
   2571      0       stevel 	struct exportinfo *exi = NULL, *pre_exi = NULL;
   2572      0       stevel 	nfsstat4 stat;
   2573      0       stevel 	fid_t fid;
   2574      0       stevel 	int attrdir, dotdot, walk;
   2575      0       stevel 	bool_t is_newvp = FALSE;
   2576      0       stevel 
   2577      0       stevel 	if (cs->vp->v_flag & V_XATTRDIR) {
   2578      0       stevel 		attrdir = 1;
   2579      0       stevel 		ASSERT(get_fh4_flag(&cs->fh, FH4_ATTRDIR));
   2580      0       stevel 	} else {
   2581      0       stevel 		attrdir = 0;
   2582      0       stevel 		ASSERT(! get_fh4_flag(&cs->fh, FH4_ATTRDIR));
   2583      0       stevel 	}
   2584      0       stevel 
   2585      0       stevel 	dotdot = (nm[0] == '.' && nm[1] == '.' && nm[2] == '\0');
   2586      0       stevel 
   2587      0       stevel 	/*
   2588      0       stevel 	 * If dotdotting, then need to check whether it's
   2589      0       stevel 	 * above the root of a filesystem, or above an
   2590      0       stevel 	 * export point.
   2591      0       stevel 	 */
   2592      0       stevel 	if (dotdot) {
   2593      0       stevel 
   2594      0       stevel 		/*
   2595      0       stevel 		 * If dotdotting at the root of a filesystem, then
   2596      0       stevel 		 * need to traverse back to the mounted-on filesystem
   2597      0       stevel 		 * and do the dotdot lookup there.
   2598      0       stevel 		 */
   2599      0       stevel 		if (cs->vp->v_flag & VROOT) {
   2600      0       stevel 
   2601      0       stevel 			/*
   2602      0       stevel 			 * If at the system root, then can
   2603      0       stevel 			 * go up no further.
   2604      0       stevel 			 */
   2605      0       stevel 			if (VN_CMP(cs->vp, rootdir))
   2606      0       stevel 				return (puterrno4(ENOENT));
   2607      0       stevel 
   2608      0       stevel 			/*
   2609      0       stevel 			 * Traverse back to the mounted-on filesystem
   2610      0       stevel 			 */
   2611      0       stevel 			cs->vp = untraverse(cs->vp);
   2612      0       stevel 
   2613      0       stevel 			/*
   2614      0       stevel 			 * Set the different_export flag so we remember
   2615      0       stevel 			 * to pick up a new exportinfo entry for
   2616      0       stevel 			 * this new filesystem.
   2617      0       stevel 			 */
   2618      0       stevel 			different_export = 1;
   2619      0       stevel 		} else {
   2620      0       stevel 
   2621      0       stevel 			/*
   2622      0       stevel 			 * If dotdotting above an export point then set
   2623      0       stevel 			 * the different_export to get new export info.
   2624      0       stevel 			 */
   2625      0       stevel 			different_export = nfs_exported(cs->exi, cs->vp);
   2626      0       stevel 		}
   2627      0       stevel 	}
   2628      0       stevel 
   2629   5331          amw 	error = VOP_LOOKUP(cs->vp, nm, &vp, NULL, 0, NULL, cs->cr,
   2630   5331          amw 	    NULL, NULL, NULL);
   2631      0       stevel 	if (error)
   2632      0       stevel 		return (puterrno4(error));
   2633      0       stevel 
   2634      0       stevel 	/*
   2635      0       stevel 	 * If the vnode is in a pseudo filesystem, check whether it is visible.
   2636      0       stevel 	 *
   2637      0       stevel 	 * XXX if the vnode is a symlink and it is not visible in
   2638      0       stevel 	 * a pseudo filesystem, return ENOENT (not following symlink).
   2639      0       stevel 	 * V4 client can not mount such symlink. This is a regression
   2640      0       stevel 	 * from V2/V3.
   2641      0       stevel 	 *
   2642      0       stevel 	 * In the same exported filesystem, if the security flavor used
   2643      0       stevel 	 * is not an explicitly shared flavor, limit the view to the visible
   2644      0       stevel 	 * list entries only. This is not a WRONGSEC case because it's already
   2645      0       stevel 	 * checked via PUTROOTFH/PUTPUBFH or PUTFH.
   2646      0       stevel 	 */
   2647      0       stevel 	if (!different_export &&
   2648      0       stevel 	    (PSEUDO(cs->exi) || ! is_exported_sec(cs->nfsflavor, cs->exi) ||
   2649      0       stevel 	    cs->access & CS_ACCESS_LIMITED)) {
   2650      0       stevel 		if (! nfs_visible(cs->exi, vp, &different_export)) {
   2651      0       stevel 			VN_RELE(vp);
   2652      0       stevel 			return (puterrno4(ENOENT));
   2653      0       stevel 		}
   2654      0       stevel 	}
   2655      0       stevel 
   2656      0       stevel 	/*
   2657      0       stevel 	 * If it's a mountpoint, then traverse it.
   2658      0       stevel 	 */
   2659      0       stevel 	if (vn_ismntpt(vp)) {
   2660      0       stevel 		pre_exi = cs->exi;	/* save pre-traversed exportinfo */
   2661      0       stevel 		pre_tvp = vp;		/* save pre-traversed vnode	*/
   2662      0       stevel 
   2663      0       stevel 		/*
   2664      0       stevel 		 * hold pre_tvp to counteract rele by traverse.  We will
   2665      0       stevel 		 * need pre_tvp below if checkexport4 fails
   2666      0       stevel 		 */
   2667      0       stevel 		VN_HOLD(pre_tvp);
   2668      0       stevel 		tvp = vp;
   2669      0       stevel 		if ((error = traverse(&tvp)) != 0) {
   2670      0       stevel 			VN_RELE(vp);
   2671      0       stevel 			VN_RELE(pre_tvp);
   2672      0       stevel 			return (puterrno4(error));
   2673      0       stevel 		}
   2674      0       stevel 		vp = tvp;
   2675      0       stevel 		different_export = 1;
   2676      0       stevel 	} else if (vp->v_vfsp != cs->vp->v_vfsp) {
   2677      0       stevel 		/*
   2678      0       stevel 		 * The vfsp comparison is to handle the case where
   2679      0       stevel 		 * a LOFS mount is shared.  lo_lookup traverses mount points,
   2680      0       stevel 		 * and NFS is unaware of local fs transistions because
   2681      0       stevel 		 * v_vfsmountedhere isn't set.  For this special LOFS case,
   2682      0       stevel 		 * the dir and the obj returned by lookup will have different
   2683      0       stevel 		 * vfs ptrs.
   2684      0       stevel 		 */
   2685      0       stevel 		different_export = 1;
   2686      0       stevel 	}
   2687      0       stevel 
   2688      0       stevel 	if (different_export) {
   2689      0       stevel 
   2690      0       stevel 		bzero(&fid, sizeof (fid));
   2691      0       stevel 		fid.fid_len = MAXFIDSZ;
   2692      0       stevel 		error = vop_fid_pseudo(vp, &fid);
   2693      0       stevel 		if (error) {
   2694      0       stevel 			VN_RELE(vp);
   2695      0       stevel 			if (pre_tvp)
   2696      0       stevel 				VN_RELE(pre_tvp);
   2697      0       stevel 			return (puterrno4(error));
   2698      0       stevel 		}
   2699      0       stevel 
   2700      0       stevel 		if (dotdot)
   2701      0       stevel 			exi = nfs_vptoexi(NULL, vp, cs->cr, &walk, NULL, TRUE);
   2702      0       stevel 		else
   2703      0       stevel 			exi = checkexport4(&vp->v_vfsp->vfs_fsid, &fid, vp);
   2704      0       stevel 
   2705      0       stevel 		if (exi == NULL) {
   2706      0       stevel 			if (pre_tvp) {
   2707      0       stevel 				/*
   2708      0       stevel 				 * If this vnode is a mounted-on vnode,
   2709      0       stevel 				 * but the mounted-on file system is not
   2710      0       stevel 				 * exported, send back the filehandle for
   2711      0       stevel 				 * the mounted-on vnode, not the root of
   2712      0       stevel 				 * the mounted-on file system.
   2713      0       stevel 				 */
   2714      0       stevel 				VN_RELE(vp);
   2715      0       stevel 				vp = pre_tvp;
   2716      0       stevel 				exi = pre_exi;
   2717      0       stevel 			} else {
   2718      0       stevel 				VN_RELE(vp);
   2719      0       stevel 				return (puterrno4(EACCES));
   2720      0       stevel 			}
   2721      0       stevel 		} else if (pre_tvp) {
   2722      0       stevel 			/* we're done with pre_tvp now. release extra hold */
   2723      0       stevel 			VN_RELE(pre_tvp);
   2724      0       stevel 		}
   2725      0       stevel 
   2726      0       stevel 		cs->exi = exi;
   2727      0       stevel 
   2728      0       stevel 		/*
   2729      0       stevel 		 * Now we do a checkauth4. The reason is that
   2730      0       stevel 		 * this client/user may not have access to the new
   2731      0       stevel 		 * exported file system, and if he does,
   2732      0       stevel 		 * the client/user may be mapped to a different uid.
   2733      0       stevel 		 *
   2734      0       stevel 		 * We start with a new cr, because the checkauth4 done
   2735      0       stevel 		 * in the PUT*FH operation over wrote the cred's uid,
   2736      0       stevel 		 * gid, etc, and we want the real thing before calling
   2737      0       stevel 		 * checkauth4()
   2738      0       stevel 		 */
   2739      0       stevel 		crfree(cs->cr);
   2740      0       stevel 		cs->cr = crdup(cs->basecr);
   2741      0       stevel 
   2742      0       stevel 		if (cs->vp)
   2743      0       stevel 			oldvp = cs->vp;
   2744      0       stevel 		cs->vp = vp;
   2745      0       stevel 		is_newvp = TRUE;
   2746      0       stevel 
   2747      0       stevel 		stat = call_checkauth4(cs, req);
   2748      0       stevel 		if (stat != NFS4_OK) {
   2749      0       stevel 			VN_RELE(cs->vp);
   2750      0       stevel 			cs->vp = oldvp;
   2751      0       stevel 			return (stat);
   2752      0       stevel 		}
   2753      0       stevel 	}
   2754      0       stevel 
   2755   1676          jpk 	/*
   2756   1676          jpk 	 * After various NFS checks, do a label check on the path
   2757   1676          jpk 	 * component. The label on this path should either be the
   2758   1676          jpk 	 * global zone's label or a zone's label. We are only
   2759   1676          jpk 	 * interested in the zone's label because exported files
   2760   1676          jpk 	 * in global zone is accessible (though read-only) to
   2761   1676          jpk 	 * clients. The exportability/visibility check is already
   2762   1676          jpk 	 * done before reaching this code.
   2763   1676          jpk 	 */
   2764   1676          jpk 	if (is_system_labeled()) {
   2765   1676          jpk 		bslabel_t *clabel;
   2766   1676          jpk 
   2767   1676          jpk 		ASSERT(req->rq_label != NULL);
   2768   1676          jpk 		clabel = req->rq_label;
   2769   1676          jpk 		DTRACE_PROBE2(tx__rfs4__log__info__oplookup__clabel, char *,
   2770   1676          jpk 		    "got client label from request(1)", struct svc_req *, req);
   2771   1676          jpk 
   2772   1676          jpk 		if (!blequal(&l_admin_low->tsl_label, clabel)) {
   2773   9871      Jarrett 			if (!do_rfs_label_check(clabel, vp, DOMINANCE_CHECK,
   2774   9871      Jarrett 			    cs->exi)) {
   2775   1676          jpk 				error = EACCES;
   2776   1676          jpk 				goto err_out;
   2777   1676          jpk 			}
   2778   1676          jpk 		} else {
   2779   1676          jpk 			/*
   2780   1676          jpk 			 * We grant access to admin_low label clients
   2781   1676          jpk 			 * only if the client is trusted, i.e. also
   2782   1676          jpk 			 * running Solaris Trusted Extension.
   2783   1676          jpk 			 */
   2784   1676          jpk 			struct sockaddr	*ca;
   2785   1676          jpk 			int		addr_type;
   2786   1676          jpk 			void		*ipaddr;
   2787   1676          jpk 			tsol_tpc_t	*tp;
   2788   1676          jpk 
   2789   1676          jpk 			ca = (struct sockaddr *)svc_getrpccaller(
   2790   1676          jpk 			    req->rq_xprt)->buf;
   2791   1676          jpk 			if (ca->sa_family == AF_INET) {
   2792   1676          jpk 				addr_type = IPV4_VERSION;
   2793   1676          jpk 				ipaddr = &((struct sockaddr_in *)ca)->sin_addr;
   2794   1676          jpk 			} else if (ca->sa_family == AF_INET6) {
   2795   1676          jpk 				addr_type = IPV6_VERSION;
   2796   1676          jpk 				ipaddr = &((struct sockaddr_in6 *)
   2797   1676          jpk 				    ca)->sin6_addr;
   2798   1676          jpk 			}
   2799   1676          jpk 			tp = find_tpc(ipaddr, addr_type, B_FALSE);
   2800   1676          jpk 			if (tp == NULL || tp->tpc_tp.tp_doi !=
   2801   1676          jpk 			    l_admin_low->tsl_doi || tp->tpc_tp.host_type !=
   2802   1676          jpk 			    SUN_CIPSO) {
   2803   4971      jarrett 				if (tp != NULL)
   2804   4971      jarrett 					TPC_RELE(tp);
   2805   1676          jpk 				error = EACCES;
   2806   1676          jpk 				goto err_out;
   2807   1676          jpk 			}
   2808   4971      jarrett 			TPC_RELE(tp);
   2809   1676          jpk 		}
   2810   1676          jpk 	}
   2811   1676          jpk 
   2812      0       stevel 	error = makefh4(&cs->fh, vp, cs->exi);
   2813      0       stevel 
   2814   1676          jpk err_out:
   2815      0       stevel 	if (error) {
   2816      0       stevel 		if (is_newvp) {
   2817      0       stevel 			VN_RELE(cs->vp);
   2818      0       stevel 			cs->vp = oldvp;
   2819      0       stevel 		} else
   2820      0       stevel 			VN_RELE(vp);
   2821      0       stevel 		return (puterrno4(error));
   2822      0       stevel 	}
   2823      0       stevel 
   2824      0       stevel 	if (!is_newvp) {
   2825      0       stevel 		if (cs->vp)
   2826      0       stevel 			VN_RELE(cs->vp);
   2827      0       stevel 		cs->vp = vp;
   2828      0       stevel 	} else if (oldvp)
   2829      0       stevel 		VN_RELE(oldvp);
   2830      0       stevel 
   2831      0       stevel 	/*
   2832      0       stevel 	 * if did lookup on attrdir and didn't lookup .., set named
   2833      0       stevel 	 * attr fh flag
   2834      0       stevel 	 */
   2835      0       stevel 	if (attrdir && ! dotdot)
   2836      0       stevel 		set_fh4_flag(&cs->fh, FH4_NAMEDATTR);
   2837      0       stevel 
   2838      0       stevel 	/* Assume false for now, open proc will set this */
   2839      0       stevel 	cs->mandlock = FALSE;
   2840      0       stevel 
   2841      0       stevel 	return (NFS4_OK);
   2842      0       stevel }
   2843      0       stevel 
   2844      0       stevel /* ARGSUSED */
   2845      0       stevel static void
   2846      0       stevel rfs4_op_lookup(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2847   9885       Robert     struct compound_state *cs)
   2848      0       stevel {
   2849      0       stevel 	LOOKUP4args *args = &argop->nfs_argop4_u.oplookup;
   2850      0       stevel 	LOOKUP4res *resp = &resop->nfs_resop4_u.oplookup;
   2851      0       stevel 	char *nm;
   2852      0       stevel 	uint_t len;
   2853   7961      Natalie 	struct sockaddr *ca;
   2854   7961      Natalie 	char *name = NULL;
   2855      0       stevel 
   2856   5647         samf 	DTRACE_NFSV4_2(op__lookup__start, struct compound_state *, cs,
   2857   5647         samf 	    LOOKUP4args *, args);
   2858   5647         samf 
   2859   5647         samf 	if (cs->vp == NULL) {
   2860   5647         samf 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2861   5647         samf 		goto out;
   2862      0       stevel 	}
   2863      0       stevel 
   2864      0       stevel 	if (cs->vp->v_type == VLNK) {
   2865      0       stevel 		*cs->statusp = resp->status = NFS4ERR_SYMLINK;
   2866   5647         samf 		goto out;
   2867      0       stevel 	}
   2868      0       stevel 
   2869      0       stevel 	if (cs->vp->v_type != VDIR) {
   2870      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   2871   5647         samf 		goto out;
   2872      0       stevel 	}
   2873      0       stevel 
   2874      0       stevel 	if (!utf8_dir_verify(&args->objname)) {
   2875      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2876   5647         samf 		goto out;
   2877      0       stevel 	}
   2878      0       stevel 
   2879      0       stevel 	nm = utf8_to_str(&args->objname, &len, NULL);
   2880      0       stevel 	if (nm == NULL) {
   2881      0       stevel 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2882   5647         samf 		goto out;
   2883      0       stevel 	}
   2884      0       stevel 
   2885      0       stevel 	if (len > MAXNAMELEN) {
   2886      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NAMETOOLONG;
   2887      0       stevel 		kmem_free(nm, len);
   2888   5647         samf 		goto out;
   2889      0       stevel 	}
   2890      0       stevel 
   2891   7961      Natalie 	/* If necessary, convert to UTF-8 for illbehaved clients */
   2892   7961      Natalie 
   2893   7961      Natalie 	ca = (struct sockaddr *)svc_getrpccaller(req->rq_xprt)->buf;
   2894   7961      Natalie 	name = nfscmd_convname(ca, cs->exi, nm, NFSCMD_CONV_INBOUND,
   2895   7961      Natalie 	    MAXPATHLEN  + 1);
   2896   7961      Natalie 
   2897   7961      Natalie 	if (name == NULL) {
   2898   7961      Natalie 		*cs->statusp = resp->status = NFS4ERR_INVAL;
   2899   7961      Natalie 		kmem_free(nm, len);
   2900   7961      Natalie 		goto out;
   2901   7961      Natalie 	}
   2902   7961      Natalie 
   2903   7961      Natalie 	*cs->statusp = resp->status = do_rfs4_op_lookup(name, len, req, cs);
   2904   7961      Natalie 
   2905   7961      Natalie 	if (name != nm)
   2906   7961      Natalie 		kmem_free(name, MAXPATHLEN + 1);
   2907      0       stevel 	kmem_free(nm, len);
   2908   5647         samf 
   2909   5647         samf out:
   2910   5647         samf 	DTRACE_NFSV4_2(op__lookup__done, struct compound_state *, cs,
   2911   5647         samf 	    LOOKUP4res *, resp);
   2912      0       stevel }
   2913      0       stevel 
   2914      0       stevel /* ARGSUSED */
   2915      0       stevel static void
   2916      0       stevel rfs4_op_lookupp(nfs_argop4 *args, nfs_resop4 *resop, struct svc_req *req,
   2917   9885       Robert     struct compound_state *cs)
   2918      0       stevel {
   2919      0       stevel 	LOOKUPP4res *resp = &resop->nfs_resop4_u.oplookupp;
   2920      0       stevel 
   2921   5647         samf 	DTRACE_NFSV4_1(op__lookupp__start, struct compound_state *, cs);
   2922   5647         samf 
   2923   5647         samf 	if (cs->vp == NULL) {
   2924   5647         samf 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2925   5647         samf 		goto out;
   2926      0       stevel 	}
   2927      0       stevel 
   2928      0       stevel 	if (cs->vp->v_type != VDIR) {
   2929      0       stevel 		*cs->statusp = resp->status = NFS4ERR_NOTDIR;
   2930   5647         samf 		goto out;
   2931      0       stevel 	}
   2932      0       stevel 
   2933      0       stevel 	*cs->statusp = resp->status = do_rfs4_op_lookup("..", 3, req, cs);
   2934      0       stevel 
   2935      0       stevel 	/*
   2936      0       stevel 	 * From NFSV4 Specification, LOOKUPP should not check for
   2937      0       stevel 	 * NFS4ERR_WRONGSEC. Retrun NFS4_OK instead.
   2938      0       stevel 	 */
   2939      0       stevel 	if (resp->status == NFS4ERR_WRONGSEC) {
   2940      0       stevel 		*cs->statusp = resp->status = NFS4_OK;
   2941      0       stevel 	}
   2942   5647         samf 
   2943   5647         samf out:
   2944   5647         samf 	DTRACE_NFSV4_2(op__lookupp__done, struct compound_state *, cs,
   2945   5647         samf 	    LOOKUPP4res *, resp);
   2946      0       stevel }
   2947      0       stevel 
   2948      0       stevel 
   2949      0       stevel /*ARGSUSED2*/
   2950      0       stevel static void
   2951      0       stevel rfs4_op_openattr(nfs_argop4 *argop, nfs_resop4 *resop, struct svc_req *req,
   2952   9885       Robert     struct compound_state *cs)
   2953      0       stevel {
   2954      0       stevel 	OPENATTR4args	*args = &argop->nfs_argop4_u.opopenattr;
   2955      0       stevel 	OPENATTR4res	*resp = &resop->nfs_resop4_u.opopenattr;
   2956      0       stevel 	vnode_t		*avp = NULL;
   2957      0       stevel 	int		lookup_flags = LOOKUP_XATTR, error;
   2958      0       stevel 	int		exp_ro = 0;
   2959      0       stevel 
   2960   5647         samf 	DTRACE_NFSV4_2(op__openattr__start, struct compound_state *, cs,
   2961   5647         samf 	    OPENATTR4args *, args);
   2962   5647         samf 
   2963   5647         samf 	if (cs->vp == NULL) {
   2964   5647         samf 		*cs->statusp = resp->status = NFS4ERR_NOFILEHANDLE;
   2965   5647         samf 		goto out;
   2966      0       stevel 	}
   2967      0       stevel 
   2968   5331          amw 	if ((cs->vp->v_vfsp->vfs_flag & VFS_XATTR) == 0 &&
   2969   7757       Janice 	    !vfs_has_feature(cs->vp->v_vfsp, VFSFT_SYSATTR_VIEWS)) {
   2970   5647         samf 		*cs->statusp = resp->status = puterrno4(ENOTSUP);
   2971   5647         samf 		goto out;
   2972      0       stevel 	}
   2973      0       stevel 
   2974   7067        marks 	/*
   2975   7067        marks 	 * If file system supports passing ACE mask to VOP_ACCESS then
   2976   7067        marks 	 * check for ACE_READ_NAMED_ATTRS, otherwise do legacy checks
   2977   7067        marks 	 */
   2978   7067        marks 
   2979   7067        marks 	if (vfs_has_feature(cs->vp->v_vfsp, VFSFT_ACEMASKONACCESS))
   2980   7067        marks 		error = VOP_ACCESS(cs->vp, ACE_READ_NAMED_ATTRS,
   2981   7067        marks 		    V_ACE_MASK, cs->cr, NULL);
   2982   7067        marks 	else
   2983   7067        marks 		error = ((VOP_ACCESS(cs->vp, VREAD, 0, cs->cr, NULL) != 0) &&
   2984   7067        marks 		    (VOP_ACCESS(cs->