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