xref: /onnv-gate/usr/src/uts/common/fs/nfs/nfs_acl_srv.c (revision 11323:897f105d8ba6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51610Sthurlow  * Common Development and Distribution License (the "License").
61610Sthurlow  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*11323SVallish.Vaidyeshwara@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/param.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/systm.h>
290Sstevel@tonic-gate #include <sys/cred.h>
300Sstevel@tonic-gate #include <sys/proc.h>
310Sstevel@tonic-gate #include <sys/user.h>
320Sstevel@tonic-gate #include <sys/buf.h>
330Sstevel@tonic-gate #include <sys/vfs.h>
340Sstevel@tonic-gate #include <sys/vnode.h>
350Sstevel@tonic-gate #include <sys/pathname.h>
360Sstevel@tonic-gate #include <sys/uio.h>
370Sstevel@tonic-gate #include <sys/file.h>
380Sstevel@tonic-gate #include <sys/stat.h>
390Sstevel@tonic-gate #include <sys/errno.h>
400Sstevel@tonic-gate #include <sys/socket.h>
410Sstevel@tonic-gate #include <sys/sysmacros.h>
420Sstevel@tonic-gate #include <sys/siginfo.h>
430Sstevel@tonic-gate #include <sys/tiuser.h>
440Sstevel@tonic-gate #include <sys/statvfs.h>
450Sstevel@tonic-gate #include <sys/t_kuser.h>
460Sstevel@tonic-gate #include <sys/kmem.h>
470Sstevel@tonic-gate #include <sys/kstat.h>
480Sstevel@tonic-gate #include <sys/acl.h>
490Sstevel@tonic-gate #include <sys/dirent.h>
500Sstevel@tonic-gate #include <sys/cmn_err.h>
510Sstevel@tonic-gate #include <sys/debug.h>
520Sstevel@tonic-gate #include <sys/unistd.h>
530Sstevel@tonic-gate #include <sys/vtrace.h>
540Sstevel@tonic-gate #include <sys/mode.h>
550Sstevel@tonic-gate 
560Sstevel@tonic-gate #include <rpc/types.h>
570Sstevel@tonic-gate #include <rpc/auth.h>
580Sstevel@tonic-gate #include <rpc/svc.h>
590Sstevel@tonic-gate #include <rpc/xdr.h>
600Sstevel@tonic-gate 
610Sstevel@tonic-gate #include <nfs/nfs.h>
620Sstevel@tonic-gate #include <nfs/export.h>
630Sstevel@tonic-gate #include <nfs/nfssys.h>
640Sstevel@tonic-gate #include <nfs/nfs_clnt.h>
650Sstevel@tonic-gate #include <nfs/nfs_acl.h>
660Sstevel@tonic-gate 
67789Sahrens #include <fs/fs_subr.h>
68789Sahrens 
690Sstevel@tonic-gate /*
700Sstevel@tonic-gate  * These are the interface routines for the server side of the
710Sstevel@tonic-gate  * NFS ACL server.  See the NFS ACL protocol specification
720Sstevel@tonic-gate  * for a description of this interface.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate 
750Sstevel@tonic-gate /* ARGSUSED */
760Sstevel@tonic-gate void
acl2_getacl(GETACL2args * args,GETACL2res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)770Sstevel@tonic-gate acl2_getacl(GETACL2args *args, GETACL2res *resp, struct exportinfo *exi,
780Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
790Sstevel@tonic-gate {
800Sstevel@tonic-gate 	int error;
810Sstevel@tonic-gate 	vnode_t *vp;
820Sstevel@tonic-gate 	vattr_t va;
830Sstevel@tonic-gate 
840Sstevel@tonic-gate 	vp = nfs_fhtovp(&args->fh, exi);
850Sstevel@tonic-gate 	if (vp == NULL) {
860Sstevel@tonic-gate 		resp->status = NFSERR_STALE;
870Sstevel@tonic-gate 		return;
880Sstevel@tonic-gate 	}
890Sstevel@tonic-gate 
900Sstevel@tonic-gate 	bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl));
910Sstevel@tonic-gate 
920Sstevel@tonic-gate 	resp->resok.acl.vsa_mask = args->mask;
930Sstevel@tonic-gate 
945331Samw 	error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL);
950Sstevel@tonic-gate 
96*11323SVallish.Vaidyeshwara@Sun.COM 	if ((error == ENOSYS) && !(exi->exi_export.ex_flags & EX_NOACLFAB)) {
97789Sahrens 		/*
98789Sahrens 		 * If the underlying file system doesn't support
99789Sahrens 		 * aclent_t type acls, fabricate an acl.  This is
100789Sahrens 		 * required in order to to support existing clients
101789Sahrens 		 * that require the call to VOP_GETSECATTR to
102789Sahrens 		 * succeed while making the assumption that all
103789Sahrens 		 * file systems support aclent_t type acls.  This
104789Sahrens 		 * causes problems for servers exporting ZFS file
105789Sahrens 		 * systems because ZFS supports ace_t type acls,
106789Sahrens 		 * and fails (with ENOSYS) when asked for aclent_t
107789Sahrens 		 * type acls.
108789Sahrens 		 *
109789Sahrens 		 * Note: if the fs_fab_acl() fails, we have other problems.
110789Sahrens 		 * This error should be returned to the caller.
111789Sahrens 		 */
1125331Samw 		error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL);
113789Sahrens 	}
114789Sahrens 
1150Sstevel@tonic-gate 	if (error) {
1160Sstevel@tonic-gate 		VN_RELE(vp);
1170Sstevel@tonic-gate 		resp->status = puterrno(error);
1180Sstevel@tonic-gate 		return;
1190Sstevel@tonic-gate 	}
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate 	va.va_mask = AT_ALL;
1220Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
1230Sstevel@tonic-gate 
1240Sstevel@tonic-gate 	VN_RELE(vp);
1250Sstevel@tonic-gate 
1260Sstevel@tonic-gate 	/* check for overflowed values */
1270Sstevel@tonic-gate 	if (!error) {
1280Sstevel@tonic-gate 		error = vattr_to_nattr(&va, &resp->resok.attr);
1290Sstevel@tonic-gate 	}
1300Sstevel@tonic-gate 	if (error) {
1310Sstevel@tonic-gate 		resp->status = puterrno(error);
1320Sstevel@tonic-gate 		if (resp->resok.acl.vsa_aclcnt > 0 &&
1330Sstevel@tonic-gate 		    resp->resok.acl.vsa_aclentp != NULL) {
1340Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_aclentp,
1350Sstevel@tonic-gate 			    resp->resok.acl.vsa_aclcnt * sizeof (aclent_t));
1360Sstevel@tonic-gate 		}
1370Sstevel@tonic-gate 		if (resp->resok.acl.vsa_dfaclcnt > 0 &&
1380Sstevel@tonic-gate 		    resp->resok.acl.vsa_dfaclentp != NULL) {
1390Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp,
1400Sstevel@tonic-gate 			    resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t));
1410Sstevel@tonic-gate 		}
1420Sstevel@tonic-gate 		return;
1430Sstevel@tonic-gate 	}
1440Sstevel@tonic-gate 
1450Sstevel@tonic-gate 	resp->status = NFS_OK;
1460Sstevel@tonic-gate 	if (!(args->mask & NA_ACL)) {
1470Sstevel@tonic-gate 		if (resp->resok.acl.vsa_aclcnt > 0 &&
1480Sstevel@tonic-gate 		    resp->resok.acl.vsa_aclentp != NULL) {
1490Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_aclentp,
1500Sstevel@tonic-gate 			    resp->resok.acl.vsa_aclcnt * sizeof (aclent_t));
1510Sstevel@tonic-gate 		}
1520Sstevel@tonic-gate 		resp->resok.acl.vsa_aclentp = NULL;
1530Sstevel@tonic-gate 	}
1540Sstevel@tonic-gate 	if (!(args->mask & NA_DFACL)) {
1550Sstevel@tonic-gate 		if (resp->resok.acl.vsa_dfaclcnt > 0 &&
1560Sstevel@tonic-gate 		    resp->resok.acl.vsa_dfaclentp != NULL) {
1570Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp,
1580Sstevel@tonic-gate 			    resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t));
1590Sstevel@tonic-gate 		}
1600Sstevel@tonic-gate 		resp->resok.acl.vsa_dfaclentp = NULL;
1610Sstevel@tonic-gate 	}
1620Sstevel@tonic-gate }
1630Sstevel@tonic-gate 
1641610Sthurlow void *
acl2_getacl_getfh(GETACL2args * args)1650Sstevel@tonic-gate acl2_getacl_getfh(GETACL2args *args)
1660Sstevel@tonic-gate {
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 	return (&args->fh);
1690Sstevel@tonic-gate }
1700Sstevel@tonic-gate 
1710Sstevel@tonic-gate void
acl2_getacl_free(GETACL2res * resp)1720Sstevel@tonic-gate acl2_getacl_free(GETACL2res *resp)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if (resp->status == NFS_OK) {
1760Sstevel@tonic-gate 		if (resp->resok.acl.vsa_aclcnt > 0 &&
1770Sstevel@tonic-gate 		    resp->resok.acl.vsa_aclentp != NULL) {
1780Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_aclentp,
1790Sstevel@tonic-gate 			    resp->resok.acl.vsa_aclcnt * sizeof (aclent_t));
1800Sstevel@tonic-gate 		}
1810Sstevel@tonic-gate 		if (resp->resok.acl.vsa_dfaclcnt > 0 &&
1820Sstevel@tonic-gate 		    resp->resok.acl.vsa_dfaclentp != NULL) {
1830Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp,
1840Sstevel@tonic-gate 			    resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t));
1850Sstevel@tonic-gate 		}
1860Sstevel@tonic-gate 	}
1870Sstevel@tonic-gate }
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /* ARGSUSED */
1900Sstevel@tonic-gate void
acl2_setacl(SETACL2args * args,SETACL2res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)1910Sstevel@tonic-gate acl2_setacl(SETACL2args *args, SETACL2res *resp, struct exportinfo *exi,
1920Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
1930Sstevel@tonic-gate {
1940Sstevel@tonic-gate 	int error;
1950Sstevel@tonic-gate 	vnode_t *vp;
1960Sstevel@tonic-gate 	vattr_t va;
1970Sstevel@tonic-gate 
1980Sstevel@tonic-gate 	vp = nfs_fhtovp(&args->fh, exi);
1990Sstevel@tonic-gate 	if (vp == NULL) {
2000Sstevel@tonic-gate 		resp->status = NFSERR_STALE;
2010Sstevel@tonic-gate 		return;
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	if (rdonly(exi, req) || vn_is_readonly(vp)) {
2050Sstevel@tonic-gate 		VN_RELE(vp);
2060Sstevel@tonic-gate 		resp->status = NFSERR_ROFS;
2070Sstevel@tonic-gate 		return;
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
2115331Samw 	error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
2120Sstevel@tonic-gate 	if (error) {
2130Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
2140Sstevel@tonic-gate 		VN_RELE(vp);
2150Sstevel@tonic-gate 		resp->status = puterrno(error);
2160Sstevel@tonic-gate 		return;
2170Sstevel@tonic-gate 	}
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2200Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
2230Sstevel@tonic-gate 	VN_RELE(vp);
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate 	/* check for overflowed values */
2260Sstevel@tonic-gate 	if (!error) {
2270Sstevel@tonic-gate 		error = vattr_to_nattr(&va, &resp->resok.attr);
2280Sstevel@tonic-gate 	}
2290Sstevel@tonic-gate 	if (error) {
2300Sstevel@tonic-gate 		resp->status = puterrno(error);
2310Sstevel@tonic-gate 		return;
2320Sstevel@tonic-gate 	}
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate 	resp->status = NFS_OK;
2350Sstevel@tonic-gate }
2360Sstevel@tonic-gate 
2371610Sthurlow void *
acl2_setacl_getfh(SETACL2args * args)2380Sstevel@tonic-gate acl2_setacl_getfh(SETACL2args *args)
2390Sstevel@tonic-gate {
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate 	return (&args->fh);
2420Sstevel@tonic-gate }
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate /* ARGSUSED */
2450Sstevel@tonic-gate void
acl2_getattr(GETATTR2args * args,GETATTR2res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)2460Sstevel@tonic-gate acl2_getattr(GETATTR2args *args, GETATTR2res *resp, struct exportinfo *exi,
2470Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
2480Sstevel@tonic-gate {
2490Sstevel@tonic-gate 	int error;
2500Sstevel@tonic-gate 	vnode_t *vp;
2510Sstevel@tonic-gate 	vattr_t va;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate 	vp = nfs_fhtovp(&args->fh, exi);
2540Sstevel@tonic-gate 	if (vp == NULL) {
2550Sstevel@tonic-gate 		resp->status = NFSERR_STALE;
2560Sstevel@tonic-gate 		return;
2570Sstevel@tonic-gate 	}
2580Sstevel@tonic-gate 
2590Sstevel@tonic-gate 	va.va_mask = AT_ALL;
2600Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate 	VN_RELE(vp);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 	/* check for overflowed values */
2650Sstevel@tonic-gate 	if (!error) {
2660Sstevel@tonic-gate 		error = vattr_to_nattr(&va, &resp->resok.attr);
2670Sstevel@tonic-gate 	}
2680Sstevel@tonic-gate 	if (error) {
2690Sstevel@tonic-gate 		resp->status = puterrno(error);
2700Sstevel@tonic-gate 		return;
2710Sstevel@tonic-gate 	}
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	resp->status = NFS_OK;
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2761610Sthurlow void *
acl2_getattr_getfh(GETATTR2args * args)2770Sstevel@tonic-gate acl2_getattr_getfh(GETATTR2args *args)
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	return (&args->fh);
2810Sstevel@tonic-gate }
2820Sstevel@tonic-gate 
2830Sstevel@tonic-gate /* ARGSUSED */
2840Sstevel@tonic-gate void
acl2_access(ACCESS2args * args,ACCESS2res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)2850Sstevel@tonic-gate acl2_access(ACCESS2args *args, ACCESS2res *resp, struct exportinfo *exi,
2860Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
2870Sstevel@tonic-gate {
2880Sstevel@tonic-gate 	int error;
2890Sstevel@tonic-gate 	vnode_t *vp;
2900Sstevel@tonic-gate 	vattr_t va;
2910Sstevel@tonic-gate 	int checkwriteperm;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 	vp = nfs_fhtovp(&args->fh, exi);
2940Sstevel@tonic-gate 	if (vp == NULL) {
2950Sstevel@tonic-gate 		resp->status = NFSERR_STALE;
2960Sstevel@tonic-gate 		return;
2970Sstevel@tonic-gate 	}
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate 	/*
3000Sstevel@tonic-gate 	 * If the file system is exported read only, it is not appropriate
3010Sstevel@tonic-gate 	 * to check write permissions for regular files and directories.
3020Sstevel@tonic-gate 	 * Special files are interpreted by the client, so the underlying
3030Sstevel@tonic-gate 	 * permissions are sent back to the client for interpretation.
3040Sstevel@tonic-gate 	 */
3050Sstevel@tonic-gate 	if (rdonly(exi, req) && (vp->v_type == VREG || vp->v_type == VDIR))
3060Sstevel@tonic-gate 		checkwriteperm = 0;
3070Sstevel@tonic-gate 	else
3080Sstevel@tonic-gate 		checkwriteperm = 1;
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/*
3110Sstevel@tonic-gate 	 * We need the mode so that we can correctly determine access
3120Sstevel@tonic-gate 	 * permissions relative to a mandatory lock file.  Access to
3130Sstevel@tonic-gate 	 * mandatory lock files is denied on the server, so it might
3140Sstevel@tonic-gate 	 * as well be reflected to the server during the open.
3150Sstevel@tonic-gate 	 */
3160Sstevel@tonic-gate 	va.va_mask = AT_MODE;
3175331Samw 	error = VOP_GETATTR(vp, &va, 0, cr, NULL);
3180Sstevel@tonic-gate 	if (error) {
3190Sstevel@tonic-gate 		VN_RELE(vp);
3200Sstevel@tonic-gate 		resp->status = puterrno(error);
3210Sstevel@tonic-gate 		return;
3220Sstevel@tonic-gate 	}
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	resp->resok.access = 0;
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	if (args->access & ACCESS2_READ) {
3275331Samw 		error = VOP_ACCESS(vp, VREAD, 0, cr, NULL);
3280Sstevel@tonic-gate 		if (!error && !MANDLOCK(vp, va.va_mode))
3290Sstevel@tonic-gate 			resp->resok.access |= ACCESS2_READ;
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 	if ((args->access & ACCESS2_LOOKUP) && vp->v_type == VDIR) {
3325331Samw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
3330Sstevel@tonic-gate 		if (!error)
3340Sstevel@tonic-gate 			resp->resok.access |= ACCESS2_LOOKUP;
3350Sstevel@tonic-gate 	}
3360Sstevel@tonic-gate 	if (checkwriteperm &&
3370Sstevel@tonic-gate 	    (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND))) {
3385331Samw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
3390Sstevel@tonic-gate 		if (!error && !MANDLOCK(vp, va.va_mode))
3400Sstevel@tonic-gate 			resp->resok.access |=
3410Sstevel@tonic-gate 			    (args->access & (ACCESS2_MODIFY|ACCESS2_EXTEND));
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 	if (checkwriteperm &&
3440Sstevel@tonic-gate 	    (args->access & ACCESS2_DELETE) && (vp->v_type == VDIR)) {
3455331Samw 		error = VOP_ACCESS(vp, VWRITE, 0, cr, NULL);
3460Sstevel@tonic-gate 		if (!error)
3470Sstevel@tonic-gate 			resp->resok.access |= ACCESS2_DELETE;
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate 	if (args->access & ACCESS2_EXECUTE) {
3505331Samw 		error = VOP_ACCESS(vp, VEXEC, 0, cr, NULL);
3510Sstevel@tonic-gate 		if (!error && !MANDLOCK(vp, va.va_mode))
3520Sstevel@tonic-gate 			resp->resok.access |= ACCESS2_EXECUTE;
3530Sstevel@tonic-gate 	}
3540Sstevel@tonic-gate 
3550Sstevel@tonic-gate 	va.va_mask = AT_ALL;
3560Sstevel@tonic-gate 	error = rfs4_delegated_getattr(vp, &va, 0, cr);
3570Sstevel@tonic-gate 
3580Sstevel@tonic-gate 	VN_RELE(vp);
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	/* check for overflowed values */
3610Sstevel@tonic-gate 	if (!error) {
3620Sstevel@tonic-gate 		error = vattr_to_nattr(&va, &resp->resok.attr);
3630Sstevel@tonic-gate 	}
3640Sstevel@tonic-gate 	if (error) {
3650Sstevel@tonic-gate 		resp->status = puterrno(error);
3660Sstevel@tonic-gate 		return;
3670Sstevel@tonic-gate 	}
3680Sstevel@tonic-gate 
3690Sstevel@tonic-gate 	resp->status = NFS_OK;
3700Sstevel@tonic-gate }
3710Sstevel@tonic-gate 
3721610Sthurlow void *
acl2_access_getfh(ACCESS2args * args)3730Sstevel@tonic-gate acl2_access_getfh(ACCESS2args *args)
3740Sstevel@tonic-gate {
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	return (&args->fh);
3770Sstevel@tonic-gate }
3780Sstevel@tonic-gate 
3790Sstevel@tonic-gate /* ARGSUSED */
3800Sstevel@tonic-gate void
acl2_getxattrdir(GETXATTRDIR2args * args,GETXATTRDIR2res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)3810Sstevel@tonic-gate acl2_getxattrdir(GETXATTRDIR2args *args, GETXATTRDIR2res *resp,
3820Sstevel@tonic-gate 	struct exportinfo *exi, struct svc_req *req, cred_t *cr)
3830Sstevel@tonic-gate {
3840Sstevel@tonic-gate 	int error;
3850Sstevel@tonic-gate 	int flags;
3860Sstevel@tonic-gate 	vnode_t *vp, *avp;
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	vp = nfs_fhtovp(&args->fh, exi);
3890Sstevel@tonic-gate 	if (vp == NULL) {
3900Sstevel@tonic-gate 		resp->status = NFSERR_STALE;
3910Sstevel@tonic-gate 		return;
3920Sstevel@tonic-gate 	}
3930Sstevel@tonic-gate 
3940Sstevel@tonic-gate 	flags = LOOKUP_XATTR;
3950Sstevel@tonic-gate 	if (args->create)
3960Sstevel@tonic-gate 		flags |= CREATE_XATTR_DIR;
3970Sstevel@tonic-gate 	else {
3980Sstevel@tonic-gate 		ulong_t val = 0;
3997067Smarks 		error = VOP_PATHCONF(vp, _PC_SATTR_EXISTS, &val, cr, NULL);
4000Sstevel@tonic-gate 		if (!error && val == 0) {
4017067Smarks 			error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS,
4027067Smarks 			    &val, cr, NULL);
4037067Smarks 			if (!error && val == 0) {
4047067Smarks 				VN_RELE(vp);
4057067Smarks 				resp->status = NFSERR_NOENT;
4067067Smarks 				return;
4077067Smarks 			}
4080Sstevel@tonic-gate 		}
4090Sstevel@tonic-gate 	}
4100Sstevel@tonic-gate 
4115331Samw 	error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr,
4125331Samw 	    NULL, NULL, NULL);
4130Sstevel@tonic-gate 	if (!error && avp == vp) {	/* lookup of "" on old FS? */
4140Sstevel@tonic-gate 		error = EINVAL;
4150Sstevel@tonic-gate 		VN_RELE(avp);
4160Sstevel@tonic-gate 	}
4170Sstevel@tonic-gate 	if (!error) {
4180Sstevel@tonic-gate 		struct vattr va;
4190Sstevel@tonic-gate 		va.va_mask = AT_ALL;
4200Sstevel@tonic-gate 		error = rfs4_delegated_getattr(avp, &va, 0, cr);
4210Sstevel@tonic-gate 		if (!error) {
4220Sstevel@tonic-gate 			error = vattr_to_nattr(&va, &resp->resok.attr);
4230Sstevel@tonic-gate 			if (!error)
4240Sstevel@tonic-gate 				error = makefh(&resp->resok.fh, avp, exi);
4250Sstevel@tonic-gate 		}
4260Sstevel@tonic-gate 		VN_RELE(avp);
4270Sstevel@tonic-gate 	}
4280Sstevel@tonic-gate 
4290Sstevel@tonic-gate 	VN_RELE(vp);
4300Sstevel@tonic-gate 
4310Sstevel@tonic-gate 	if (error) {
4320Sstevel@tonic-gate 		resp->status = puterrno(error);
4330Sstevel@tonic-gate 		return;
4340Sstevel@tonic-gate 	}
4350Sstevel@tonic-gate 	resp->status = NFS_OK;
4360Sstevel@tonic-gate }
4370Sstevel@tonic-gate 
4381610Sthurlow void *
acl2_getxattrdir_getfh(GETXATTRDIR2args * args)4390Sstevel@tonic-gate acl2_getxattrdir_getfh(GETXATTRDIR2args *args)
4400Sstevel@tonic-gate {
4410Sstevel@tonic-gate 	return (&args->fh);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate /* ARGSUSED */
4450Sstevel@tonic-gate void
acl3_getacl(GETACL3args * args,GETACL3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)4460Sstevel@tonic-gate acl3_getacl(GETACL3args *args, GETACL3res *resp, struct exportinfo *exi,
4470Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
4480Sstevel@tonic-gate {
4490Sstevel@tonic-gate 	int error;
4500Sstevel@tonic-gate 	vnode_t *vp;
4510Sstevel@tonic-gate 	vattr_t *vap;
4520Sstevel@tonic-gate 	vattr_t va;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	vap = NULL;
4550Sstevel@tonic-gate 
4560Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fh, exi);
4570Sstevel@tonic-gate 	if (vp == NULL) {
4580Sstevel@tonic-gate 		error = ESTALE;
4590Sstevel@tonic-gate 		goto out;
4600Sstevel@tonic-gate 	}
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate #ifdef DEBUG
4630Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
4640Sstevel@tonic-gate 		va.va_mask = AT_ALL;
4650Sstevel@tonic-gate 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
4660Sstevel@tonic-gate 	} else
4670Sstevel@tonic-gate 		vap = NULL;
4680Sstevel@tonic-gate #else
4690Sstevel@tonic-gate 	va.va_mask = AT_ALL;
4700Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
4710Sstevel@tonic-gate #endif
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	bzero((caddr_t)&resp->resok.acl, sizeof (resp->resok.acl));
4740Sstevel@tonic-gate 
4750Sstevel@tonic-gate 	resp->resok.acl.vsa_mask = args->mask;
4760Sstevel@tonic-gate 
4775331Samw 	error = VOP_GETSECATTR(vp, &resp->resok.acl, 0, cr, NULL);
4780Sstevel@tonic-gate 
479*11323SVallish.Vaidyeshwara@Sun.COM 	if ((error == ENOSYS) && !(exi->exi_export.ex_flags & EX_NOACLFAB)) {
480789Sahrens 		/*
481789Sahrens 		 * If the underlying file system doesn't support
482789Sahrens 		 * aclent_t type acls, fabricate an acl.  This is
483789Sahrens 		 * required in order to to support existing clients
484789Sahrens 		 * that require the call to VOP_GETSECATTR to
485789Sahrens 		 * succeed while making the assumption that all
486789Sahrens 		 * file systems support aclent_t type acls.  This
487789Sahrens 		 * causes problems for servers exporting ZFS file
488789Sahrens 		 * systems because ZFS supports ace_t type acls,
489789Sahrens 		 * and fails (with ENOSYS) when asked for aclent_t
490789Sahrens 		 * type acls.
491789Sahrens 		 *
492789Sahrens 		 * Note: if the fs_fab_acl() fails, we have other problems.
493789Sahrens 		 * This error should be returned to the caller.
494789Sahrens 		 */
4955331Samw 		error = fs_fab_acl(vp, &resp->resok.acl, 0, cr, NULL);
496789Sahrens 	}
497789Sahrens 
4980Sstevel@tonic-gate 	if (error)
4990Sstevel@tonic-gate 		goto out;
5000Sstevel@tonic-gate 
5010Sstevel@tonic-gate #ifdef DEBUG
5020Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
5030Sstevel@tonic-gate 		va.va_mask = AT_ALL;
5040Sstevel@tonic-gate 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5050Sstevel@tonic-gate 	} else
5060Sstevel@tonic-gate 		vap = NULL;
5070Sstevel@tonic-gate #else
5080Sstevel@tonic-gate 	va.va_mask = AT_ALL;
5090Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5100Sstevel@tonic-gate #endif
5110Sstevel@tonic-gate 
5120Sstevel@tonic-gate 	VN_RELE(vp);
5130Sstevel@tonic-gate 
5140Sstevel@tonic-gate 	resp->status = NFS3_OK;
5150Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.attr);
5160Sstevel@tonic-gate 	if (!(args->mask & NA_ACL)) {
5170Sstevel@tonic-gate 		if (resp->resok.acl.vsa_aclcnt > 0 &&
5180Sstevel@tonic-gate 		    resp->resok.acl.vsa_aclentp != NULL) {
5190Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_aclentp,
5200Sstevel@tonic-gate 			    resp->resok.acl.vsa_aclcnt * sizeof (aclent_t));
5210Sstevel@tonic-gate 		}
5220Sstevel@tonic-gate 		resp->resok.acl.vsa_aclentp = NULL;
5230Sstevel@tonic-gate 	}
5240Sstevel@tonic-gate 	if (!(args->mask & NA_DFACL)) {
5250Sstevel@tonic-gate 		if (resp->resok.acl.vsa_dfaclcnt > 0 &&
5260Sstevel@tonic-gate 		    resp->resok.acl.vsa_dfaclentp != NULL) {
5270Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp,
5280Sstevel@tonic-gate 			    resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t));
5290Sstevel@tonic-gate 		}
5300Sstevel@tonic-gate 		resp->resok.acl.vsa_dfaclentp = NULL;
5310Sstevel@tonic-gate 	}
5320Sstevel@tonic-gate 	return;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate out:
5350Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
5360Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
5370Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
5380Sstevel@tonic-gate 	} else
5390Sstevel@tonic-gate 		resp->status = puterrno3(error);
5400Sstevel@tonic-gate out1:
5410Sstevel@tonic-gate 	if (vp != NULL)
5420Sstevel@tonic-gate 		VN_RELE(vp);
5430Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.attr);
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate 
5461610Sthurlow void *
acl3_getacl_getfh(GETACL3args * args)5470Sstevel@tonic-gate acl3_getacl_getfh(GETACL3args *args)
5480Sstevel@tonic-gate {
5490Sstevel@tonic-gate 
5501610Sthurlow 	return (&args->fh);
5510Sstevel@tonic-gate }
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate void
acl3_getacl_free(GETACL3res * resp)5540Sstevel@tonic-gate acl3_getacl_free(GETACL3res *resp)
5550Sstevel@tonic-gate {
5560Sstevel@tonic-gate 
5570Sstevel@tonic-gate 	if (resp->status == NFS3_OK) {
5580Sstevel@tonic-gate 		if (resp->resok.acl.vsa_aclcnt > 0 &&
5590Sstevel@tonic-gate 		    resp->resok.acl.vsa_aclentp != NULL) {
5600Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_aclentp,
5610Sstevel@tonic-gate 			    resp->resok.acl.vsa_aclcnt * sizeof (aclent_t));
5620Sstevel@tonic-gate 		}
5630Sstevel@tonic-gate 		if (resp->resok.acl.vsa_dfaclcnt > 0 &&
5640Sstevel@tonic-gate 		    resp->resok.acl.vsa_dfaclentp != NULL) {
5650Sstevel@tonic-gate 			kmem_free((caddr_t)resp->resok.acl.vsa_dfaclentp,
5660Sstevel@tonic-gate 			    resp->resok.acl.vsa_dfaclcnt * sizeof (aclent_t));
5670Sstevel@tonic-gate 		}
5680Sstevel@tonic-gate 	}
5690Sstevel@tonic-gate }
5700Sstevel@tonic-gate 
5710Sstevel@tonic-gate /* ARGSUSED */
5720Sstevel@tonic-gate void
acl3_setacl(SETACL3args * args,SETACL3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)5730Sstevel@tonic-gate acl3_setacl(SETACL3args *args, SETACL3res *resp, struct exportinfo *exi,
5740Sstevel@tonic-gate 	struct svc_req *req, cred_t *cr)
5750Sstevel@tonic-gate {
5760Sstevel@tonic-gate 	int error;
5770Sstevel@tonic-gate 	vnode_t *vp;
5780Sstevel@tonic-gate 	vattr_t *vap;
5790Sstevel@tonic-gate 	vattr_t va;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	vap = NULL;
5820Sstevel@tonic-gate 
5830Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fh, exi);
5840Sstevel@tonic-gate 	if (vp == NULL) {
5850Sstevel@tonic-gate 		error = ESTALE;
5860Sstevel@tonic-gate 		goto out1;
5870Sstevel@tonic-gate 	}
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	(void) VOP_RWLOCK(vp, V_WRITELOCK_TRUE, NULL);
5900Sstevel@tonic-gate 
5910Sstevel@tonic-gate #ifdef DEBUG
5920Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
5930Sstevel@tonic-gate 		va.va_mask = AT_ALL;
5940Sstevel@tonic-gate 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
5950Sstevel@tonic-gate 	} else
5960Sstevel@tonic-gate 		vap = NULL;
5970Sstevel@tonic-gate #else
5980Sstevel@tonic-gate 	va.va_mask = AT_ALL;
5990Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
6000Sstevel@tonic-gate #endif
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 	if (rdonly(exi, req) || vn_is_readonly(vp)) {
6030Sstevel@tonic-gate 		resp->status = NFS3ERR_ROFS;
6040Sstevel@tonic-gate 		goto out1;
6050Sstevel@tonic-gate 	}
6060Sstevel@tonic-gate 
6075331Samw 	error = VOP_SETSECATTR(vp, &args->acl, 0, cr, NULL);
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate #ifdef DEBUG
6100Sstevel@tonic-gate 	if (rfs3_do_post_op_attr) {
6110Sstevel@tonic-gate 		va.va_mask = AT_ALL;
6120Sstevel@tonic-gate 		vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
6130Sstevel@tonic-gate 	} else
6140Sstevel@tonic-gate 		vap = NULL;
6150Sstevel@tonic-gate #else
6160Sstevel@tonic-gate 	va.va_mask = AT_ALL;
6170Sstevel@tonic-gate 	vap = rfs4_delegated_getattr(vp, &va, 0, cr) ? NULL : &va;
6180Sstevel@tonic-gate #endif
6190Sstevel@tonic-gate 
6200Sstevel@tonic-gate 	if (error)
6210Sstevel@tonic-gate 		goto out;
6220Sstevel@tonic-gate 
6230Sstevel@tonic-gate 	VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
6240Sstevel@tonic-gate 	VN_RELE(vp);
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	resp->status = NFS3_OK;
6270Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resok.attr);
6280Sstevel@tonic-gate 	return;
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate out:
6310Sstevel@tonic-gate 	if (curthread->t_flag & T_WOULDBLOCK) {
6320Sstevel@tonic-gate 		curthread->t_flag &= ~T_WOULDBLOCK;
6330Sstevel@tonic-gate 		resp->status = NFS3ERR_JUKEBOX;
6340Sstevel@tonic-gate 	} else
6350Sstevel@tonic-gate 		resp->status = puterrno3(error);
6360Sstevel@tonic-gate out1:
6370Sstevel@tonic-gate 	if (vp != NULL) {
6380Sstevel@tonic-gate 		VOP_RWUNLOCK(vp, V_WRITELOCK_TRUE, NULL);
6390Sstevel@tonic-gate 		VN_RELE(vp);
6400Sstevel@tonic-gate 	}
6410Sstevel@tonic-gate 	vattr_to_post_op_attr(vap, &resp->resfail.attr);
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate 
6441610Sthurlow void *
acl3_setacl_getfh(SETACL3args * args)6450Sstevel@tonic-gate acl3_setacl_getfh(SETACL3args *args)
6460Sstevel@tonic-gate {
6470Sstevel@tonic-gate 
6481610Sthurlow 	return (&args->fh);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate /* ARGSUSED */
6520Sstevel@tonic-gate void
acl3_getxattrdir(GETXATTRDIR3args * args,GETXATTRDIR3res * resp,struct exportinfo * exi,struct svc_req * req,cred_t * cr)6530Sstevel@tonic-gate acl3_getxattrdir(GETXATTRDIR3args *args, GETXATTRDIR3res *resp,
6540Sstevel@tonic-gate 	struct exportinfo *exi, struct svc_req *req, cred_t *cr)
6550Sstevel@tonic-gate {
6560Sstevel@tonic-gate 	int error;
6570Sstevel@tonic-gate 	int flags;
6580Sstevel@tonic-gate 	vnode_t *vp, *avp;
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	vp = nfs3_fhtovp(&args->fh, exi);
6610Sstevel@tonic-gate 	if (vp == NULL) {
6620Sstevel@tonic-gate 		resp->status = NFS3ERR_STALE;
6630Sstevel@tonic-gate 		return;
6640Sstevel@tonic-gate 	}
6650Sstevel@tonic-gate 
6660Sstevel@tonic-gate 	flags = LOOKUP_XATTR;
6670Sstevel@tonic-gate 	if (args->create)
6680Sstevel@tonic-gate 		flags |= CREATE_XATTR_DIR;
6690Sstevel@tonic-gate 	else {
6700Sstevel@tonic-gate 		ulong_t val = 0;
6717067Smarks 
6727067Smarks 		error = VOP_PATHCONF(vp, _PC_SATTR_EXISTS, &val, cr, NULL);
6730Sstevel@tonic-gate 		if (!error && val == 0) {
6747067Smarks 			error = VOP_PATHCONF(vp, _PC_XATTR_EXISTS,
6757067Smarks 			    &val, cr, NULL);
6767067Smarks 			if (!error && val == 0) {
6777067Smarks 				VN_RELE(vp);
6787067Smarks 				resp->status = NFS3ERR_NOENT;
6797067Smarks 				return;
6807067Smarks 			}
6810Sstevel@tonic-gate 		}
6820Sstevel@tonic-gate 	}
6830Sstevel@tonic-gate 
6845331Samw 	error = VOP_LOOKUP(vp, "", &avp, NULL, flags, NULL, cr,
6855331Samw 	    NULL, NULL, NULL);
6860Sstevel@tonic-gate 	if (!error && avp == vp) {	/* lookup of "" on old FS? */
6870Sstevel@tonic-gate 		error = EINVAL;
6880Sstevel@tonic-gate 		VN_RELE(avp);
6890Sstevel@tonic-gate 	}
6900Sstevel@tonic-gate 	if (!error) {
6910Sstevel@tonic-gate 		struct vattr va;
6920Sstevel@tonic-gate 		va.va_mask = AT_ALL;
6930Sstevel@tonic-gate 		error = rfs4_delegated_getattr(avp, &va, 0, cr);
6940Sstevel@tonic-gate 		if (!error) {
6950Sstevel@tonic-gate 			vattr_to_post_op_attr(&va, &resp->resok.attr);
6960Sstevel@tonic-gate 			error = makefh3(&resp->resok.fh, avp, exi);
6970Sstevel@tonic-gate 		}
6980Sstevel@tonic-gate 		VN_RELE(avp);
6990Sstevel@tonic-gate 	}
7000Sstevel@tonic-gate 
7010Sstevel@tonic-gate 	VN_RELE(vp);
7020Sstevel@tonic-gate 
7030Sstevel@tonic-gate 	if (error) {
7040Sstevel@tonic-gate 		resp->status = puterrno3(error);
7050Sstevel@tonic-gate 		return;
7060Sstevel@tonic-gate 	}
7070Sstevel@tonic-gate 	resp->status = NFS3_OK;
7080Sstevel@tonic-gate }
7090Sstevel@tonic-gate 
7101610Sthurlow void *
acl3_getxattrdir_getfh(GETXATTRDIR3args * args)7110Sstevel@tonic-gate acl3_getxattrdir_getfh(GETXATTRDIR3args *args)
7120Sstevel@tonic-gate {
7131610Sthurlow 	return (&args->fh);
7140Sstevel@tonic-gate }
715