From nobody Mon Dec 22 01:08:47 2025 X-Original-To: dev-commits-src-main@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4dZKlh0FPpz6Lmvr for ; Mon, 22 Dec 2025 01:08:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4dZKlg425Cz3H6k for ; Mon, 22 Dec 2025 01:08:47 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1766365727; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QafS1sryQR/W3D4qHD6AH2mmaQNQNtlfMzfhMX6RorM=; b=rPDlOFL7JYi6dIjYF7ntafDMvxm8VhkmqdibAgjxRj3XGgeB+WQtZclZ4iInxz/39iCIHC Re6nmSsxwZfD2CcMIreJnbO9qP6oZDuu9pWzqzuAYeKWZhUK5WSZprUblt7kAp1fCzjzVt LiSdHzWYtOF0iSf56nZmz4bYf7yRUxvsi3HtBr6mj4Z0TMUjRxnixc44BIR5UYEWo0vfLH /Ok6HlTBEcodUGK0DDH1cxQSFLP4vujz2X0BBaMeu+8Z2nOHOHCuwEy/uYmk5sJgDrqJKM 8xnTwZY+zq68jhA4hWlychZ63+0W1HxRTGy6KtDrCbGW61R3BKEuV1E9qrfbjQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1766365727; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=QafS1sryQR/W3D4qHD6AH2mmaQNQNtlfMzfhMX6RorM=; b=tHxPOHLfK9uOYv9TCZeaS3uwpb9ZYzBjjBsMsL5ioiQhQuTBkm9h0Qe+nOspJTCDlKJW0l olnZIXhDUFe+bknoPLb9HmpyCmLiY2PgrowKqPRO+gdfLpEonbunw34RDHiswp/sIDrCU6 UATqrfE5HRoB2Cg8uvWvWuFjRnUr39GU9Ui8y9/iEDnyQAkdAp/w1HOswL349rfeAtOkEi ffPMQFTUCltzaZ3X95rin89c743Li80BiMGgnuX1xP+a76C4JLGmllwkRHqDLgGUEdGuzy d/uCOzUZcKgUgrS5iciBVFI1e0KCUQxaw+1C6mBN4SBDEZotVzABKomHt5Au9A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1766365727; a=rsa-sha256; cv=none; b=xCedZAfReeTR6VZYHb0PjsI1i6+v7oSlRUuYAjsXyRn4aO38KQfoq9s7XlFs3/qaaKvJES ZIL2hdlV7o32HAJS9icN+YNJKq2r4YxRSQGSQGSGGxqNuFUmBzrcduL4pNX1vrK8nyW6Iq Z/R/8fcL5sRjmsRTNJJ1EvBlX60knhjIYOhF5sPFNDanNiLixvQTYJRlpaL5jB901Fzwcw RirnK8Jf+9d7IQficLzR2P7Bb7Aww6Ux1WMOufMOgBXHHrweTA8YHsAdDPJRTIJUpPrZwH WtIIKX/tHcAvNklXyuKC2gWXmBvGdWy2dpTdI4nZbuy7NdLQZvjhZYjJF4pcQg== ARC-Authentication-Results: i=1; mx1.freebsd.org; none Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4dZKlg3V7sz140t for ; Mon, 22 Dec 2025 01:08:47 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 27d2d by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Mon, 22 Dec 2025 01:08:47 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Rick Macklem Subject: git: 949cff4dceff - main - nfscommon: Add some support for POSIX draft ACLs List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: rmacklem X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: 949cff4dceffdbee70fa7741c1d61cf6c5255aeb Auto-Submitted: auto-generated Date: Mon, 22 Dec 2025 01:08:47 +0000 Message-Id: <69489a1f.27d2d.62a82838@gitrepo.freebsd.org> The branch main has been updated by rmacklem: URL: https://cgit.FreeBSD.org/src/commit/?id=949cff4dceffdbee70fa7741c1d61cf6c5255aeb commit 949cff4dceffdbee70fa7741c1d61cf6c5255aeb Author: Rick Macklem AuthorDate: 2025-12-22 01:07:10 +0000 Commit: Rick Macklem CommitDate: 2025-12-22 01:07:10 +0000 nfscommon: Add some support for POSIX draft ACLs An internet draft (expected to become an RFC someday) https://datatracker.ietf.org/doc/draft-ietf-nfsv4-posix-acls describes an extension to NFSv4.2 to handle POSIX draft ACLs. This is the third of several patches that implement the above draft. There should be no semantics change for the series at this point. Fixes: a35bbd5d9f5f ("nfscommon: Add some support for POSIX draft ACLs") --- sys/fs/nfs/nfs_commonacl.c | 195 ++++++++++++++++++++++++++++++- sys/fs/nfs/nfs_commonsubs.c | 272 ++++++++++++++++++++++++++++++++++++++++---- sys/fs/nfs/nfs_var.h | 3 + 3 files changed, 445 insertions(+), 25 deletions(-) diff --git a/sys/fs/nfs/nfs_commonacl.c b/sys/fs/nfs/nfs_commonacl.c index bba1d8821a9b..2120b095823b 100644 --- a/sys/fs/nfs/nfs_commonacl.c +++ b/sys/fs/nfs/nfs_commonacl.c @@ -36,7 +36,7 @@ static int nfsrv_acemasktoperm(u_int32_t acetype, u_int32_t mask, int owner, __enum_uint8(vtype) type, acl_perm_t *permp); /* - * Handle xdr for an ace. + * Handle xdr for an NFSv4 ace. */ int nfsrv_dissectace(struct nfsrv_descript *nd, struct acl_entry *acep, @@ -181,6 +181,84 @@ nfsmout: return (error); } +static acl_tag_t nfsv4_to_posixacltag[NFSV4_POSIXACL_TAG_OTHER + 1] = + { ACL_UNDEFINED_TAG, ACL_USER_OBJ, ACL_USER, ACL_GROUP_OBJ, + ACL_GROUP, ACL_MASK, ACL_OTHER }; + +/* + * Handle xdr for a POSIX draft ace. + */ +int +nfsrv_dissectposixace(struct nfsrv_descript *nd, struct acl_entry *acep, + bool server, int *aceerrp, int *acesizep) +{ + uint32_t *tl, tag; + int len, error = 0, aceerr = 0; + u_char *name, namestr[NFSV4_SMALLSTR + 1]; + gid_t gid; + uid_t uid; + + *aceerrp = 0; + NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); + tag = fxdr_unsigned(uint32_t, *tl++); + acep->ae_perm = fxdr_unsigned(acl_perm_t, *tl++); + len = fxdr_unsigned(int, *tl); + /* + * The RFCs do not specify a limit to the length of the "who", but + * NFSV4_OPAQUELIMIT (1024) should be sufficient. + */ + if (len < 0 || len > NFSV4_OPAQUELIMIT) { + error = NFSERR_BADXDR; + goto nfsmout; + } + if (tag < NFSV4_POSIXACL_TAG_USER_OBJ || + tag > NFSV4_POSIXACL_TAG_OTHER) { + error = NFSERR_ATTRNOTSUPP; + goto nfsmout; + } + acep->ae_tag = nfsv4_to_posixacltag[tag]; + if (len > NFSV4_SMALLSTR) + name = malloc(len + 1, M_NFSSTRING, M_WAITOK); + else + name = namestr; + if (len > 0) + error = nfsrv_mtostr(nd, name, len); + if (error != 0) { + if (len > NFSV4_SMALLSTR) + free(name, M_NFSSTRING); + goto nfsmout; + } + switch (acep->ae_tag) { + case ACL_USER: + aceerr = nfsv4_strtouid(nd, name, len, &uid); + if (aceerr == 0) + acep->ae_id = uid; + break; + case ACL_GROUP: + aceerr = nfsv4_strtogid(nd, name, len, &gid); + if (aceerr == 0) + acep->ae_id = (uid_t)gid; + break; + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_MASK: + case ACL_OTHER: + break; + default: + aceerr = NFSERR_ATTRNOTSUPP; + } + if (len > NFSV4_SMALLSTR) + free(name, M_NFSSTRING); + + *aceerrp = aceerr; + if (acesizep != NULL) + *acesizep = NFSM_RNDUP(len) + (3 * NFSX_UNSIGNED); + error = 0; +nfsmout: + NFSEXITCODE(error); + return (error); +} + /* * Turn an NFSv4 ace mask into R/W/X flag bits. */ @@ -277,9 +355,11 @@ out: /* local functions */ static int nfsrv_buildace(struct nfsrv_descript *, u_char *, int, __enum_uint8(vtype), int, int, struct acl_entry *); +static int nfsrv_buildposixace(struct nfsrv_descript *, u_char *, int, + struct acl_entry *); /* - * This function builds an NFS ace. + * This function builds an NFSv4 ace. */ static int nfsrv_buildace(struct nfsrv_descript *nd, u_char *name, int namelen, @@ -399,6 +479,59 @@ nfs_aceperm(acl_perm_t ae_perm) return (acemask); } +/* + * This function builds a POSIX draft ace. + */ +static int +nfsrv_buildposixace(struct nfsrv_descript *nd, u_char *name, int namelen, + struct acl_entry *ace) +{ + uint32_t *tl; + int full_len; + + full_len = NFSM_RNDUP(namelen); + NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED + full_len); + + /* + * Fill in the ace tag. + */ + switch (ace->ae_tag) { + case ACL_USER_OBJ: + *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_USER_OBJ); + break; + case ACL_USER: + *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_USER); + break; + case ACL_GROUP_OBJ: + *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_GROUP_OBJ); + break; + case ACL_GROUP: + *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_GROUP); + break; + case ACL_MASK: + *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_MASK); + break; + case ACL_OTHER: + *tl++ = txdr_unsigned(NFSV4_POSIXACL_TAG_OTHER); + break; + default: + printf("nfsrv_buildposixace: bad ae_tag 0x%x\n", ace->ae_tag); + *tl++ = txdr_unsigned(0); + } + + /* + * Fill in the permission bits. + */ + *tl++ = txdr_unsigned(ace->ae_perm); + *tl++ = txdr_unsigned(namelen); + if (namelen > 0) { + if (full_len - namelen) + *(tl + (namelen / NFSX_UNSIGNED)) = 0x0; + memcpy(tl, name, namelen); + } + return (full_len + 3 * NFSX_UNSIGNED); +} + /* * Build an NFSv4 ACL. */ @@ -461,6 +594,64 @@ nfsrv_buildacl(struct nfsrv_descript *nd, NFSACL_T *aclp, __enum_uint8(vtype) ty return (retlen); } +/* + * Build a POSIX draft ACL. + */ +int +nfsrv_buildposixacl(struct nfsrv_descript *nd, NFSACL_T *aclp, + acl_type_t acltype) +{ + int i, entrycnt = 0, retlen; + uint32_t *entrycntp; + unsigned int cnt; + int namelen; + u_char *name, namestr[NFSV4_SMALLSTR]; + bool malloced; + + NFSM_BUILD(entrycntp, uint32_t *, NFSX_UNSIGNED); + retlen = NFSX_UNSIGNED; + cnt = 0; + if (aclp != NULL) + cnt = aclp->acl_cnt; + /* + * Loop through the acl entries, building each one. + */ + for (i = 0; i < cnt; i++) { + malloced = false; + switch (aclp->acl_entry[i].ae_tag) { + case ACL_USER_OBJ: + case ACL_GROUP_OBJ: + case ACL_OTHER: + case ACL_MASK: + namelen = 0; + break; + case ACL_USER: + name = namestr; + nfsv4_uidtostr(aclp->acl_entry[i].ae_id, &name, + &namelen); + if (name != namestr) + malloced = true; + break; + case ACL_GROUP: + name = namestr; + nfsv4_gidtostr((gid_t)aclp->acl_entry[i].ae_id, &name, + &namelen); + if (name != namestr) + malloced = true; + break; + default: + continue; + } + retlen += nfsrv_buildposixace(nd, name, namelen, + &aclp->acl_entry[i]); + entrycnt++; + if (malloced) + free(name, M_NFSSTRING); + } + *entrycntp = txdr_unsigned(entrycnt); + return (retlen); +} + /* * Compare two NFSv4 acls. * Return 0 if they are the same, 1 if not the same. diff --git a/sys/fs/nfs/nfs_commonsubs.c b/sys/fs/nfs/nfs_commonsubs.c index 707ad5749ab2..2b0ce45d05dd 100644 --- a/sys/fs/nfs/nfs_commonsubs.c +++ b/sys/fs/nfs/nfs_commonsubs.c @@ -228,7 +228,7 @@ static bool nfs_bigreply[NFSV42_NPROCS] = { }; /* local functions */ -static int nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep); +static int nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t, int *acesizep); static void nfsv4_wanted(struct nfsv4lock *lp); static uint32_t nfsv4_filesavail(struct statfs *, struct mount *); static int nfsrv_getuser(int procnum, uid_t uid, gid_t gid, char *name); @@ -240,6 +240,7 @@ static uint32_t vtonfsv4_type(struct vattr *); static __enum_uint8(vtype) nfsv4tov_type(uint32_t, uint16_t *); static void nfsv4_setsequence(struct nfsmount *, struct nfsrv_descript *, struct nfsclsession *, bool, struct ucred *); +static uint32_t nfs_trueform(struct vnode *); static struct { int op; @@ -1149,18 +1150,19 @@ int nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server, int *aclerrp, int *aclsizep, __unused NFSPROC_T *p) { - u_int32_t *tl; + uint32_t *tl; int i, aclsize; int acecnt, error = 0, aceerr = 0, acesize; + bool posixacl = false; *aclerrp = 0; - if (aclp) + if (aclp != NULL) aclp->acl_cnt = 0; /* * Parse out the ace entries and expect them to conform to * what can be supported by R/W/X bits. */ - NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED); + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); aclsize = NFSX_UNSIGNED; acecnt = fxdr_unsigned(int, *tl); /* @@ -1176,20 +1178,28 @@ nfsrv_dissectacl(struct nfsrv_descript *nd, NFSACL_T *aclp, bool server, if (nfsrv_useacl == 0) aceerr = NFSERR_ATTRNOTSUPP; for (i = 0; i < acecnt; i++) { - if (aclp && !aceerr) - error = nfsrv_dissectace(nd, &aclp->acl_entry[i], - server, &aceerr, &acesize, p); + if (aclp != NULL && aceerr == 0) { + if (posixacl) + error = nfsrv_dissectposixace(nd, + &aclp->acl_entry[i], server, &aceerr, + &acesize); + else + error = nfsrv_dissectace(nd, + &aclp->acl_entry[i], server, &aceerr, + &acesize, p); + } else if (posixacl) + error = nfsrv_skipace(nd, ACL_TYPE_ACCESS, &acesize); else - error = nfsrv_skipace(nd, &acesize); - if (error) + error = nfsrv_skipace(nd, ACL_TYPE_NFS4, &acesize); + if (error != 0) goto nfsmout; aclsize += acesize; } - if (aclp && !aceerr) + if (aclp != NULL && aceerr == 0) aclp->acl_cnt = acecnt; - if (aceerr) + if (aceerr != 0) *aclerrp = aceerr; - if (aclsizep) + if (aclsizep != NULL) *aclsizep = aclsize; nfsmout: NFSEXITCODE2(error, nd); @@ -1200,16 +1210,22 @@ nfsmout: * Skip over an NFSv4 ace entry. Just dissect the xdr and discard it. */ static int -nfsrv_skipace(struct nfsrv_descript *nd, int *acesizep) +nfsrv_skipace(struct nfsrv_descript *nd, acl_type_t acltype, int *acesizep) { - u_int32_t *tl; + uint32_t *tl; int error, len = 0; - NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED); - len = fxdr_unsigned(int, *(tl + 3)); + if (acltype == ACL_TYPE_NFS4) { + NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED); + len = fxdr_unsigned(int, *(tl + 3)); + *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); + } else { + NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED); + len = fxdr_unsigned(int, *(tl + 2)); + *acesizep = NFSM_RNDUP(len) + (3 * NFSX_UNSIGNED); + } error = nfsm_advance(nd, NFSM_RNDUP(len), -1); nfsmout: - *acesizep = NFSM_RNDUP(len) + (4 * NFSX_UNSIGNED); NFSEXITCODE2(error, nd); return (error); } @@ -1437,6 +1453,11 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACL); NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_ACLSUPPORT); } + /* Some filesystem do not support POSIX ACL */ + if (nfsrv_useacl == 0 || nfs_supportsposixacls(vp) == 0) { + NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_POSIXACCESSACL); + NFSCLRBIT_ATTRBIT(&checkattrbits, NFSATTRBIT_POSIXDEFAULTACL); + } /* Some filesystems do not support uf_hidden */ if (vp == NULL || VOP_PATHCONF(vp, _PC_HAS_HIDDENSYSTEM, &has_pathconf) != 0) @@ -1655,7 +1676,7 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, if (error) goto nfsmout; } - + attrsum += cnt; break; case NFSATTRBIT_ACLSUPPORT: @@ -2440,6 +2461,111 @@ nfsv4_loadattr(struct nfsrv_descript *nd, vnode_t vp, } attrsum += NFSX_UNSIGNED; break; + case NFSATTRBIT_ACLTRUEFORM: + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + tuint = nfs_trueform(vp); + if (tuint != fxdr_unsigned(uint32_t, + *tl)) + *retcmpp = NFSERR_NOTSAME; + } +#ifdef notyet + } else if (trueformp != NULL) { + *trueformp = fxdr_unsigned(uint32_t, *tl); + } +#else + } +#endif + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_ACLTRUEFORMSCOPE: + NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED); + if (compare) { + if (!(*retcmpp)) { + if (fxdr_unsigned(uint32_t, *tl) != + NFSV4_ACL_SCOPE_FILE_SYSTEM) + *retcmpp = NFSERR_NOTSAME; + } + } + attrsum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_POSIXACCESSACL: + if (compare) { + if (!(*retcmpp)) { + if (nfsrv_useacl && nfs_supportsposixacls(vp)) { + NFSACL_T *naclp; + + naclp = acl_alloc(M_WAITOK); + error = nfsrv_dissectacl(nd, naclp, true, + &aceerr, &cnt, p); + if (error) { + acl_free(naclp); + goto nfsmout; + } + if (aceerr || aclp == NULL || + nfsrv_compareacl(aclp, naclp)) + *retcmpp = NFSERR_NOTSAME; + acl_free(naclp); + } else { + error = nfsrv_dissectacl(nd, NULL, true, + &aceerr, &cnt, p); + if (error) + goto nfsmout; + *retcmpp = NFSERR_ATTRNOTSUPP; + } + } + } else { + if (vp != NULL && aclp != NULL) + error = nfsrv_dissectacl(nd, aclp, false, + &aceerr, &cnt, p); + else + error = nfsrv_dissectacl(nd, NULL, false, + &aceerr, &cnt, p); + if (error) + goto nfsmout; + } + + attrsum += cnt; + break; + case NFSATTRBIT_POSIXDEFAULTACL: + if (compare) { + if (!(*retcmpp)) { + if (nfsrv_useacl && nfs_supportsposixacls(vp)) { + NFSACL_T *naclp; + + naclp = acl_alloc(M_WAITOK); + error = nfsrv_dissectacl(nd, naclp, true, + &aceerr, &cnt, p); + if (error) { + acl_free(naclp); + goto nfsmout; + } + if (aceerr || aclp == NULL || + nfsrv_compareacl(aclp, naclp)) + *retcmpp = NFSERR_NOTSAME; + acl_free(naclp); + } else { + error = nfsrv_dissectacl(nd, NULL, true, + &aceerr, &cnt, p); + if (error) + goto nfsmout; + *retcmpp = NFSERR_ATTRNOTSUPP; + } + } + } else { + if (vp != NULL && aclp != NULL) + error = nfsrv_dissectacl(nd, aclp, false, + &aceerr, &cnt, p); + else + error = nfsrv_dissectacl(nd, NULL, false, + &aceerr, &cnt, p); + if (error) + goto nfsmout; + } + + attrsum += cnt; + break; default: printf("EEK! nfsv4_loadattr unknown attr=%d\n", bitpos); @@ -2711,7 +2837,8 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, struct statfs *fs; struct nfsfsinfo fsinf; struct timespec temptime; - NFSACL_T *aclp, *naclp = NULL; + NFSACL_T *aclp, *naclp = NULL, *paclp, *npaclp = NULL, *daclp; + NFSACL_T *ndaclp = NULL; short irflag; #ifdef QUOTA struct dqblk dqb; @@ -2730,11 +2857,21 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, */ if (p == NULL && cred == NULL) { NFSCLRNOTSETABLE_ATTRBIT(retbitp, nd); - aclp = saclp; + /* Only one of the ACL types can be set for a call. */ + if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) + aclp = saclp; + else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL)) + paclp = saclp; + else if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL)) + daclp = saclp; } else { NFSCLRNOTFILLABLE_ATTRBIT(retbitp, nd); naclp = acl_alloc(M_WAITOK); aclp = naclp; + npaclp = acl_alloc(M_WAITOK); + paclp = npaclp; + ndaclp = acl_alloc(M_WAITOK); + daclp = ndaclp; } nfsvno_getfs(&fsinf, isdgram); /* @@ -2769,12 +2906,12 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, */ if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT) && (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && - supports_nfsv4acls == 0))) { + supports_nfsv4acls != SUPPACL_NFSV4))) { NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACLSUPPORT); } if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_ACL)) { if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && - supports_nfsv4acls == 0)) { + supports_nfsv4acls != SUPPACL_NFSV4)) { NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_ACL); } else if (naclp != NULL) { if (NFSVOPLOCK(vp, LK_SHARED) == 0) { @@ -2796,6 +2933,49 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, } } + /* and the POSIX draft ACL. */ + if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL)) { + if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && + supports_nfsv4acls != SUPPACL_POSIX)) { + NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_POSIXACCESSACL); + } else if (npaclp != NULL) { + if (NFSVOPLOCK(vp, LK_SHARED) == 0) { + error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); + if (error == 0) + error = VOP_GETACL(vp, ACL_TYPE_ACCESS, + npaclp, cred, p); + NFSVOPUNLOCK(vp); + } else + error = NFSERR_PERM; + if (error != 0) { + if (reterr) { + nd->nd_repstat = NFSERR_INVAL; + free(fs, M_STATFS); + return (0); + } + NFSCLRBIT_ATTRBIT(retbitp, + NFSATTRBIT_POSIXACCESSACL); + } + } + } + if (NFSISSET_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL)) { + if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) && + supports_nfsv4acls != SUPPACL_POSIX)) { + NFSCLRBIT_ATTRBIT(retbitp, NFSATTRBIT_POSIXDEFAULTACL); + } else if (ndaclp != NULL) { + if (NFSVOPLOCK(vp, LK_SHARED) == 0) { + error = VOP_ACCESSX(vp, VREAD_ACL, cred, p); + if (error == 0) + error = VOP_GETACL(vp, ACL_TYPE_DEFAULT, + ndaclp, cred, p); + NFSVOPUNLOCK(vp); + } else + error = NFSERR_PERM; + if (error != 0) + ndaclp->acl_cnt = 0; + } + } + /* * Put out the attribute bitmap for the ones being filled in * and get the field for the number of attributes returned. @@ -2813,10 +2993,17 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, case NFSATTRBIT_SUPPORTEDATTRS: NFSSETSUPP_ATTRBIT(&attrbits, nd); if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) - && supports_nfsv4acls == 0)) { + && supports_nfsv4acls != SUPPACL_NFSV4)) { NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACLSUPPORT); NFSCLRBIT_ATTRBIT(&attrbits,NFSATTRBIT_ACL); } + if (nfsrv_useacl == 0 || ((cred != NULL || p != NULL) + && supports_nfsv4acls != SUPPACL_POSIX)) { + NFSCLRBIT_ATTRBIT(&attrbits, + NFSATTRBIT_POSIXACCESSACL); + NFSCLRBIT_ATTRBIT(&attrbits, + NFSATTRBIT_POSIXDEFAULTACL); + } if (!has_hiddensystem) { NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_HIDDEN); NFSCLRBIT_ATTRBIT(&attrbits, NFSATTRBIT_SYSTEM); @@ -3321,6 +3508,24 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, *tl = txdr_unsigned(clone_blksize); retnum += NFSX_UNSIGNED; break; + case NFSATTRBIT_ACLTRUEFORM: + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(nfs_trueform(vp)); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_ACLTRUEFORMSCOPE: + NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED); + *tl = txdr_unsigned(NFSV4_ACL_SCOPE_FILE_SYSTEM); + retnum += NFSX_UNSIGNED; + break; + case NFSATTRBIT_POSIXACCESSACL: + retnum += nfsrv_buildposixacl(nd, paclp, + ACL_TYPE_ACCESS); + break; + case NFSATTRBIT_POSIXDEFAULTACL: + retnum += nfsrv_buildposixacl(nd, daclp, + ACL_TYPE_DEFAULT); + break; default: printf("EEK! Bad V4 attribute bitpos=%d\n", bitpos); } @@ -3328,6 +3533,10 @@ nfsv4_fillattr(struct nfsrv_descript *nd, struct mount *mp, vnode_t vp, } if (naclp != NULL) acl_free(naclp); + if (npaclp != NULL) + acl_free(npaclp); + if (ndaclp != NULL) + acl_free(ndaclp); free(fs, M_STATFS); *retnump = txdr_unsigned(retnum); return (retnum + prefixnum); @@ -5346,6 +5555,23 @@ nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclsession *tsep, return (error); } +/* + * Determine the true form (the type of ACL stored on the file) for the + * vnode argument. + */ +static uint32_t +nfs_trueform(struct vnode *vp) +{ + uint32_t trueform; + + trueform = NFSV4_ACL_MODEL_NONE; + if ((vp->v_mount->mnt_flag & MNT_NFS4ACLS) != 0) + trueform = NFSV4_ACL_MODEL_NFS4; + else if ((vp->v_mount->mnt_flag & MNT_ACLS) != 0) + trueform = NFSV4_ACL_MODEL_POSIX_DRAFT; + return (trueform); +} + /* * Translate a vnode type into an NFSv4 type, including the named * attribute types. diff --git a/sys/fs/nfs/nfs_var.h b/sys/fs/nfs/nfs_var.h index 49a94323a572..c04c3951d42d 100644 --- a/sys/fs/nfs/nfs_var.h +++ b/sys/fs/nfs/nfs_var.h @@ -443,8 +443,11 @@ int nfs_supportsposixacls(struct vnode *); int nfsrv_dissectace(struct nfsrv_descript *, struct acl_entry *, bool, int *, int *, NFSPROC_T *); uint32_t nfs_aceperm(acl_perm_t); +int nfsrv_dissectposixace(struct nfsrv_descript *, struct acl_entry *, + bool, int *, int *); int nfsrv_buildacl(struct nfsrv_descript *, NFSACL_T *, __enum_uint8(vtype), NFSPROC_T *); +int nfsrv_buildposixacl(struct nfsrv_descript *, NFSACL_T *, acl_type_t); int nfsrv_compareacl(NFSACL_T *, NFSACL_T *); /* nfs_clrpcops.c */