- From 14c0ecf4fd59d2ca2044f951419ad4eecad8b54a Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 15 Nov 2025 15:18:13 +0100
- Subject: [PATCH 1/5] build.vc19,daemon: Move Windows ACL from/to NFSv4 ACL
- conversion functions into aclutil.[ch]
- Move Windows ACL from/to NFSv4 ACL conversion functions from acl.c
- into aclutil.[ch].
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- build.vc19/nfsd/nfsd.vcxproj | 2 +
- build.vc19/nfsd/nfsd.vcxproj.filters | 6 +
- daemon/acl.c | 1159 +------------------------
- daemon/aclutil.c | 1187 ++++++++++++++++++++++++++
- daemon/aclutil.h | 46 +
- daemon/open.c | 7 +-
- 6 files changed, 1243 insertions(+), 1164 deletions(-)
- create mode 100644 daemon/aclutil.c
- create mode 100644 daemon/aclutil.h
- diff --git a/build.vc19/nfsd/nfsd.vcxproj b/build.vc19/nfsd/nfsd.vcxproj
- index 846dfbb..8589a2a 100644
- --- a/build.vc19/nfsd/nfsd.vcxproj
- +++ b/build.vc19/nfsd/nfsd.vcxproj
- @@ -288,6 +288,7 @@
- <ItemGroup>
- <ClCompile Include="..\..\daemon\accesstoken.c" />
- <ClCompile Include="..\..\daemon\acl.c" />
- + <ClCompile Include="..\..\daemon\aclutil.c" />
- <ClCompile Include="..\..\daemon\callback_server.c" />
- <ClCompile Include="..\..\daemon\callback_xdr.c" />
- <ClCompile Include="..\..\daemon\cpvparser1.c" />
- @@ -333,6 +334,7 @@
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="..\..\daemon\accesstoken.h" />
- + <ClInclude Include="..\..\daemon\aclutil.h" />
- <ClInclude Include="..\..\daemon\cpvparser1.h" />
- <ClInclude Include="..\..\daemon\daemon_debug.h" />
- <ClInclude Include="..\..\daemon\delegation.h" />
- diff --git a/build.vc19/nfsd/nfsd.vcxproj.filters b/build.vc19/nfsd/nfsd.vcxproj.filters
- index 135a635..8e833c1 100644
- --- a/build.vc19/nfsd/nfsd.vcxproj.filters
- +++ b/build.vc19/nfsd/nfsd.vcxproj.filters
- @@ -18,6 +18,9 @@
- <ClCompile Include="..\..\daemon\acl.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- + <ClCompile Include="..\..\daemon\aclutil.c">
- + <Filter>Source Files</Filter>
- + </ClCompile>
- <ClCompile Include="..\..\daemon\callback_server.c">
- <Filter>Source Files</Filter>
- </ClCompile>
- @@ -149,6 +152,9 @@
- </ClCompile>
- </ItemGroup>
- <ItemGroup>
- + <ClInclude Include="..\..\daemon\aclutil.h">
- + <Filter>Header Files</Filter>
- + </ClInclude>
- <ClInclude Include="..\..\daemon\cpvparser1.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- diff --git a/daemon/acl.c b/daemon/acl.c
- index d53281e..bd02f56 100644
- --- a/daemon/acl.c
- +++ b/daemon/acl.c
- @@ -28,6 +28,7 @@
- #include "nfs41_ops.h"
- #include "nfs41_build_features.h"
- +#include "aclutil.h"
- #include "nfs41_daemon.h"
- #include "delegation.h"
- #include "daemon_debug.h"
- @@ -36,25 +37,6 @@
- #include "nfs41_xdr.h"
- #include "sid.h"
- -#define MAP_WIN32GENERIC2ACE4GENERIC 1
- -#define WORKAROUND_FOR_LINUX_NFSD_NOT_SETTING_ACE4_WRITE_ATTRIBUTES 1
- -
- -/* |DPRINTF()| levels for acl logging */
- -#define ACLLVL1 1
- -#define ACLLVL2 2
- -#define ACLLVL3 3
- -
- -#define ACE4_RW_NAMED_ATTRS \
- - (ACE4_READ_NAMED_ATTRS|ACE4_WRITE_NAMED_ATTRS)
- -
- -/* Local prototypes */
- -static void map_winace2nfs4aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags);
- -static void map_nfs4aceflags2winaceflags(uint32_t nfs4_aceflags, DWORD *win_aceflags);
- -static void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
- - int file_type, bool named_attr_support, uint32_t *nfs4_mask);
- -static void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
- - int file_type, bool named_attr_support, ACCESS_MASK *win_mask);
- -
- static int parse_getacl(
- const unsigned char *restrict buffer,
- uint32_t length,
- @@ -73,267 +55,6 @@ out:
- return status;
- }
- -static void convert_nfs4name_2_user_domain(LPSTR nfs4name,
- - LPSTR *domain)
- -{
- - LPSTR p = nfs4name;
- - for(; p[0] != '\0'; p++) {
- - if (p[0] == '@') {
- - p[0] = '\0';
- -
- - *domain = &p[1];
- - break;
- - }
- - }
- -}
- -
- -static void free_sids(PSID *sids, int count)
- -{
- - int i;
- - for(i = 0; i < count; i++)
- - free(sids[i]);
- - free(sids);
- -}
- -
- -static int check_4_special_identifiers(const char *restrict who,
- - PSID *sid,
- - DWORD *sid_len,
- - BOOLEAN *flag)
- -{
- - int status = ERROR_SUCCESS;
- - WELL_KNOWN_SID_TYPE type = 0;
- - *flag = TRUE;
- -
- - /*
- - * Compare |who| against known constant strings, excluding the '@'
- - * symbol. Note that |ACE4_NOBODY| and |ACE4_WIN_NULL_SID| do not
- - * have a '@
- - */
- - if (!strncmp(who, ACE4_OWNER, ACE4_OWNER_LEN-1))
- - type = WinCreatorOwnerSid;
- -#ifdef NFS41_DRIVER_WS2022_HACKS
- - else if (!strncmp(who, ACE4_WIN_CREATOR_OWNER, ACE4_WIN_CREATOR_OWNER_LEN-1))
- - type = WinCreatorOwnerSid;
- -#endif /* NFS41_DRIVER_WS2022_HACKS */
- - else if (!strncmp(who, ACE4_GROUP, ACE4_GROUP_LEN-1))
- - type = WinCreatorGroupSid;
- -#ifdef NFS41_DRIVER_WS2022_HACKS
- - else if (!strncmp(who, ACE4_WIN_CREATOR_GROUP, ACE4_WIN_CREATOR_GROUP_LEN-1))
- - type = WinCreatorGroupSid;
- -#endif /* NFS41_DRIVER_WS2022_HACKS */
- - else if (!strncmp(who, ACE4_EVERYONE, ACE4_EVERYONE_LEN-1))
- - type = WinWorldSid;
- -#ifdef NFS41_DRIVER_WS2022_HACKS
- - else if (!strncmp(who, ACE4_WIN_EVERYONE, ACE4_WIN_EVERYONE_LEN-1))
- - type = WinWorldSid;
- -#endif /* NFS41_DRIVER_WS2022_HACKS */
- - else if (!strncmp(who, ACE4_NOBODY, ACE4_NOBODY_LEN))
- - type = WinNullSid;
- -#ifdef NFS41_DRIVER_WS2022_HACKS
- - else if (!strncmp(who, ACE4_WIN_NULL_SID, ACE4_WIN_NULL_SID_LEN))
- - type = WinNullSid;
- -#endif /* NFS41_DRIVER_WS2022_HACKS */
- - else
- - *flag = FALSE;
- - if (*flag)
- - status = create_unknownsid(type, sid, sid_len);
- - return status;
- -}
- -
- -static int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
- - nfsacl41 *acl, int file_type, PACL *dacl_out, PSID **sids_out,
- - bool named_attr_support)
- -{
- - int status = ERROR_NOT_SUPPORTED, size = 0;
- - uint32_t nfs_i = 0, win_i = 0;
- - DWORD sid_len;
- - PSID *sids;
- - PACL dacl;
- - LPSTR domain = NULL;
- - BOOLEAN flag;
- -
- - DPRINTF(ACLLVL2, ("--> convert_nfs4acl_2_dacl(acl=0x%p,"
- - "file_type='%s'(=%d), named_attr_support=%d)\n",
- - acl, map_nfs_ftype2str(file_type), file_type,
- - (int)named_attr_support));
- -
- - bool *skip_aces = _alloca(acl->count * sizeof(bool));
- -
- - /*
- - * We use |calloc()| here to get |NULL| pointer for unallocated
- - * slots in case of error codepaths below...
- - */
- - sids = calloc(acl->count, sizeof(PSID));
- - if (sids == NULL) {
- - status = GetLastError();
- - goto out;
- - }
- - for (nfs_i = win_i = 0; nfs_i < acl->count; nfs_i++) {
- - nfsace4 *curr_nfsace = &acl->aces[nfs_i];
- -
- - skip_aces[nfs_i] = false;
- -
- - convert_nfs4name_2_user_domain(curr_nfsace->who, &domain);
- - DPRINTF(ACLLVL2, ("convert_nfs4acl_2_dacl: for user='%s' domain='%s'\n",
- - curr_nfsace->who, domain?domain:"<null>"));
- -
- - EASSERT_MSG(!isdigit(curr_nfsace->who[0]),
- - ("convert_nfs4acl_2_dacl: aces[%d]->who='%s' uses numeric id\n",
- - (int)nfs_i, curr_nfsace->who));
- -
- -#ifdef NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES
- - /*
- - * Skip "nobody" ACEs - Cygwin uses |WinNullSid| ACEs (mapped
- - * to NFS user "nobody") to store special data.
- - * We skip these here, because we cannot use them, as Linux nfsd
- - * only supports POSIX ACLs translated to NFSv4 ACLs, which
- - * corrupts the Cygwin data.
- - */
- - if (!strcmp(curr_nfsace->who, ACE4_NOBODY)) {
- - DPRINTF(ACLLVL3, ("Skipping 'nobody' ACE, "
- - "win_i=%d nfs_i=%d\n", (int)win_i, (int)nfs_i));
- - skip_aces[nfs_i] = true;
- - continue;
- - }
- -#endif /* NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES */
- -
- - status = check_4_special_identifiers(curr_nfsace->who, &sids[win_i],
- - &sid_len, &flag);
- - if (status) {
- - free_sids(sids, win_i);
- - goto out;
- - }
- - if (!flag) {
- - bool isgroupacl = (curr_nfsace->aceflag & ACE4_IDENTIFIER_GROUP)?true:false;
- -
- -
- -#ifdef NFS41_DRIVER_WS2022_HACKS
- - if ((isgroupacl == false) && domain &&
- - (!strcmp(domain, "BUILTIN"))) {
- - if ((!strcmp(curr_nfsace->who, "Users")) ||
- - (!strcmp(curr_nfsace->who, "Administrators"))) {
- - DPRINTF(1, ("convert_nfs4acl_2_dacl: "
- - "force isgroupacl=true for for user='%s'\n",
- - curr_nfsace->who));
- - isgroupacl = true;
- - }
- - }
- -#endif /* NFS41_DRIVER_WS2022_HACKS */
- - if (isgroupacl) {
- - DPRINTF(ACLLVL2,
- - ("convert_nfs4acl_2_dacl: aces[%d].who='%s': "
- - "Setting group flag\n",
- - nfs_i, curr_nfsace->who));
- - }
- -
- - status = map_nfs4servername_2_sid(nfs41dg,
- - (isgroupacl?GROUP_SECURITY_INFORMATION:OWNER_SECURITY_INFORMATION),
- - &sid_len, &sids[win_i], curr_nfsace->who);
- - if (status) {
- - free_sids(sids, win_i);
- - goto out;
- - }
- - }
- - size += sid_len - sizeof(DWORD);
- -
- - win_i++;
- - }
- - size += sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)*win_i);
- - size = align8(size); // align size on |DWORD| boundry
- - dacl = malloc(size);
- - if (dacl == NULL)
- - goto out_free_sids;
- -
- - if (InitializeAcl(dacl, size, ACL_REVISION)) {
- - ACCESS_MASK mask;
- - DWORD win_aceflags;
- -
- - for (nfs_i = win_i = 0; nfs_i < acl->count; nfs_i++) {
- - nfsace4 *curr_nfsace = &acl->aces[nfs_i];
- -
- - if (skip_aces[nfs_i])
- - continue;
- -
- - map_nfs4aceflags2winaceflags(curr_nfsace->aceflag,
- - &win_aceflags);
- - map_nfs4acemask2winaccessmask(curr_nfsace->acemask,
- - file_type, named_attr_support, &mask);
- -
- - if (DPRINTF_LEVEL_ENABLED(ACLLVL1)) {
- - dprintf_out("nfs2win: acl->aces[%d].who='%s': "
- - "acetype='%s', "
- - "nfs_acemask=0x%lx, win_mask=0x%lx, "
- - "win_aceflags=0x%lx\n",
- - nfs_i, curr_nfsace->who,
- - map_nfs_acetype2str(curr_nfsace->acetype),
- - (long)curr_nfsace->acemask,
- - (long)mask,
- - (long)win_aceflags);
- -
- - print_nfs_access_mask(curr_nfsace->who,
- - curr_nfsace->acemask);
- - print_windows_access_mask(curr_nfsace->who, mask);
- - }
- -
- - if (curr_nfsace->acetype == ACE4_ACCESS_ALLOWED_ACE_TYPE) {
- - status = AddAccessAllowedAceEx(dacl, ACL_REVISION,
- - win_aceflags, mask, sids[win_i]);
- - if (!status) {
- - eprintf("convert_nfs4acl_2_dacl: "
- - "AddAccessAllowedAceEx"
- - "(dacl=0x%p,win_aceflags=0x%x,mask=0x%x,who='%s') "
- - "failed with lasterr=%d\n",
- - dacl, (int)win_aceflags, (int)mask,
- - curr_nfsace->who, (int)GetLastError());
- - status = ERROR_INTERNAL_ERROR;
- - goto out_free_dacl;
- - }
- - status = ERROR_SUCCESS;
- - } else if (curr_nfsace->acetype == ACE4_ACCESS_DENIED_ACE_TYPE) {
- - status = AddAccessDeniedAceEx(dacl, ACL_REVISION,
- - win_aceflags, mask, sids[win_i]);
- - if (!status) {
- - eprintf("convert_nfs4acl_2_dacl: "
- - "AddAccessDeniedAceEx"
- - "(dacl=0x%p,win_aceflags=0x%x,mask=0x%x,who='%s') "
- - "failed with lasterr=%d\n",
- - dacl, (int)win_aceflags, (int)mask,
- - curr_nfsace->who, (int)GetLastError());
- - status = ERROR_INTERNAL_ERROR;
- - goto out_free_dacl;
- - }
- - status = ERROR_SUCCESS;
- - } else {
- - eprintf("convert_nfs4acl_2_dacl: unknown acetype %d\n",
- - curr_nfsace->acetype);
- - status = ERROR_INTERNAL_ERROR;
- - free(dacl);
- - free_sids(sids, win_i);
- - goto out;
- - }
- -
- - win_i++;
- - }
- - } else {
- - eprintf("convert_nfs4acl_2_dacl: InitializeAcl failed with %d\n", status);
- - goto out_free_dacl;
- - }
- - status = ERROR_SUCCESS;
- - *sids_out = sids;
- - *dacl_out = dacl;
- -out:
- - DPRINTF(ACLLVL2, ("<-- convert_nfs4acl_2_dacl("
- - "acl=0x%p,file_type='%s'(=%d)) returning %d\n",
- - acl, map_nfs_ftype2str(file_type), file_type, status));
- - return status;
- -out_free_dacl:
- - free(dacl);
- -out_free_sids:
- - free_sids(sids, win_i);
- - status = GetLastError();
- - goto out;
- -}
- -
- static int handle_getacl(void *daemon_context, nfs41_upcall *upcall)
- {
- int status = ERROR_NOT_SUPPORTED;
- @@ -553,884 +274,6 @@ out:
- return status;
- }
- -static int is_well_known_sid(PSID sid, char *who, SID_NAME_USE *snu_out)
- -{
- - const WELL_KNOWN_SID_TYPE test_types[] = {
- - WinCreatorOwnerSid,
- - WinCreatorGroupSid,
- - WinBuiltinUsersSid,
- - WinNullSid,
- - WinAnonymousSid,
- - WinWorldSid,
- - WinAuthenticatedUserSid,
- - WinDialupSid,
- - WinNetworkSid,
- - WinBatchSid,
- - WinInteractiveSid,
- - WinNetworkServiceSid,
- - WinLocalServiceSid,
- - WinServiceSid
- - };
- - const size_t test_types_count = ARRAYSIZE(test_types);
- -
- - BOOL ismatch;
- - size_t i;
- -
- -#ifdef _DEBUG
- - static bool once = true;
- -
- - if (once) {
- - once = false;
- - EASSERT(test_types_count == 14);
- - /* Safeguards if someone tampers with the #defines for this */
- - EASSERT(strlen(ACE4_OWNER) == ACE4_OWNER_LEN);
- - EASSERT(strlen(ACE4_GROUP) == ACE4_GROUP_LEN);
- - EASSERT(strlen(ACE4_NOBODY) == ACE4_NOBODY_LEN);
- - EASSERT(strlen(ACE4_ANONYMOUS) == ACE4_ANONYMOUS_LEN);
- - EASSERT(strlen(ACE4_EVERYONE) == ACE4_EVERYONE_LEN);
- - }
- -#endif /* _DEBUG */
- -
- - for (i = 0; i < test_types_count ; i++) {
- - WELL_KNOWN_SID_TYPE tt = test_types[i];
- -
- - ismatch = IsWellKnownSid(sid, tt);
- - if (!ismatch) {
- - continue;
- - }
- -
- - DPRINTF(ACLLVL3, ("WELL_KNOWN_SID_TYPE=%d\n", (int)tt));
- - switch(tt) {
- - case WinCreatorOwnerSid:
- - (void)memcpy(who, ACE4_OWNER, ACE4_OWNER_LEN+1);
- - *snu_out = SidTypeUser;
- - return TRUE;
- - case WinCreatorGroupSid:
- - case WinBuiltinUsersSid:
- - (void)memcpy(who, ACE4_GROUP, ACE4_GROUP_LEN+1);
- - *snu_out = SidTypeGroup;
- - return TRUE;
- - case WinNullSid:
- - (void)memcpy(who, ACE4_NOBODY, ACE4_NOBODY_LEN+1);
- - *snu_out = SidTypeUser;
- - return TRUE;
- - case WinAnonymousSid:
- - (void)memcpy(who, ACE4_ANONYMOUS, ACE4_ANONYMOUS_LEN+1);
- - return TRUE;
- - case WinWorldSid:
- - (void)memcpy(who, ACE4_EVERYONE, ACE4_EVERYONE_LEN+1);
- - *snu_out = SidTypeGroup;
- - return TRUE;
- - case WinAuthenticatedUserSid:
- - (void)memcpy(who, ACE4_AUTHENTICATED, ACE4_AUTHENTICATED_LEN+1);
- - return TRUE;
- - case WinDialupSid:
- - (void)memcpy(who, ACE4_DIALUP, ACE4_DIALUP_LEN+1);
- - return TRUE;
- - case WinNetworkSid:
- - (void)memcpy(who, ACE4_NETWORK, ACE4_NETWORK_LEN+1);
- - return TRUE;
- - case WinBatchSid:
- - (void)memcpy(who, ACE4_BATCH, ACE4_BATCH_LEN+1);
- - return TRUE;
- - case WinInteractiveSid:
- - (void)memcpy(who, ACE4_INTERACTIVE, ACE4_INTERACTIVE_LEN+1);
- - return TRUE;
- - case WinNetworkServiceSid:
- - case WinLocalServiceSid:
- - case WinServiceSid:
- - (void)memcpy(who, ACE4_SERVICE, ACE4_SERVICE_LEN+1);
- - return TRUE;
- - default:
- - eprintf("is_well_known_sid: unknown tt=%d\n", (int)tt);
- - return FALSE;
- - }
- - }
- - return FALSE;
- -}
- -
- -static void map_winace2nfs4aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags)
- -{
- - *nfs4_aceflags = 0;
- -
- - if (win_aceflags & OBJECT_INHERIT_ACE)
- - *nfs4_aceflags |= ACE4_FILE_INHERIT_ACE;
- - if (win_aceflags & CONTAINER_INHERIT_ACE)
- - *nfs4_aceflags |= ACE4_DIRECTORY_INHERIT_ACE;
- - if (win_aceflags & NO_PROPAGATE_INHERIT_ACE)
- - *nfs4_aceflags |= ACE4_NO_PROPAGATE_INHERIT_ACE;
- - if (win_aceflags & INHERIT_ONLY_ACE)
- - *nfs4_aceflags |= ACE4_INHERIT_ONLY_ACE;
- - if (win_aceflags & INHERITED_ACE)
- - *nfs4_aceflags |= ACE4_INHERITED_ACE;
- - DPRINTF(ACLLVL3,
- - ("map_winace2nfs4aceflags: win_aceflags=0x%x nfs4_aceflags=0x%x\n",
- - (int)win_aceflags, (int)*nfs4_aceflags));
- -}
- -
- -static void map_nfs4aceflags2winaceflags(uint32_t nfs4_aceflags, DWORD *win_aceflags)
- -{
- - *win_aceflags = 0;
- -
- - if (nfs4_aceflags & ACE4_FILE_INHERIT_ACE)
- - *win_aceflags |= OBJECT_INHERIT_ACE;
- - if (nfs4_aceflags & ACE4_DIRECTORY_INHERIT_ACE)
- - *win_aceflags |= CONTAINER_INHERIT_ACE;
- - if (nfs4_aceflags & ACE4_NO_PROPAGATE_INHERIT_ACE)
- - *win_aceflags |= NO_PROPAGATE_INHERIT_ACE;
- - if (nfs4_aceflags & ACE4_INHERIT_ONLY_ACE)
- - *win_aceflags |= INHERIT_ONLY_ACE;
- - if (nfs4_aceflags & ACE4_INHERITED_ACE)
- - *win_aceflags |= INHERITED_ACE;
- - DPRINTF(ACLLVL3,
- - ("map_nfs4aceflags2winace: nfs4_aceflags=0x%x win_aceflags=0x%x\n",
- - (int)nfs4_aceflags, (int)*win_aceflags));
- -}
- -
- -static
- -void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
- - int file_type, bool named_attr_support, uint32_t *nfs4_mask)
- -{
- - *nfs4_mask = 0;
- -
- - /* check if any GENERIC bits set */
- - if (win_mask & 0xf000000) {
- - /* Filtered |ACE4_GENERIC_*| masks */
- - uint32_t ace4_generic_read_filt = ACE4_GENERIC_READ;
- - uint32_t ace4_generic_write_filt = ACE4_GENERIC_WRITE;
- - uint32_t ace4_generic_execute_filt = ACE4_GENERIC_EXECUTE;
- - uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
- - uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
- -
- -#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- - if (!named_attr_support) {
- - /*
- - * Filter out unsupported features for
- - * |GENERIC_*| --> |ACE_*ATTR| conversion.
- - * Do not filter out explicit individual flags below!
- - */
- - ace4_generic_read_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_generic_write_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_generic_execute_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
- - }
- -#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- -
- - if (win_mask & GENERIC_ALL) {
- - if (file_type == NF4DIR)
- - *nfs4_mask |= ace4_all_dir_filt;
- - else
- - *nfs4_mask |= ace4_all_file_filt;
- - } else {
- - if (win_mask & GENERIC_READ)
- - *nfs4_mask |= ace4_generic_read_filt;
- - if (win_mask & GENERIC_WRITE)
- - *nfs4_mask |= ace4_generic_write_filt;
- - if (win_mask & GENERIC_EXECUTE)
- - *nfs4_mask |= ace4_generic_execute_filt;
- - }
- - }
- -
- - /* Individual flags */
- - if (file_type == NF4DIR) {
- - if (win_mask & FILE_LIST_DIRECTORY) {
- - *nfs4_mask |= ACE4_LIST_DIRECTORY;
- - }
- - if (win_mask & FILE_ADD_FILE) {
- - *nfs4_mask |= ACE4_ADD_FILE;
- - }
- - if (win_mask & FILE_ADD_SUBDIRECTORY) {
- - *nfs4_mask |= ACE4_ADD_SUBDIRECTORY;
- - }
- - if (win_mask & FILE_DELETE_CHILD) {
- - *nfs4_mask |= ACE4_DELETE_CHILD;
- - }
- - if (win_mask & FILE_TRAVERSE) {
- - *nfs4_mask |= ACE4_EXECUTE;
- - }
- - }
- - else {
- - if (win_mask & FILE_READ_DATA) {
- - *nfs4_mask |= ACE4_READ_DATA;
- - }
- - if (win_mask & FILE_WRITE_DATA) {
- - *nfs4_mask |= ACE4_WRITE_DATA;
- - }
- - if (win_mask & FILE_APPEND_DATA) {
- - *nfs4_mask |= ACE4_APPEND_DATA;
- - }
- - if (win_mask & FILE_EXECUTE) {
- - *nfs4_mask |= ACE4_EXECUTE;
- - }
- - /*
- - * gisburn: Why does Win10 set |FILE_DELETE_CHILD| for
- - * plain files ?
- - */
- - if (win_mask & FILE_DELETE_CHILD) {
- - *nfs4_mask |= ACE4_DELETE_CHILD;
- - }
- - }
- -
- - if (win_mask & FILE_READ_EA) {
- - *nfs4_mask |= ACE4_READ_NAMED_ATTRS;
- - }
- - if (win_mask & FILE_WRITE_EA) {
- - *nfs4_mask |= ACE4_WRITE_NAMED_ATTRS;
- - }
- - if (win_mask & FILE_READ_ATTRIBUTES) {
- - *nfs4_mask |= ACE4_READ_ATTRIBUTES;
- - }
- - if (win_mask & FILE_WRITE_ATTRIBUTES) {
- - *nfs4_mask |= ACE4_WRITE_ATTRIBUTES;
- - }
- - if (win_mask & READ_CONTROL) {
- - *nfs4_mask |= ACE4_READ_ACL;
- - }
- - if (win_mask & WRITE_DAC) {
- - *nfs4_mask |= ACE4_WRITE_ACL;
- - }
- - if (win_mask & WRITE_OWNER) {
- - *nfs4_mask |= ACE4_WRITE_OWNER;
- - }
- - if (win_mask & SYNCHRONIZE) {
- - *nfs4_mask |= ACE4_SYNCHRONIZE;
- - }
- - if (win_mask & DELETE) {
- - *nfs4_mask |= ACE4_DELETE;
- - }
- -
- -#if 1
- - /* DEBUG: Compare old and new code */
- - DASSERT_MSG(0,
- - ((long)*nfs4_mask == (long)(win_mask & 0x00ffffff)),
- - ("map_winaccessmask2nfs4acemask: "
- - "new code nfs4_mask=0x%lx, "
- - "old code nfs4_mask=0x%lx\n",
- - (long)*nfs4_mask, (long)(win_mask & 0x00ffffff)));
- -#endif
- -}
- -
- -static
- -void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
- - int file_type, bool named_attr_support, ACCESS_MASK *win_mask)
- -{
- - *win_mask = 0;
- -
- -#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- - bool is_generic = false;
- -
- - /* Filtered |ACE4_GENERIC_*| masks */
- - uint32_t ace4_generic_read_filt = ACE4_GENERIC_READ;
- - uint32_t ace4_generic_write_filt = ACE4_GENERIC_WRITE;
- - uint32_t ace4_generic_execute_filt = ACE4_GENERIC_EXECUTE;
- - uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
- - uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
- -
- - if (!named_attr_support) {
- - /*
- - * Filter out unsupported features for
- - * |ACE_*ATTR| --> |GENERIC_*| conversion.
- - * Do not filter out explicit individual flags below!
- - */
- - ace4_generic_read_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_generic_write_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_generic_execute_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
- - ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
- -
- -#ifdef WORKAROUND_FOR_LINUX_NFSD_NOT_SETTING_ACE4_WRITE_ATTRIBUTES
- - /*
- - * BUG(?): Linux 6.6.32-RT32 does not return
- - * |ACE4_WRITE_ATTRIBUTES| even when the attributes are
- - * writeable.
- - *
- - * Since |ACE4_GENERIC_WRITE| includes the
- - * |ACE4_WRITE_ATTRIBUTES| bit an attempt to set
- - * |GENERIC_WRITE| will succeed, but we can never get all
- - * the |ACE4_*| bits in |ACE4_GENERIC_WRITE| back when
- - * reading the ACL, so without this workaround we could
- - * never match |GENERIC_WRITE| when constructing the Win32
- - * ACLs.
- - *
- - * Testcase:
- - * ---- snip ----
- - * $ ksh93 -c 'rm -f test1.txt
- - * touch test1.txt
- - * icacls test1.txt /grant "siegfried_wulsch:(GW)"
- - * icacls test1.txt'
- - * ---- snip ----
- - * Second icacls should return "GW" for user "siegfried_wulsch".
- - */
- - ace4_generic_read_filt &= ~ACE4_WRITE_ATTRIBUTES;
- - ace4_generic_write_filt &= ~ACE4_WRITE_ATTRIBUTES;
- - ace4_generic_execute_filt &= ~ACE4_WRITE_ATTRIBUTES;
- - ace4_all_file_filt &= ~ACE4_WRITE_ATTRIBUTES;
- - ace4_all_dir_filt &= ~ACE4_WRITE_ATTRIBUTES;
- -#endif /* WORKAROUND_FOR_LINUX_NFSD_NOT_SETTING_ACE4_WRITE_ATTRIBUTES */
- - }
- -
- - /*
- - * Generic masks
- - * (|ACE4_GENERIC_*| contain multiple bits)
- - */
- -#define ACEMASK_TEST_MASK(value, mask) (((value)&(mask)) == (mask))
- - if (file_type == NF4DIR) {
- - if (ACEMASK_TEST_MASK(nfs4_mask, ace4_all_dir_filt)) {
- - *win_mask |= GENERIC_ALL;
- - is_generic = true;
- - }
- - }
- - else {
- - if (ACEMASK_TEST_MASK(nfs4_mask, ace4_all_file_filt)) {
- - *win_mask |= GENERIC_ALL;
- - is_generic = true;
- - }
- - }
- -
- - if (!(*win_mask & GENERIC_ALL)) {
- - if (ACEMASK_TEST_MASK(nfs4_mask, ace4_generic_read_filt)) {
- - *win_mask |= GENERIC_READ;
- - is_generic = true;
- - }
- - if (ACEMASK_TEST_MASK(nfs4_mask, ace4_generic_write_filt)) {
- - *win_mask |= GENERIC_WRITE;
- - is_generic = true;
- - }
- - if (ACEMASK_TEST_MASK(nfs4_mask, ace4_generic_execute_filt)) {
- - *win_mask |= GENERIC_EXECUTE;
- - is_generic = true;
- - }
- - }
- -#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- -
- - /* Individual flags */
- - if (file_type == NF4DIR) {
- - if (nfs4_mask & ACE4_LIST_DIRECTORY) {
- - *win_mask |= FILE_LIST_DIRECTORY;
- - }
- - if (nfs4_mask & ACE4_ADD_FILE) {
- - *win_mask |= FILE_ADD_FILE;
- - }
- - if (nfs4_mask & ACE4_ADD_SUBDIRECTORY) {
- - *win_mask |= FILE_ADD_SUBDIRECTORY;
- - }
- - if (nfs4_mask & ACE4_DELETE_CHILD) {
- - *win_mask |= FILE_DELETE_CHILD;
- - }
- - if (nfs4_mask & ACE4_EXECUTE) {
- - *win_mask |= FILE_TRAVERSE;
- - }
- - }
- - else {
- - if (nfs4_mask & ACE4_READ_DATA) {
- - *win_mask |= FILE_READ_DATA;
- - }
- - if (nfs4_mask & ACE4_WRITE_DATA) {
- - *win_mask |= FILE_WRITE_DATA;
- - }
- - if (nfs4_mask & ACE4_APPEND_DATA) {
- - *win_mask |= FILE_APPEND_DATA;
- - }
- - if (nfs4_mask & ACE4_EXECUTE) {
- - *win_mask |= FILE_EXECUTE;
- - }
- - }
- -
- - if (nfs4_mask & ACE4_READ_NAMED_ATTRS) {
- - *win_mask |= FILE_READ_EA;
- - }
- - if (nfs4_mask & ACE4_WRITE_NAMED_ATTRS) {
- - *win_mask |= FILE_WRITE_EA;
- - }
- - if (nfs4_mask & ACE4_READ_ATTRIBUTES) {
- - *win_mask |= FILE_READ_ATTRIBUTES;
- - }
- - if (nfs4_mask & ACE4_WRITE_ATTRIBUTES) {
- - *win_mask |= FILE_WRITE_ATTRIBUTES;
- - }
- - if (nfs4_mask & ACE4_READ_ACL) {
- - *win_mask |= READ_CONTROL;
- - }
- - if (nfs4_mask & ACE4_WRITE_ACL) {
- - *win_mask |= WRITE_DAC;
- - }
- - if (nfs4_mask & ACE4_WRITE_OWNER) {
- - *win_mask |= WRITE_OWNER;
- - }
- - if (nfs4_mask & ACE4_SYNCHRONIZE) {
- - *win_mask |= SYNCHRONIZE;
- - }
- - if (nfs4_mask & ACE4_DELETE) {
- - *win_mask |= DELETE;
- - }
- -
- -#if 1
- - /* DEBUG: Compare old and new code */
- -#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- - if (!is_generic)
- -#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- - {
- - DASSERT_MSG(0,
- - ((long)*win_mask == (long)(nfs4_mask /*& 0x00ffffff*/)),
- - ("#### map_nfs4acemask2winaccessmask: "
- - "new code win_mask=0x%lx, "
- - "old code win_mask=0x%lx\n",
- - (long)*win_mask, (long)(nfs4_mask /*& 0x00ffffff*/)));
- - }
- -#endif
- -}
- -
- -static
- -int map_sid2nfs4ace_who(PSID sid, PSID owner_sid, PSID group_sid,
- - char *who_out, char *domain, SID_NAME_USE *sid_type_out)
- -{
- - int status, lasterr;
- - SID_NAME_USE sid_type = 0;
- - /* |(UTF8_UNLEN+sizeof('\0'))*2| so we have space for user+domain */
- - char who_buf[(UTF8_UNLEN+1)*2];
- - char domain_buf[UTF8_UNLEN+1];
- - DWORD who_size = sizeof(who_buf), domain_size = sizeof(domain_buf);
- - LPSTR sidstr = NULL;
- -
- - DPRINTF(ACLLVL2, ("--> map_sid2nfs4ace_who("
- - "sid=0x%p,owner_sid=0x%p, group_sid=0x%p)\n",
- - sid, owner_sid, group_sid));
- -
- - if (DPRINTF_LEVEL_ENABLED(ACLLVL2)) {
- - print_sid("sid", sid);
- - print_sid("owner_sid", owner_sid);
- - print_sid("group_sid", group_sid);
- - }
- -
- - /* for ace mapping, we want to map owner's sid into "owner@"
- - * but for set_owner attribute we want to map owner into a user name
- - * same applies to group
- - */
- - status = 0;
- - if (owner_sid) {
- - if (EqualSid(sid, owner_sid)) {
- - DPRINTF(ACLLVL2, ("this is owner's sid\n"));
- - (void)memcpy(who_out, ACE4_OWNER, ACE4_OWNER_LEN+1);
- - sid_type = SidTypeUser;
- - status = ERROR_SUCCESS;
- - goto out;
- - }
- - }
- - if (group_sid) {
- - if (EqualSid(sid, group_sid)) {
- - DPRINTF(ACLLVL2, ("this is group's sid\n"));
- - memcpy(who_out, ACE4_GROUP, ACE4_GROUP_LEN+1);
- - sid_type = SidTypeGroup;
- - status = ERROR_SUCCESS;
- - goto out;
- - }
- - }
- - status = is_well_known_sid(sid, who_out, &sid_type);
- - if (status) {
- - if (!strncmp(who_out, ACE4_NOBODY, ACE4_NOBODY_LEN)) {
- - who_size = (DWORD)ACE4_NOBODY_LEN;
- - goto add_domain;
- - }
- -
- - /* fixme: What about |sid_type| ? */
- - status = ERROR_SUCCESS;
- - goto out;
- - }
- -
- - if (!ConvertSidToStringSidA(sid, &sidstr)) {
- - status = GetLastError();
- - eprintf("map_sid2nfs4ace_who: ConvertSidToStringSidA() "
- - "failed, error=%d\n", status);
- - goto out;
- - }
- -
- - status = lookupaccountsidutf8(NULL, sid, who_buf, &who_size, domain_buf,
- - &domain_size, &sid_type);
- - lasterr = GetLastError();
- -
- - if (status) {
- - DPRINTF(ACLLVL2, ("map_sid2nfs4ace_who: "
- - "LookupAccountSid(sidtostr(sid)='%s', who_buf='%s', "
- - "who_size=%d, domain='%s', domain_size=%d) "
- - "returned success, status=%d, GetLastError=%d\n",
- - sidstr, who_buf, who_size,
- - domain_buf, domain_size, status, lasterr));
- - }
- - else {
- - DPRINTF(ACLLVL2, ("map_sid2nfs4ace_who: "
- - "LookupAccountSid(sidtostr(sid)='%s', who_size=%d, "
- - "domain_size=%d) returned failure, status=%d, "
- - "GetLastError=%d\n",
- - sidstr, who_size, domain_size, status, lasterr));
- -
- - /*
- - * No SID to local account mapping. Can happen for some system
- - * SIDs, and Unix_User+<uid> or Unix_Group+<gid> SIDs
- - */
- - switch (lasterr) {
- - /*
- - * This happens for Unix_User+<uid> or Unix_Group+<gid>
- - * SIDs
- - */
- - case ERROR_NONE_MAPPED:
- - /*
- - * This can happen for two reasons:
- - * 1. Someone copied a file from a NFS(v3) filesystem,
- - * and Cygwin generated an Unix_User+<uid> or
- - * Unix_Group+<gid> SID for the source file, which
- - * tools like Cygwin cp(1) just copy.
- - * 2. We have an uid/gid for which we do not have
- - * a user-/group-name mapped.
- - */
- -#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- - /* fixme: This should be a function argument */
- - extern nfs41_daemon_globals nfs41_dg;
- -
- - uid_t unixuser_uid = ~0U;
- - gid_t unixgroup_gid = ~0U;
- -
- - if (unixuser_sid2uid(sid, &unixuser_uid)) {
- - if (!nfs41_idmap_uid_to_name(nfs41_dg.idmapper,
- - unixuser_uid, who_out, UTF8_UNLEN)) {
- - who_size = (DWORD)strlen(who_out);
- - sid_type = SidTypeUser;
- - status = ERROR_SUCCESS;
- -
- - DPRINTF(ACLLVL1, ("map_sid2nfs4ace_who: "
- - "Unix_User+%d SID "
- - "mapped to user '%s'\n",
- - unixuser_uid, who_out));
- - goto add_domain;
- - }
- -
- - eprintf("map_sid2nfs4ace_who: "
- - "unixuser_sid2uid(sid='%s',unixuser_uid=%d) "
- - "returned no mapping.\n",
- - sidstr, (int)unixuser_uid);
- - goto err_none_mapped;
- - }
- -
- - if (unixgroup_sid2gid(sid, &unixgroup_gid)) {
- - if (!nfs41_idmap_gid_to_group(nfs41_dg.idmapper,
- - unixgroup_gid, who_out, UTF8_GNLEN)) {
- - who_size = (DWORD)strlen(who_out);
- - sid_type = SidTypeGroup;
- - status = ERROR_SUCCESS;
- -
- - DPRINTF(ACLLVL1, ("map_sid2nfs4ace_who: "
- - "Unix_Group+%d SID "
- - "mapped to group '%s'\n",
- - unixgroup_gid, who_out));
- - goto add_domain;
- - }
- -
- - eprintf("map_sid2nfs4ace_who: "
- - "unixgroup_sid2gid(sid='%s',unixgroup_gid=%d) "
- - "returned no mapping.\n",
- - sidstr, (int)unixgroup_gid);
- - goto err_none_mapped;
- - }
- -
- - eprintf("map_sid2nfs4ace_who: lookupaccountsidutf8() "
- - "returned ERROR_NONE_MAPPED+no "
- - "Unix_@(User|Group)+ mapping for sidstr='%s'\n",
- - sidstr);
- -err_none_mapped:
- - status = ERROR_NONE_MAPPED;
- -#else
- - DPRINTF(ACLLVL2,
- - ("map_sid2nfs4ace_who: lookupaccountsidutf8() "
- - "returned ERROR_NONE_MAPPED for sidstr='%s'\n",
- - sidstr));
- - status = lasterr;
- - goto out;
- -#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
- -
- - /* Catch other cases */
- - case ERROR_NO_SUCH_USER:
- - case ERROR_NO_SUCH_GROUP:
- - eprintf("map_sid2nfs4ace_who: lookupaccountsidutf8() "
- - "returned ERROR_NO_SUCH_@(USER|GROUP) for "
- - "sidstr='%s'\n",
- - sidstr);
- - status = lasterr;
- - goto out;
- - default:
- - eprintf("map_sid2nfs4ace_who: Internal error, "
- - "lookupaccountsidutf8() returned unexpected ERROR_%d "
- - "for sidstr='%s'\n",
- - status, sidstr);
- - status = ERROR_INTERNAL_ERROR;
- - goto out;
- - }
- - }
- -
- - (void)memcpy(who_out, who_buf, who_size);
- -add_domain:
- - /*
- - * Complain if we attempt to add a domain suffix to an UID/GID
- - * value
- - */
- - EASSERT(!isdigit(who_out[0]));
- -
- - char *wp;
- -
- - wp = mempcpy(who_out+who_size, "@", sizeof(char));
- -
- -#ifdef NFS41_DRIVER_WS2022_HACKS
- - /* Fixup |domain| for Windows Sever 2022 NFSv4.1 server */
- - if ((!strncmp(who_out, "Users@", (size_t)who_size+1)) ||
- - (!strncmp(who_out, "Administrators@", (size_t)who_size+1))) {
- - domain = "BUILTIN";
- - DPRINTF(1,
- - ("map_sid2nfs4ace_who: Fixup '%.*s' domain='%s'\n",
- - (int)who_size+1, who_out, domain));
- - }
- - else if (!strncmp(who_out, "SYSTEM@", (size_t)who_size+1)) {
- - domain = "NT AUTHORITY";
- - DPRINTF(1,
- - ("map_sid2nfs4ace_who: Fixup '%.*s' domain='%s'\n",
- - (int)who_size+1, who_out, domain));
- - }
- -#endif /* NFS41_DRIVER_WS2022_HACKS */
- - (void)memcpy(wp, domain, strlen(domain)+1);
- -
- -/* no_add_domain: */
- - status = ERROR_SUCCESS;
- -out:
- - if (status) {
- - DPRINTF(ACLLVL2,
- - ("<-- map_sid2nfs4ace_who() returns %d\n", status));
- - }
- - else {
- - DPRINTF(ACLLVL2,
- - ("<-- map_sid2nfs4ace_who(who_out='%s', sid_type='%s'/%d) "
- - "returns %d\n",
- - who_out,
- - map_SID_NAME_USE2str(sid_type), sid_type,
- - status));
- - if (sid_type_out) {
- - *sid_type_out = sid_type;
- - }
- - }
- - if (sidstr)
- - LocalFree(sidstr);
- - return status;
- -}
- -
- -/* FIXME: Move this into aclutils.c */
- -int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
- - int file_type, bool named_attr_support, char *domain)
- -{
- - int status;
- - if (acl == NULL) {
- - DPRINTF(ACLLVL2, ("this is a NULL dacl: all access to an object\n"));
- - nfs4_acl->count = 1;
- - nfs4_acl->aces = calloc(1, sizeof(nfsace4));
- - if (nfs4_acl->aces == NULL) {
- - status = GetLastError();
- - goto out;
- - }
- - nfs4_acl->flag = 0;
- - (void)memcpy(nfs4_acl->aces->who, ACE4_EVERYONE, ACE4_EVERYONE_LEN+1);
- - nfs4_acl->aces->acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE;
- -
- - if (file_type == NF4DIR) {
- - uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
- -#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- - /* Filter out unsupported features */
- - if (!named_attr_support)
- - ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
- -#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- - nfs4_acl->aces->acemask = ace4_all_dir_filt;
- - }
- - else {
- - uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
- -#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- - /* Filter out unsupported features */
- - if (!named_attr_support)
- - ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
- -#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- - nfs4_acl->aces->acemask = ace4_all_file_filt;
- - }
- - nfs4_acl->aces->aceflag = 0;
- - } else {
- - int win_i, nfs_i;
- - PACE_HEADER ace;
- - PBYTE tmp_pointer;
- - SID_NAME_USE who_sid_type = 0;
- - ACCESS_MASK win_mask;
- -
- - DPRINTF(ACLLVL2, ("NON-NULL dacl with %d ACEs\n", acl->AceCount));
- - if (DPRINTF_LEVEL_ENABLED(ACLLVL3)) {
- - print_hexbuf_no_asci("ACL\n",
- - (const unsigned char *)acl, acl->AclSize);
- - }
- -
- - nfs4_acl->aces = calloc(acl->AceCount, sizeof(nfsace4));
- - if (nfs4_acl->aces == NULL) {
- - status = GetLastError();
- - goto out;
- - }
- - nfs4_acl->flag = 0;
- - for (win_i = nfs_i = 0; win_i < acl->AceCount; win_i++) {
- - nfsace4 *curr_nfsace = &nfs4_acl->aces[nfs_i];
- - PSID ace_sid;
- -
- - status = GetAce(acl, win_i, (LPVOID *)&ace);
- - if (!status) {
- - status = GetLastError();
- - eprintf("map_dacl_2_nfs4acl: GetAce failed with %d\n", status);
- - goto out_free;
- - }
- - tmp_pointer = (PBYTE)ace;
- - if (DPRINTF_LEVEL_ENABLED(ACLLVL3)) {
- - print_hexbuf_no_asci("ACE\n",
- - (const unsigned char *)ace, ace->AceSize);
- - }
- - DPRINTF(ACLLVL3, ("ACE TYPE: 0x%x\n", ace->AceType));
- - if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE)
- - curr_nfsace->acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE;
- - else if (ace->AceType == ACCESS_DENIED_ACE_TYPE)
- - curr_nfsace->acetype = ACE4_ACCESS_DENIED_ACE_TYPE;
- - else {
- - eprintf("map_dacl_2_nfs4acl: unsupported ACE type %d\n",
- - ace->AceType);
- - status = ERROR_NOT_SUPPORTED;
- - goto out_free;
- - }
- -
- - tmp_pointer += sizeof(ACCESS_MASK) + sizeof(ACE_HEADER);
- - ace_sid = tmp_pointer;
- -
- -#ifdef NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES
- - if (IsWellKnownSid(ace_sid, WinNullSid)) {
- - /*
- - * Skip ACEs with SID==|WinNullSid|
- - *
- - * Cygwin generates artificial ACEs with SID user
- - * |WinNullSid| to encode permission information
- - * (see |CYG_ACE_ISBITS_TO_POSIX()| in
- - * Cygwin newlib-cygwin/winsup/cygwin/sec/acl.cc
- - *
- - * This assumes that the filesystem which stores
- - * the ACL data leaves them 1:1 intact - which is
- - * not the case for the Linux NFSv4.1 server
- - * (tested with Linux 6.6.32), which transforms the
- - * NFSv4.1 ACLs into POSIX ACLs at setacl time,
- - * and the POSIX ACLs back to NFSv4 ACLs at getacl
- - * time.
- - * And this lossy transformation screws-up Cygwin
- - * completly.
- - * The best we can do for now is to skip such
- - * ACEs, as we have no way to detect whether
- - * the NFS server supports full NFSv4 ACLs, or
- - * only POSIX ACLs disguised as NFSv4 ACLs.
- - */
- - DPRINTF(ACLLVL3, ("Skipping WinNullSid ACE, "
- - "win_i=%d nfs_i=%d\n", (int)win_i, (int)nfs_i));
- - continue;
- - }
- -#endif /* NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES */
- -
- - status = map_sid2nfs4ace_who(ace_sid, sid, gsid,
- - curr_nfsace->who, domain, &who_sid_type);
- - if (status)
- - goto out_free;
- -
- - win_mask = *(PACCESS_MASK)(ace + 1);
- -
- - map_winace2nfs4aceflags(ace->AceFlags,
- - &curr_nfsace->aceflag);
- - map_winaccessmask2nfs4acemask(win_mask,
- - file_type, named_attr_support,
- - &curr_nfsace->acemask);
- -
- - /*
- - * Clear |ACE4_INHERITED_ACE|
- - *
- - * (See RFC 8884 Section-6.2.1.4.1:
- - * ACE4_INHERITED_ACE
- - * Indicates that this ACE is inherited from a parent
- - * directory. A server that supports automatic inheritance
- - * will place this flag on any ACEs inherited from the
- - * parent directory when creating a new object.
- - * Client applications will use this to perform automatic
- - * inheritance. Clients and servers MUST clear this bit in
- - * the acl attribute; it may only be used in the dacl and
- - * sacl attributes.
- - * ---- snip ----
- - * )
- - *
- - * If we do not clear this bit Linux 6.6.32-RT32 nfsd
- - * will reject setting ACLs |NFS4ERR_ATTRNOTSUPP| via
- - * icacls(1win) if the parent directory has inheritance
- - * ACLs.
- - */
- - if (curr_nfsace->aceflag & ACE4_INHERITED_ACE) {
- - curr_nfsace->aceflag &= ~ACE4_INHERITED_ACE;
- - DPRINTF(ACLLVL3, ("clearning ACE4_INHERITED_ACE\n"));
- - }
- -
- - /*
- - * Treat |SidTypeAlias| as (local) group
- - *
- - * It seems that |LookupAccount*A()| will always return
- - * |SidTypeAlias| for local groups created with
- - * $ net localgroup cygwingrp1 /add #
- - *
- - * References:
- - * - https://stackoverflow.com/questions/39373188/lookupaccountnamew-returns-sidtypealias-but-expected-sidtypegroup
- - */
- - if ((who_sid_type == SidTypeGroup) ||
- - (who_sid_type == SidTypeAlias)) {
- - DPRINTF(ACLLVL3, ("map_dacl_2_nfs4acl: who_sid_type='%s': "
- - "aces[%d].who='%s': "
- - "setting group flag\n",
- - map_SID_NAME_USE2str(who_sid_type),
- - nfs_i, curr_nfsace->who));
- - curr_nfsace->aceflag |= ACE4_IDENTIFIER_GROUP;
- - }
- -
- - if (DPRINTF_LEVEL_ENABLED(ACLLVL1)) {
- - dprintf_out("win2nfs: nfs4_acl->aces[%d]=(who='%s', "
- - "acetype='%s', "
- - "aceflag='%s'/0x%lx, "
- - "acemask='%s'/0x%lx(=win_mask=0x%lx)), "
- - "who_sid_type='%s', "
- - "win_i=%d\n",
- - nfs_i,
- - curr_nfsace->who,
- - map_nfs_acetype2str(curr_nfsace->acetype),
- - nfs_aceflag2shortname(curr_nfsace->aceflag),
- - curr_nfsace->aceflag,
- - nfs_mask2shortname(curr_nfsace->acemask),
- - (long)curr_nfsace->acemask,
- - (long)win_mask,
- - map_SID_NAME_USE2str(who_sid_type),
- - (int)win_i);
- - if (DPRINTF_LEVEL_ENABLED(ACLLVL2)) {
- - print_windows_access_mask(curr_nfsace->who,
- - win_mask);
- - print_nfs_access_mask(curr_nfsace->who,
- - curr_nfsace->acemask);
- - }
- - }
- -
- - nfs_i++;
- - }
- -
- - nfs4_acl->count = nfs_i;
- - }
- - status = ERROR_SUCCESS;
- -out:
- - return status;
- -out_free:
- - free(nfs4_acl->aces);
- - goto out;
- -}
- -
- static int handle_setacl(void *daemon_context, nfs41_upcall *upcall)
- {
- int status = ERROR_NOT_SUPPORTED;
- diff --git a/daemon/aclutil.c b/daemon/aclutil.c
- new file mode 100644
- index 0000000..57c1111
- --- /dev/null
- +++ b/daemon/aclutil.c
- @@ -0,0 +1,1187 @@
- +/* NFSv4.1 client for Windows
- + * Copyright (C) 2012 The Regents of the University of Michigan
- + * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * Olga Kornievskaia <aglo@umich.edu>
- + * Casey Bodley <cbodley@umich.edu>
- + * Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * This library is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU Lesser General Public License as published by
- + * the Free Software Foundation; either version 2.1 of the License, or (at
- + * your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful, but
- + * without any warranty; without even the implied warranty of merchantability
- + * or fitness for a particular purpose. See the GNU Lesser General Public
- + * License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public License
- + * along with this library; if not, write to the Free Software Foundation,
- + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- + */
- +
- +#include <Windows.h>
- +#include <stdio.h>
- +#include <strsafe.h>
- +#include <sddl.h>
- +
- +#include "nfs41_build_features.h"
- +#include "aclutil.h"
- +#include "nfs41_daemon.h"
- +#include "daemon_debug.h"
- +#include "util.h"
- +#include "sid.h"
- +
- +#define MAP_WIN32GENERIC2ACE4GENERIC 1
- +#define WORKAROUND_FOR_LINUX_NFSD_NOT_SETTING_ACE4_WRITE_ATTRIBUTES 1
- +
- +#define ACE4_RW_NAMED_ATTRS \
- + (ACE4_READ_NAMED_ATTRS|ACE4_WRITE_NAMED_ATTRS)
- +
- +/* Local prototypes */
- +static void map_winace2nfs4aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags);
- +static void map_nfs4aceflags2winaceflags(uint32_t nfs4_aceflags, DWORD *win_aceflags);
- +static void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
- + int file_type, bool named_attr_support, uint32_t *nfs4_mask);
- +static void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
- + int file_type, bool named_attr_support, ACCESS_MASK *win_mask);
- +
- + void convert_nfs4name_2_user_domain(LPSTR nfs4name,
- + LPSTR *domain)
- +{
- + LPSTR p = nfs4name;
- + for(; p[0] != '\0'; p++) {
- + if (p[0] == '@') {
- + p[0] = '\0';
- +
- + *domain = &p[1];
- + break;
- + }
- + }
- +}
- +
- +void free_sids(PSID *sids, int count)
- +{
- + int i;
- + for(i = 0; i < count; i++)
- + free(sids[i]);
- + free(sids);
- +}
- +
- +static int check_4_special_identifiers(const char *restrict who,
- + PSID *sid,
- + DWORD *sid_len,
- + BOOLEAN *flag)
- +{
- + int status = ERROR_SUCCESS;
- + WELL_KNOWN_SID_TYPE type = 0;
- + *flag = TRUE;
- +
- + /*
- + * Compare |who| against known constant strings, excluding the '@'
- + * symbol. Note that |ACE4_NOBODY| and |ACE4_WIN_NULL_SID| do not
- + * have a '@
- + */
- + if (!strncmp(who, ACE4_OWNER, ACE4_OWNER_LEN-1))
- + type = WinCreatorOwnerSid;
- +#ifdef NFS41_DRIVER_WS2022_HACKS
- + else if (!strncmp(who, ACE4_WIN_CREATOR_OWNER, ACE4_WIN_CREATOR_OWNER_LEN-1))
- + type = WinCreatorOwnerSid;
- +#endif /* NFS41_DRIVER_WS2022_HACKS */
- + else if (!strncmp(who, ACE4_GROUP, ACE4_GROUP_LEN-1))
- + type = WinCreatorGroupSid;
- +#ifdef NFS41_DRIVER_WS2022_HACKS
- + else if (!strncmp(who, ACE4_WIN_CREATOR_GROUP, ACE4_WIN_CREATOR_GROUP_LEN-1))
- + type = WinCreatorGroupSid;
- +#endif /* NFS41_DRIVER_WS2022_HACKS */
- + else if (!strncmp(who, ACE4_EVERYONE, ACE4_EVERYONE_LEN-1))
- + type = WinWorldSid;
- +#ifdef NFS41_DRIVER_WS2022_HACKS
- + else if (!strncmp(who, ACE4_WIN_EVERYONE, ACE4_WIN_EVERYONE_LEN-1))
- + type = WinWorldSid;
- +#endif /* NFS41_DRIVER_WS2022_HACKS */
- + else if (!strncmp(who, ACE4_NOBODY, ACE4_NOBODY_LEN))
- + type = WinNullSid;
- +#ifdef NFS41_DRIVER_WS2022_HACKS
- + else if (!strncmp(who, ACE4_WIN_NULL_SID, ACE4_WIN_NULL_SID_LEN))
- + type = WinNullSid;
- +#endif /* NFS41_DRIVER_WS2022_HACKS */
- + else
- + *flag = FALSE;
- + if (*flag)
- + status = create_unknownsid(type, sid, sid_len);
- + return status;
- +}
- +
- +int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
- + nfsacl41 *acl, int file_type, PACL *dacl_out, PSID **sids_out,
- + bool named_attr_support)
- +{
- + int status = ERROR_NOT_SUPPORTED, size = 0;
- + uint32_t nfs_i = 0, win_i = 0;
- + DWORD sid_len;
- + PSID *sids;
- + PACL dacl;
- + LPSTR domain = NULL;
- + BOOLEAN flag;
- +
- + DPRINTF(ACLLVL2, ("--> convert_nfs4acl_2_dacl(acl=0x%p,"
- + "file_type='%s'(=%d), named_attr_support=%d)\n",
- + acl, map_nfs_ftype2str(file_type), file_type,
- + (int)named_attr_support));
- +
- + bool *skip_aces = _alloca(acl->count * sizeof(bool));
- +
- + /*
- + * We use |calloc()| here to get |NULL| pointer for unallocated
- + * slots in case of error codepaths below...
- + */
- + sids = calloc(acl->count, sizeof(PSID));
- + if (sids == NULL) {
- + status = GetLastError();
- + goto out;
- + }
- + for (nfs_i = win_i = 0; nfs_i < acl->count; nfs_i++) {
- + nfsace4 *curr_nfsace = &acl->aces[nfs_i];
- +
- + skip_aces[nfs_i] = false;
- +
- + convert_nfs4name_2_user_domain(curr_nfsace->who, &domain);
- + DPRINTF(ACLLVL2, ("convert_nfs4acl_2_dacl: for user='%s' domain='%s'\n",
- + curr_nfsace->who, domain?domain:"<null>"));
- +
- + EASSERT_MSG(!isdigit(curr_nfsace->who[0]),
- + ("convert_nfs4acl_2_dacl: aces[%d]->who='%s' uses numeric id\n",
- + (int)nfs_i, curr_nfsace->who));
- +
- +#ifdef NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES
- + /*
- + * Skip "nobody" ACEs - Cygwin uses |WinNullSid| ACEs (mapped
- + * to NFS user "nobody") to store special data.
- + * We skip these here, because we cannot use them, as Linux nfsd
- + * only supports POSIX ACLs translated to NFSv4 ACLs, which
- + * corrupts the Cygwin data.
- + */
- + if (!strcmp(curr_nfsace->who, ACE4_NOBODY)) {
- + DPRINTF(ACLLVL3, ("Skipping 'nobody' ACE, "
- + "win_i=%d nfs_i=%d\n", (int)win_i, (int)nfs_i));
- + skip_aces[nfs_i] = true;
- + continue;
- + }
- +#endif /* NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES */
- +
- + status = check_4_special_identifiers(curr_nfsace->who, &sids[win_i],
- + &sid_len, &flag);
- + if (status) {
- + free_sids(sids, win_i);
- + goto out;
- + }
- + if (!flag) {
- + bool isgroupacl = (curr_nfsace->aceflag & ACE4_IDENTIFIER_GROUP)?true:false;
- +
- +
- +#ifdef NFS41_DRIVER_WS2022_HACKS
- + if ((isgroupacl == false) && domain &&
- + (!strcmp(domain, "BUILTIN"))) {
- + if ((!strcmp(curr_nfsace->who, "Users")) ||
- + (!strcmp(curr_nfsace->who, "Administrators"))) {
- + DPRINTF(1, ("convert_nfs4acl_2_dacl: "
- + "force isgroupacl=true for for user='%s'\n",
- + curr_nfsace->who));
- + isgroupacl = true;
- + }
- + }
- +#endif /* NFS41_DRIVER_WS2022_HACKS */
- + if (isgroupacl) {
- + DPRINTF(ACLLVL2,
- + ("convert_nfs4acl_2_dacl: aces[%d].who='%s': "
- + "Setting group flag\n",
- + nfs_i, curr_nfsace->who));
- + }
- +
- + status = map_nfs4servername_2_sid(nfs41dg,
- + (isgroupacl?GROUP_SECURITY_INFORMATION:OWNER_SECURITY_INFORMATION),
- + &sid_len, &sids[win_i], curr_nfsace->who);
- + if (status) {
- + free_sids(sids, win_i);
- + goto out;
- + }
- + }
- + size += sid_len - sizeof(DWORD);
- +
- + win_i++;
- + }
- + size += sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)*win_i);
- + size = align8(size); /* align size on |DWORD| boundry */
- + dacl = malloc(size);
- + if (dacl == NULL)
- + goto out_free_sids;
- +
- + if (InitializeAcl(dacl, size, ACL_REVISION)) {
- + ACCESS_MASK mask;
- + DWORD win_aceflags;
- +
- + for (nfs_i = win_i = 0; nfs_i < acl->count; nfs_i++) {
- + nfsace4 *curr_nfsace = &acl->aces[nfs_i];
- +
- + if (skip_aces[nfs_i])
- + continue;
- +
- + map_nfs4aceflags2winaceflags(curr_nfsace->aceflag,
- + &win_aceflags);
- + map_nfs4acemask2winaccessmask(curr_nfsace->acemask,
- + file_type, named_attr_support, &mask);
- +
- + if (DPRINTF_LEVEL_ENABLED(ACLLVL1)) {
- + dprintf_out("nfs2win: acl->aces[%d].who='%s': "
- + "acetype='%s', "
- + "nfs_acemask=0x%lx, win_mask=0x%lx, "
- + "win_aceflags=0x%lx\n",
- + nfs_i, curr_nfsace->who,
- + map_nfs_acetype2str(curr_nfsace->acetype),
- + (long)curr_nfsace->acemask,
- + (long)mask,
- + (long)win_aceflags);
- +
- + print_nfs_access_mask(curr_nfsace->who,
- + curr_nfsace->acemask);
- + print_windows_access_mask(curr_nfsace->who, mask);
- + }
- +
- + if (curr_nfsace->acetype == ACE4_ACCESS_ALLOWED_ACE_TYPE) {
- + status = AddAccessAllowedAceEx(dacl, ACL_REVISION,
- + win_aceflags, mask, sids[win_i]);
- + if (!status) {
- + eprintf("convert_nfs4acl_2_dacl: "
- + "AddAccessAllowedAceEx"
- + "(dacl=0x%p,win_aceflags=0x%x,mask=0x%x,who='%s') "
- + "failed with lasterr=%d\n",
- + dacl, (int)win_aceflags, (int)mask,
- + curr_nfsace->who, (int)GetLastError());
- + status = ERROR_INTERNAL_ERROR;
- + goto out_free_dacl;
- + }
- + status = ERROR_SUCCESS;
- + } else if (curr_nfsace->acetype == ACE4_ACCESS_DENIED_ACE_TYPE) {
- + status = AddAccessDeniedAceEx(dacl, ACL_REVISION,
- + win_aceflags, mask, sids[win_i]);
- + if (!status) {
- + eprintf("convert_nfs4acl_2_dacl: "
- + "AddAccessDeniedAceEx"
- + "(dacl=0x%p,win_aceflags=0x%x,mask=0x%x,who='%s') "
- + "failed with lasterr=%d\n",
- + dacl, (int)win_aceflags, (int)mask,
- + curr_nfsace->who, (int)GetLastError());
- + status = ERROR_INTERNAL_ERROR;
- + goto out_free_dacl;
- + }
- + status = ERROR_SUCCESS;
- + } else {
- + eprintf("convert_nfs4acl_2_dacl: unknown acetype %d\n",
- + curr_nfsace->acetype);
- + status = ERROR_INTERNAL_ERROR;
- + free(dacl);
- + free_sids(sids, win_i);
- + goto out;
- + }
- +
- + win_i++;
- + }
- + } else {
- + eprintf("convert_nfs4acl_2_dacl: InitializeAcl failed with %d\n", status);
- + goto out_free_dacl;
- + }
- + status = ERROR_SUCCESS;
- + *sids_out = sids;
- + *dacl_out = dacl;
- +out:
- + DPRINTF(ACLLVL2, ("<-- convert_nfs4acl_2_dacl("
- + "acl=0x%p,file_type='%s'(=%d)) returning %d\n",
- + acl, map_nfs_ftype2str(file_type), file_type, status));
- + return status;
- +out_free_dacl:
- + free(dacl);
- +out_free_sids:
- + free_sids(sids, win_i);
- + status = GetLastError();
- + goto out;
- +}
- +
- +static int is_well_known_sid(PSID sid, char *who, SID_NAME_USE *snu_out)
- +{
- + const WELL_KNOWN_SID_TYPE test_types[] = {
- + WinCreatorOwnerSid,
- + WinCreatorGroupSid,
- + WinBuiltinUsersSid,
- + WinNullSid,
- + WinAnonymousSid,
- + WinWorldSid,
- + WinAuthenticatedUserSid,
- + WinDialupSid,
- + WinNetworkSid,
- + WinBatchSid,
- + WinInteractiveSid,
- + WinNetworkServiceSid,
- + WinLocalServiceSid,
- + WinServiceSid
- + };
- + const size_t test_types_count = ARRAYSIZE(test_types);
- +
- + BOOL ismatch;
- + size_t i;
- +
- +#ifdef _DEBUG
- + static bool once = true;
- +
- + if (once) {
- + once = false;
- + EASSERT(test_types_count == 14);
- + /* Safeguards if someone tampers with the #defines for this */
- + EASSERT(strlen(ACE4_OWNER) == ACE4_OWNER_LEN);
- + EASSERT(strlen(ACE4_GROUP) == ACE4_GROUP_LEN);
- + EASSERT(strlen(ACE4_NOBODY) == ACE4_NOBODY_LEN);
- + EASSERT(strlen(ACE4_ANONYMOUS) == ACE4_ANONYMOUS_LEN);
- + EASSERT(strlen(ACE4_EVERYONE) == ACE4_EVERYONE_LEN);
- + }
- +#endif /* _DEBUG */
- +
- + for (i = 0; i < test_types_count ; i++) {
- + WELL_KNOWN_SID_TYPE tt = test_types[i];
- +
- + ismatch = IsWellKnownSid(sid, tt);
- + if (!ismatch) {
- + continue;
- + }
- +
- + DPRINTF(ACLLVL3, ("WELL_KNOWN_SID_TYPE=%d\n", (int)tt));
- + switch(tt) {
- + case WinCreatorOwnerSid:
- + (void)memcpy(who, ACE4_OWNER, ACE4_OWNER_LEN+1);
- + *snu_out = SidTypeUser;
- + return TRUE;
- + case WinCreatorGroupSid:
- + case WinBuiltinUsersSid:
- + (void)memcpy(who, ACE4_GROUP, ACE4_GROUP_LEN+1);
- + *snu_out = SidTypeGroup;
- + return TRUE;
- + case WinNullSid:
- + (void)memcpy(who, ACE4_NOBODY, ACE4_NOBODY_LEN+1);
- + *snu_out = SidTypeUser;
- + return TRUE;
- + case WinAnonymousSid:
- + (void)memcpy(who, ACE4_ANONYMOUS, ACE4_ANONYMOUS_LEN+1);
- + return TRUE;
- + case WinWorldSid:
- + (void)memcpy(who, ACE4_EVERYONE, ACE4_EVERYONE_LEN+1);
- + *snu_out = SidTypeGroup;
- + return TRUE;
- + case WinAuthenticatedUserSid:
- + (void)memcpy(who, ACE4_AUTHENTICATED, ACE4_AUTHENTICATED_LEN+1);
- + return TRUE;
- + case WinDialupSid:
- + (void)memcpy(who, ACE4_DIALUP, ACE4_DIALUP_LEN+1);
- + return TRUE;
- + case WinNetworkSid:
- + (void)memcpy(who, ACE4_NETWORK, ACE4_NETWORK_LEN+1);
- + return TRUE;
- + case WinBatchSid:
- + (void)memcpy(who, ACE4_BATCH, ACE4_BATCH_LEN+1);
- + return TRUE;
- + case WinInteractiveSid:
- + (void)memcpy(who, ACE4_INTERACTIVE, ACE4_INTERACTIVE_LEN+1);
- + return TRUE;
- + case WinNetworkServiceSid:
- + case WinLocalServiceSid:
- + case WinServiceSid:
- + (void)memcpy(who, ACE4_SERVICE, ACE4_SERVICE_LEN+1);
- + return TRUE;
- + default:
- + eprintf("is_well_known_sid: unknown tt=%d\n", (int)tt);
- + return FALSE;
- + }
- + }
- + return FALSE;
- +}
- +
- +static void map_winace2nfs4aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags)
- +{
- + *nfs4_aceflags = 0;
- +
- + if (win_aceflags & OBJECT_INHERIT_ACE)
- + *nfs4_aceflags |= ACE4_FILE_INHERIT_ACE;
- + if (win_aceflags & CONTAINER_INHERIT_ACE)
- + *nfs4_aceflags |= ACE4_DIRECTORY_INHERIT_ACE;
- + if (win_aceflags & NO_PROPAGATE_INHERIT_ACE)
- + *nfs4_aceflags |= ACE4_NO_PROPAGATE_INHERIT_ACE;
- + if (win_aceflags & INHERIT_ONLY_ACE)
- + *nfs4_aceflags |= ACE4_INHERIT_ONLY_ACE;
- + if (win_aceflags & INHERITED_ACE)
- + *nfs4_aceflags |= ACE4_INHERITED_ACE;
- + DPRINTF(ACLLVL3,
- + ("map_winace2nfs4aceflags: win_aceflags=0x%x nfs4_aceflags=0x%x\n",
- + (int)win_aceflags, (int)*nfs4_aceflags));
- +}
- +
- +static void map_nfs4aceflags2winaceflags(uint32_t nfs4_aceflags, DWORD *win_aceflags)
- +{
- + *win_aceflags = 0;
- +
- + if (nfs4_aceflags & ACE4_FILE_INHERIT_ACE)
- + *win_aceflags |= OBJECT_INHERIT_ACE;
- + if (nfs4_aceflags & ACE4_DIRECTORY_INHERIT_ACE)
- + *win_aceflags |= CONTAINER_INHERIT_ACE;
- + if (nfs4_aceflags & ACE4_NO_PROPAGATE_INHERIT_ACE)
- + *win_aceflags |= NO_PROPAGATE_INHERIT_ACE;
- + if (nfs4_aceflags & ACE4_INHERIT_ONLY_ACE)
- + *win_aceflags |= INHERIT_ONLY_ACE;
- + if (nfs4_aceflags & ACE4_INHERITED_ACE)
- + *win_aceflags |= INHERITED_ACE;
- + DPRINTF(ACLLVL3,
- + ("map_nfs4aceflags2winace: nfs4_aceflags=0x%x win_aceflags=0x%x\n",
- + (int)nfs4_aceflags, (int)*win_aceflags));
- +}
- +
- +static
- +void map_winaccessmask2nfs4acemask(ACCESS_MASK win_mask,
- + int file_type, bool named_attr_support, uint32_t *nfs4_mask)
- +{
- + *nfs4_mask = 0;
- +
- + /* check if any GENERIC bits set */
- + if (win_mask & 0xf000000) {
- + /* Filtered |ACE4_GENERIC_*| masks */
- + uint32_t ace4_generic_read_filt = ACE4_GENERIC_READ;
- + uint32_t ace4_generic_write_filt = ACE4_GENERIC_WRITE;
- + uint32_t ace4_generic_execute_filt = ACE4_GENERIC_EXECUTE;
- + uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
- + uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
- +
- +#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- + if (!named_attr_support) {
- + /*
- + * Filter out unsupported features for
- + * |GENERIC_*| --> |ACE_*ATTR| conversion.
- + * Do not filter out explicit individual flags below!
- + */
- + ace4_generic_read_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_generic_write_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_generic_execute_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
- + }
- +#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- +
- + if (win_mask & GENERIC_ALL) {
- + if (file_type == NF4DIR)
- + *nfs4_mask |= ace4_all_dir_filt;
- + else
- + *nfs4_mask |= ace4_all_file_filt;
- + } else {
- + if (win_mask & GENERIC_READ)
- + *nfs4_mask |= ace4_generic_read_filt;
- + if (win_mask & GENERIC_WRITE)
- + *nfs4_mask |= ace4_generic_write_filt;
- + if (win_mask & GENERIC_EXECUTE)
- + *nfs4_mask |= ace4_generic_execute_filt;
- + }
- + }
- +
- + /* Individual flags */
- + if (file_type == NF4DIR) {
- + if (win_mask & FILE_LIST_DIRECTORY) {
- + *nfs4_mask |= ACE4_LIST_DIRECTORY;
- + }
- + if (win_mask & FILE_ADD_FILE) {
- + *nfs4_mask |= ACE4_ADD_FILE;
- + }
- + if (win_mask & FILE_ADD_SUBDIRECTORY) {
- + *nfs4_mask |= ACE4_ADD_SUBDIRECTORY;
- + }
- + if (win_mask & FILE_DELETE_CHILD) {
- + *nfs4_mask |= ACE4_DELETE_CHILD;
- + }
- + if (win_mask & FILE_TRAVERSE) {
- + *nfs4_mask |= ACE4_EXECUTE;
- + }
- + }
- + else {
- + if (win_mask & FILE_READ_DATA) {
- + *nfs4_mask |= ACE4_READ_DATA;
- + }
- + if (win_mask & FILE_WRITE_DATA) {
- + *nfs4_mask |= ACE4_WRITE_DATA;
- + }
- + if (win_mask & FILE_APPEND_DATA) {
- + *nfs4_mask |= ACE4_APPEND_DATA;
- + }
- + if (win_mask & FILE_EXECUTE) {
- + *nfs4_mask |= ACE4_EXECUTE;
- + }
- + /*
- + * gisburn: Why does Win10 set |FILE_DELETE_CHILD| for
- + * plain files ?
- + */
- + if (win_mask & FILE_DELETE_CHILD) {
- + *nfs4_mask |= ACE4_DELETE_CHILD;
- + }
- + }
- +
- + if (win_mask & FILE_READ_EA) {
- + *nfs4_mask |= ACE4_READ_NAMED_ATTRS;
- + }
- + if (win_mask & FILE_WRITE_EA) {
- + *nfs4_mask |= ACE4_WRITE_NAMED_ATTRS;
- + }
- + if (win_mask & FILE_READ_ATTRIBUTES) {
- + *nfs4_mask |= ACE4_READ_ATTRIBUTES;
- + }
- + if (win_mask & FILE_WRITE_ATTRIBUTES) {
- + *nfs4_mask |= ACE4_WRITE_ATTRIBUTES;
- + }
- + if (win_mask & READ_CONTROL) {
- + *nfs4_mask |= ACE4_READ_ACL;
- + }
- + if (win_mask & WRITE_DAC) {
- + *nfs4_mask |= ACE4_WRITE_ACL;
- + }
- + if (win_mask & WRITE_OWNER) {
- + *nfs4_mask |= ACE4_WRITE_OWNER;
- + }
- + if (win_mask & SYNCHRONIZE) {
- + *nfs4_mask |= ACE4_SYNCHRONIZE;
- + }
- + if (win_mask & DELETE) {
- + *nfs4_mask |= ACE4_DELETE;
- + }
- +
- +#if 1
- + /* DEBUG: Compare old and new code */
- + DASSERT_MSG(0,
- + ((long)*nfs4_mask == (long)(win_mask & 0x00ffffff)),
- + ("map_winaccessmask2nfs4acemask: "
- + "new code nfs4_mask=0x%lx, "
- + "old code nfs4_mask=0x%lx\n",
- + (long)*nfs4_mask, (long)(win_mask & 0x00ffffff)));
- +#endif
- +}
- +
- +static
- +void map_nfs4acemask2winaccessmask(uint32_t nfs4_mask,
- + int file_type, bool named_attr_support, ACCESS_MASK *win_mask)
- +{
- + *win_mask = 0;
- +
- +#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- + bool is_generic = false;
- +
- + /* Filtered |ACE4_GENERIC_*| masks */
- + uint32_t ace4_generic_read_filt = ACE4_GENERIC_READ;
- + uint32_t ace4_generic_write_filt = ACE4_GENERIC_WRITE;
- + uint32_t ace4_generic_execute_filt = ACE4_GENERIC_EXECUTE;
- + uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
- + uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
- +
- + if (!named_attr_support) {
- + /*
- + * Filter out unsupported features for
- + * |ACE_*ATTR| --> |GENERIC_*| conversion.
- + * Do not filter out explicit individual flags below!
- + */
- + ace4_generic_read_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_generic_write_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_generic_execute_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
- + ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
- +
- +#ifdef WORKAROUND_FOR_LINUX_NFSD_NOT_SETTING_ACE4_WRITE_ATTRIBUTES
- + /*
- + * BUG(?): Linux 6.6.32-RT32 does not return
- + * |ACE4_WRITE_ATTRIBUTES| even when the attributes are
- + * writeable.
- + *
- + * Since |ACE4_GENERIC_WRITE| includes the
- + * |ACE4_WRITE_ATTRIBUTES| bit an attempt to set
- + * |GENERIC_WRITE| will succeed, but we can never get all
- + * the |ACE4_*| bits in |ACE4_GENERIC_WRITE| back when
- + * reading the ACL, so without this workaround we could
- + * never match |GENERIC_WRITE| when constructing the Win32
- + * ACLs.
- + *
- + * Testcase:
- + * ---- snip ----
- + * $ ksh93 -c 'rm -f test1.txt
- + * touch test1.txt
- + * icacls test1.txt /grant "siegfried_wulsch:(GW)"
- + * icacls test1.txt'
- + * ---- snip ----
- + * Second icacls should return "GW" for user "siegfried_wulsch".
- + */
- + ace4_generic_read_filt &= ~ACE4_WRITE_ATTRIBUTES;
- + ace4_generic_write_filt &= ~ACE4_WRITE_ATTRIBUTES;
- + ace4_generic_execute_filt &= ~ACE4_WRITE_ATTRIBUTES;
- + ace4_all_file_filt &= ~ACE4_WRITE_ATTRIBUTES;
- + ace4_all_dir_filt &= ~ACE4_WRITE_ATTRIBUTES;
- +#endif /* WORKAROUND_FOR_LINUX_NFSD_NOT_SETTING_ACE4_WRITE_ATTRIBUTES */
- + }
- +
- + /*
- + * Generic masks
- + * (|ACE4_GENERIC_*| contain multiple bits)
- + */
- +#define ACEMASK_TEST_MASK(value, mask) (((value)&(mask)) == (mask))
- + if (file_type == NF4DIR) {
- + if (ACEMASK_TEST_MASK(nfs4_mask, ace4_all_dir_filt)) {
- + *win_mask |= GENERIC_ALL;
- + is_generic = true;
- + }
- + }
- + else {
- + if (ACEMASK_TEST_MASK(nfs4_mask, ace4_all_file_filt)) {
- + *win_mask |= GENERIC_ALL;
- + is_generic = true;
- + }
- + }
- +
- + if (!(*win_mask & GENERIC_ALL)) {
- + if (ACEMASK_TEST_MASK(nfs4_mask, ace4_generic_read_filt)) {
- + *win_mask |= GENERIC_READ;
- + is_generic = true;
- + }
- + if (ACEMASK_TEST_MASK(nfs4_mask, ace4_generic_write_filt)) {
- + *win_mask |= GENERIC_WRITE;
- + is_generic = true;
- + }
- + if (ACEMASK_TEST_MASK(nfs4_mask, ace4_generic_execute_filt)) {
- + *win_mask |= GENERIC_EXECUTE;
- + is_generic = true;
- + }
- + }
- +#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- +
- + /* Individual flags */
- + if (file_type == NF4DIR) {
- + if (nfs4_mask & ACE4_LIST_DIRECTORY) {
- + *win_mask |= FILE_LIST_DIRECTORY;
- + }
- + if (nfs4_mask & ACE4_ADD_FILE) {
- + *win_mask |= FILE_ADD_FILE;
- + }
- + if (nfs4_mask & ACE4_ADD_SUBDIRECTORY) {
- + *win_mask |= FILE_ADD_SUBDIRECTORY;
- + }
- + if (nfs4_mask & ACE4_DELETE_CHILD) {
- + *win_mask |= FILE_DELETE_CHILD;
- + }
- + if (nfs4_mask & ACE4_EXECUTE) {
- + *win_mask |= FILE_TRAVERSE;
- + }
- + }
- + else {
- + if (nfs4_mask & ACE4_READ_DATA) {
- + *win_mask |= FILE_READ_DATA;
- + }
- + if (nfs4_mask & ACE4_WRITE_DATA) {
- + *win_mask |= FILE_WRITE_DATA;
- + }
- + if (nfs4_mask & ACE4_APPEND_DATA) {
- + *win_mask |= FILE_APPEND_DATA;
- + }
- + if (nfs4_mask & ACE4_EXECUTE) {
- + *win_mask |= FILE_EXECUTE;
- + }
- + }
- +
- + if (nfs4_mask & ACE4_READ_NAMED_ATTRS) {
- + *win_mask |= FILE_READ_EA;
- + }
- + if (nfs4_mask & ACE4_WRITE_NAMED_ATTRS) {
- + *win_mask |= FILE_WRITE_EA;
- + }
- + if (nfs4_mask & ACE4_READ_ATTRIBUTES) {
- + *win_mask |= FILE_READ_ATTRIBUTES;
- + }
- + if (nfs4_mask & ACE4_WRITE_ATTRIBUTES) {
- + *win_mask |= FILE_WRITE_ATTRIBUTES;
- + }
- + if (nfs4_mask & ACE4_READ_ACL) {
- + *win_mask |= READ_CONTROL;
- + }
- + if (nfs4_mask & ACE4_WRITE_ACL) {
- + *win_mask |= WRITE_DAC;
- + }
- + if (nfs4_mask & ACE4_WRITE_OWNER) {
- + *win_mask |= WRITE_OWNER;
- + }
- + if (nfs4_mask & ACE4_SYNCHRONIZE) {
- + *win_mask |= SYNCHRONIZE;
- + }
- + if (nfs4_mask & ACE4_DELETE) {
- + *win_mask |= DELETE;
- + }
- +
- +#if 1
- + /* DEBUG: Compare old and new code */
- +#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- + if (!is_generic)
- +#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- + {
- + DASSERT_MSG(0,
- + ((long)*win_mask == (long)(nfs4_mask /*& 0x00ffffff*/)),
- + ("#### map_nfs4acemask2winaccessmask: "
- + "new code win_mask=0x%lx, "
- + "old code win_mask=0x%lx\n",
- + (long)*win_mask, (long)(nfs4_mask /*& 0x00ffffff*/)));
- + }
- +#endif
- +}
- +
- +int map_sid2nfs4ace_who(PSID sid, PSID owner_sid, PSID group_sid,
- + char *who_out, char *domain, SID_NAME_USE *sid_type_out)
- +{
- + int status, lasterr;
- + SID_NAME_USE sid_type = 0;
- + /* |(UTF8_UNLEN+sizeof('\0'))*2| so we have space for user+domain */
- + char who_buf[(UTF8_UNLEN+1)*2];
- + char domain_buf[UTF8_UNLEN+1];
- + DWORD who_size = sizeof(who_buf), domain_size = sizeof(domain_buf);
- + LPSTR sidstr = NULL;
- +
- + DPRINTF(ACLLVL2, ("--> map_sid2nfs4ace_who("
- + "sid=0x%p,owner_sid=0x%p, group_sid=0x%p)\n",
- + sid, owner_sid, group_sid));
- +
- + if (DPRINTF_LEVEL_ENABLED(ACLLVL2)) {
- + print_sid("sid", sid);
- + print_sid("owner_sid", owner_sid);
- + print_sid("group_sid", group_sid);
- + }
- +
- + /* for ace mapping, we want to map owner's sid into "owner@"
- + * but for set_owner attribute we want to map owner into a user name
- + * same applies to group
- + */
- + status = 0;
- + if (owner_sid) {
- + if (EqualSid(sid, owner_sid)) {
- + DPRINTF(ACLLVL2, ("this is owner's sid\n"));
- + (void)memcpy(who_out, ACE4_OWNER, ACE4_OWNER_LEN+1);
- + sid_type = SidTypeUser;
- + status = ERROR_SUCCESS;
- + goto out;
- + }
- + }
- + if (group_sid) {
- + if (EqualSid(sid, group_sid)) {
- + DPRINTF(ACLLVL2, ("this is group's sid\n"));
- + memcpy(who_out, ACE4_GROUP, ACE4_GROUP_LEN+1);
- + sid_type = SidTypeGroup;
- + status = ERROR_SUCCESS;
- + goto out;
- + }
- + }
- + status = is_well_known_sid(sid, who_out, &sid_type);
- + if (status) {
- + if (!strncmp(who_out, ACE4_NOBODY, ACE4_NOBODY_LEN)) {
- + who_size = (DWORD)ACE4_NOBODY_LEN;
- + goto add_domain;
- + }
- +
- + /* fixme: What about |sid_type| ? */
- + status = ERROR_SUCCESS;
- + goto out;
- + }
- +
- + if (!ConvertSidToStringSidA(sid, &sidstr)) {
- + status = GetLastError();
- + eprintf("map_sid2nfs4ace_who: ConvertSidToStringSidA() "
- + "failed, error=%d\n", status);
- + goto out;
- + }
- +
- + status = lookupaccountsidutf8(NULL, sid, who_buf, &who_size, domain_buf,
- + &domain_size, &sid_type);
- + lasterr = GetLastError();
- +
- + if (status) {
- + DPRINTF(ACLLVL2, ("map_sid2nfs4ace_who: "
- + "LookupAccountSid(sidtostr(sid)='%s', who_buf='%s', "
- + "who_size=%d, domain='%s', domain_size=%d) "
- + "returned success, status=%d, GetLastError=%d\n",
- + sidstr, who_buf, who_size,
- + domain_buf, domain_size, status, lasterr));
- + }
- + else {
- + DPRINTF(ACLLVL2, ("map_sid2nfs4ace_who: "
- + "LookupAccountSid(sidtostr(sid)='%s', who_size=%d, "
- + "domain_size=%d) returned failure, status=%d, "
- + "GetLastError=%d\n",
- + sidstr, who_size, domain_size, status, lasterr));
- +
- + /*
- + * No SID to local account mapping. Can happen for some system
- + * SIDs, and Unix_User+<uid> or Unix_Group+<gid> SIDs
- + */
- + switch (lasterr) {
- + /*
- + * This happens for Unix_User+<uid> or Unix_Group+<gid>
- + * SIDs
- + */
- + case ERROR_NONE_MAPPED:
- + /*
- + * This can happen for two reasons:
- + * 1. Someone copied a file from a NFS(v3) filesystem,
- + * and Cygwin generated an Unix_User+<uid> or
- + * Unix_Group+<gid> SID for the source file, which
- + * tools like Cygwin cp(1) just copy.
- + * 2. We have an uid/gid for which we do not have
- + * a user-/group-name mapped.
- + */
- +#ifdef NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID
- + /* fixme: This should be a function argument */
- + extern nfs41_daemon_globals nfs41_dg;
- +
- + uid_t unixuser_uid = ~0U;
- + gid_t unixgroup_gid = ~0U;
- +
- + if (unixuser_sid2uid(sid, &unixuser_uid)) {
- + if (!nfs41_idmap_uid_to_name(nfs41_dg.idmapper,
- + unixuser_uid, who_out, UTF8_UNLEN)) {
- + who_size = (DWORD)strlen(who_out);
- + sid_type = SidTypeUser;
- + status = ERROR_SUCCESS;
- +
- + DPRINTF(ACLLVL1, ("map_sid2nfs4ace_who: "
- + "Unix_User+%d SID "
- + "mapped to user '%s'\n",
- + unixuser_uid, who_out));
- + goto add_domain;
- + }
- +
- + eprintf("map_sid2nfs4ace_who: "
- + "unixuser_sid2uid(sid='%s',unixuser_uid=%d) "
- + "returned no mapping.\n",
- + sidstr, (int)unixuser_uid);
- + goto err_none_mapped;
- + }
- +
- + if (unixgroup_sid2gid(sid, &unixgroup_gid)) {
- + if (!nfs41_idmap_gid_to_group(nfs41_dg.idmapper,
- + unixgroup_gid, who_out, UTF8_GNLEN)) {
- + who_size = (DWORD)strlen(who_out);
- + sid_type = SidTypeGroup;
- + status = ERROR_SUCCESS;
- +
- + DPRINTF(ACLLVL1, ("map_sid2nfs4ace_who: "
- + "Unix_Group+%d SID "
- + "mapped to group '%s'\n",
- + unixgroup_gid, who_out));
- + goto add_domain;
- + }
- +
- + eprintf("map_sid2nfs4ace_who: "
- + "unixgroup_sid2gid(sid='%s',unixgroup_gid=%d) "
- + "returned no mapping.\n",
- + sidstr, (int)unixgroup_gid);
- + goto err_none_mapped;
- + }
- +
- + eprintf("map_sid2nfs4ace_who: lookupaccountsidutf8() "
- + "returned ERROR_NONE_MAPPED+no "
- + "Unix_@(User|Group)+ mapping for sidstr='%s'\n",
- + sidstr);
- +err_none_mapped:
- + status = ERROR_NONE_MAPPED;
- +#else
- + DPRINTF(ACLLVL2,
- + ("map_sid2nfs4ace_who: lookupaccountsidutf8() "
- + "returned ERROR_NONE_MAPPED for sidstr='%s'\n",
- + sidstr));
- + status = lasterr;
- + goto out;
- +#endif /* NFS41_DRIVER_FEATURE_MAP_UNMAPPED_USER_TO_UNIXUSER_SID */
- +
- + /* Catch other cases */
- + case ERROR_NO_SUCH_USER:
- + case ERROR_NO_SUCH_GROUP:
- + eprintf("map_sid2nfs4ace_who: lookupaccountsidutf8() "
- + "returned ERROR_NO_SUCH_@(USER|GROUP) for "
- + "sidstr='%s'\n",
- + sidstr);
- + status = lasterr;
- + goto out;
- + default:
- + eprintf("map_sid2nfs4ace_who: Internal error, "
- + "lookupaccountsidutf8() returned unexpected ERROR_%d "
- + "for sidstr='%s'\n",
- + status, sidstr);
- + status = ERROR_INTERNAL_ERROR;
- + goto out;
- + }
- + }
- +
- + (void)memcpy(who_out, who_buf, who_size);
- +add_domain:
- + /*
- + * Complain if we attempt to add a domain suffix to an UID/GID
- + * value
- + */
- + EASSERT(!isdigit(who_out[0]));
- +
- + char *wp;
- +
- + wp = mempcpy(who_out+who_size, "@", sizeof(char));
- +
- +#ifdef NFS41_DRIVER_WS2022_HACKS
- + /* Fixup |domain| for Windows Sever 2022 NFSv4.1 server */
- + if ((!strncmp(who_out, "Users@", (size_t)who_size+1)) ||
- + (!strncmp(who_out, "Administrators@", (size_t)who_size+1))) {
- + domain = "BUILTIN";
- + DPRINTF(1,
- + ("map_sid2nfs4ace_who: Fixup '%.*s' domain='%s'\n",
- + (int)who_size+1, who_out, domain));
- + }
- + else if (!strncmp(who_out, "SYSTEM@", (size_t)who_size+1)) {
- + domain = "NT AUTHORITY";
- + DPRINTF(1,
- + ("map_sid2nfs4ace_who: Fixup '%.*s' domain='%s'\n",
- + (int)who_size+1, who_out, domain));
- + }
- +#endif /* NFS41_DRIVER_WS2022_HACKS */
- + (void)memcpy(wp, domain, strlen(domain)+1);
- +
- +/* no_add_domain: */
- + status = ERROR_SUCCESS;
- +out:
- + if (status) {
- + DPRINTF(ACLLVL2,
- + ("<-- map_sid2nfs4ace_who() returns %d\n", status));
- + }
- + else {
- + DPRINTF(ACLLVL2,
- + ("<-- map_sid2nfs4ace_who(who_out='%s', sid_type='%s'/%d) "
- + "returns %d\n",
- + who_out,
- + map_SID_NAME_USE2str(sid_type), sid_type,
- + status));
- + if (sid_type_out) {
- + *sid_type_out = sid_type;
- + }
- + }
- + if (sidstr)
- + LocalFree(sidstr);
- + return status;
- +}
- +
- +int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
- + int file_type, bool named_attr_support, char *domain)
- +{
- + int status;
- + if (acl == NULL) {
- + DPRINTF(ACLLVL2, ("this is a NULL dacl: all access to an object\n"));
- + nfs4_acl->count = 1;
- + nfs4_acl->aces = calloc(1, sizeof(nfsace4));
- + if (nfs4_acl->aces == NULL) {
- + status = GetLastError();
- + goto out;
- + }
- + nfs4_acl->flag = 0;
- + (void)memcpy(nfs4_acl->aces->who, ACE4_EVERYONE, ACE4_EVERYONE_LEN+1);
- + nfs4_acl->aces->acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE;
- +
- + if (file_type == NF4DIR) {
- + uint32_t ace4_all_dir_filt = ACE4_ALL_DIR;
- +#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- + /* Filter out unsupported features */
- + if (!named_attr_support) {
- + ace4_all_dir_filt &= ~ACE4_RW_NAMED_ATTRS;
- + }
- +#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- + nfs4_acl->aces->acemask = ace4_all_dir_filt;
- + }
- + else {
- + uint32_t ace4_all_file_filt = ACE4_ALL_FILE;
- +#ifdef MAP_WIN32GENERIC2ACE4GENERIC
- + /* Filter out unsupported features */
- + if (!named_attr_support) {
- + ace4_all_file_filt &= ~ACE4_RW_NAMED_ATTRS;
- + }
- +#endif /* MAP_WIN32GENERIC2ACE4GENERIC */
- + nfs4_acl->aces->acemask = ace4_all_file_filt;
- + }
- + nfs4_acl->aces->aceflag = 0;
- + } else {
- + int win_i, nfs_i;
- + PACE_HEADER ace;
- + PBYTE tmp_pointer;
- + SID_NAME_USE who_sid_type = 0;
- + ACCESS_MASK win_mask;
- +
- + DPRINTF(ACLLVL2, ("NON-NULL dacl with %d ACEs\n", acl->AceCount));
- + if (DPRINTF_LEVEL_ENABLED(ACLLVL3)) {
- + print_hexbuf_no_asci("ACL\n",
- + (const unsigned char *)acl, acl->AclSize);
- + }
- +
- + nfs4_acl->aces = calloc(acl->AceCount, sizeof(nfsace4));
- + if (nfs4_acl->aces == NULL) {
- + status = GetLastError();
- + goto out;
- + }
- + nfs4_acl->flag = 0;
- + for (win_i = nfs_i = 0; win_i < acl->AceCount; win_i++) {
- + nfsace4 *curr_nfsace = &nfs4_acl->aces[nfs_i];
- + PSID ace_sid;
- +
- + status = GetAce(acl, win_i, (LPVOID *)&ace);
- + if (!status) {
- + status = GetLastError();
- + eprintf("map_dacl_2_nfs4acl: GetAce failed with %d\n", status);
- + goto out_free;
- + }
- + tmp_pointer = (PBYTE)ace;
- + if (DPRINTF_LEVEL_ENABLED(ACLLVL3)) {
- + print_hexbuf_no_asci("ACE\n",
- + (const unsigned char *)ace, ace->AceSize);
- + }
- + DPRINTF(ACLLVL3, ("ACE TYPE: 0x%x\n", ace->AceType));
- + if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE)
- + curr_nfsace->acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE;
- + else if (ace->AceType == ACCESS_DENIED_ACE_TYPE)
- + curr_nfsace->acetype = ACE4_ACCESS_DENIED_ACE_TYPE;
- + else {
- + eprintf("map_dacl_2_nfs4acl: unsupported ACE type %d\n",
- + ace->AceType);
- + status = ERROR_NOT_SUPPORTED;
- + goto out_free;
- + }
- +
- + tmp_pointer += sizeof(ACCESS_MASK) + sizeof(ACE_HEADER);
- + ace_sid = tmp_pointer;
- +
- +#ifdef NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES
- + if (IsWellKnownSid(ace_sid, WinNullSid)) {
- + /*
- + * Skip ACEs with SID==|WinNullSid|
- + *
- + * Cygwin generates artificial ACEs with SID user
- + * |WinNullSid| to encode permission information
- + * (see |CYG_ACE_ISBITS_TO_POSIX()| in
- + * Cygwin newlib-cygwin/winsup/cygwin/sec/acl.cc
- + *
- + * This assumes that the filesystem which stores
- + * the ACL data leaves them 1:1 intact - which is
- + * not the case for the Linux NFSv4.1 server
- + * (tested with Linux 6.6.32), which transforms the
- + * NFSv4.1 ACLs into POSIX ACLs at setacl time,
- + * and the POSIX ACLs back to NFSv4 ACLs at getacl
- + * time.
- + * And this lossy transformation screws-up Cygwin
- + * completly.
- + * The best we can do for now is to skip such
- + * ACEs, as we have no way to detect whether
- + * the NFS server supports full NFSv4 ACLs, or
- + * only POSIX ACLs disguised as NFSv4 ACLs.
- + */
- + DPRINTF(ACLLVL3, ("Skipping WinNullSid ACE, "
- + "win_i=%d nfs_i=%d\n", (int)win_i, (int)nfs_i));
- + continue;
- + }
- +#endif /* NFS41_DRIVER_ACLS_SETACL_SKIP_WINNULLSID_ACES */
- +
- + status = map_sid2nfs4ace_who(ace_sid, sid, gsid,
- + curr_nfsace->who, domain, &who_sid_type);
- + if (status)
- + goto out_free;
- +
- + win_mask = *(PACCESS_MASK)(ace + 1);
- +
- + map_winace2nfs4aceflags(ace->AceFlags,
- + &curr_nfsace->aceflag);
- + map_winaccessmask2nfs4acemask(win_mask,
- + file_type, named_attr_support,
- + &curr_nfsace->acemask);
- +
- + /*
- + * Clear |ACE4_INHERITED_ACE|
- + *
- + * (See RFC 8884 Section-6.2.1.4.1:
- + * ACE4_INHERITED_ACE
- + * Indicates that this ACE is inherited from a parent
- + * directory. A server that supports automatic inheritance
- + * will place this flag on any ACEs inherited from the
- + * parent directory when creating a new object.
- + * Client applications will use this to perform automatic
- + * inheritance. Clients and servers MUST clear this bit in
- + * the acl attribute; it may only be used in the dacl and
- + * sacl attributes.
- + * ---- snip ----
- + * )
- + *
- + * If we do not clear this bit Linux 6.6.32-RT32 nfsd
- + * will reject setting ACLs |NFS4ERR_ATTRNOTSUPP| via
- + * icacls(1win) if the parent directory has inheritance
- + * ACLs.
- + */
- + if (curr_nfsace->aceflag & ACE4_INHERITED_ACE) {
- + curr_nfsace->aceflag &= ~ACE4_INHERITED_ACE;
- + DPRINTF(ACLLVL3, ("clearning ACE4_INHERITED_ACE\n"));
- + }
- +
- + /*
- + * Treat |SidTypeAlias| as (local) group
- + *
- + * It seems that |LookupAccount*A()| will always return
- + * |SidTypeAlias| for local groups created with
- + * $ net localgroup cygwingrp1 /add #
- + *
- + * References:
- + * - https://stackoverflow.com/questions/39373188/lookupaccountnamew-returns-sidtypealias-but-expected-sidtypegroup
- + */
- + if ((who_sid_type == SidTypeGroup) ||
- + (who_sid_type == SidTypeAlias)) {
- + DPRINTF(ACLLVL3, ("map_dacl_2_nfs4acl: who_sid_type='%s': "
- + "aces[%d].who='%s': "
- + "setting group flag\n",
- + map_SID_NAME_USE2str(who_sid_type),
- + nfs_i, curr_nfsace->who));
- + curr_nfsace->aceflag |= ACE4_IDENTIFIER_GROUP;
- + }
- +
- + if (DPRINTF_LEVEL_ENABLED(ACLLVL1)) {
- + dprintf_out("win2nfs: nfs4_acl->aces[%d]=(who='%s', "
- + "acetype='%s', "
- + "aceflag='%s'/0x%lx, "
- + "acemask='%s'/0x%lx(=win_mask=0x%lx)), "
- + "who_sid_type='%s', "
- + "win_i=%d\n",
- + nfs_i,
- + curr_nfsace->who,
- + map_nfs_acetype2str(curr_nfsace->acetype),
- + nfs_aceflag2shortname(curr_nfsace->aceflag),
- + curr_nfsace->aceflag,
- + nfs_mask2shortname(curr_nfsace->acemask),
- + (long)curr_nfsace->acemask,
- + (long)win_mask,
- + map_SID_NAME_USE2str(who_sid_type),
- + (int)win_i);
- + if (DPRINTF_LEVEL_ENABLED(ACLLVL2)) {
- + print_windows_access_mask(curr_nfsace->who,
- + win_mask);
- + print_nfs_access_mask(curr_nfsace->who,
- + curr_nfsace->acemask);
- + }
- + }
- +
- + nfs_i++;
- + }
- +
- + nfs4_acl->count = nfs_i;
- + }
- + status = ERROR_SUCCESS;
- +out:
- + return status;
- +out_free:
- + free(nfs4_acl->aces);
- + goto out;
- +}
- diff --git a/daemon/aclutil.h b/daemon/aclutil.h
- new file mode 100644
- index 0000000..66b4f24
- --- /dev/null
- +++ b/daemon/aclutil.h
- @@ -0,0 +1,46 @@
- +/* NFSv4.1 client for Windows
- + * Copyright (C) 2012 The Regents of the University of Michigan
- + * Copyright (C) 2023-2025 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * Olga Kornievskaia <aglo@umich.edu>
- + * Casey Bodley <cbodley@umich.edu>
- + * Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * This library is free software; you can redistribute it and/or modify it
- + * under the terms of the GNU Lesser General Public License as published by
- + * the Free Software Foundation; either version 2.1 of the License, or (at
- + * your option) any later version.
- + *
- + * This library is distributed in the hope that it will be useful, but
- + * without any warranty; without even the implied warranty of merchantability
- + * or fitness for a particular purpose. See the GNU Lesser General Public
- + * License for more details.
- + *
- + * You should have received a copy of the GNU Lesser General Public License
- + * along with this library; if not, write to the Free Software Foundation,
- + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA
- + */
- +
- +#ifndef __NFS41_DAEMON_ACLUTIL_H__
- +#define __NFS41_DAEMON_ACLUTIL_H__ 1
- +
- +#include "nfs41_build_features.h"
- +#include "nfs41_daemon.h"
- +
- +/* |DPRINTF()| levels for acl logging */
- +#define ACLLVL1 1
- +#define ACLLVL2 2
- +#define ACLLVL3 3
- +
- +void free_sids(PSID *sids, int count);
- +int map_sid2nfs4ace_who(PSID sid, PSID owner_sid, PSID group_sid,
- + char *who_out, char *domain, SID_NAME_USE *sid_type_out);
- +void convert_nfs4name_2_user_domain(LPSTR nfs4name,
- + LPSTR *domain);
- +int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
- + nfsacl41 *acl, int file_type, PACL *dacl_out, PSID **sids_out,
- + bool named_attr_support);
- +int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
- + int file_type, bool named_attr_support, char *domain);
- +
- +#endif /* !__NFS41_DAEMON_ACLUTIL_H__ */
- diff --git a/daemon/open.c b/daemon/open.c
- index e010c55..9cfc28b 100644
- --- a/daemon/open.c
- +++ b/daemon/open.c
- @@ -27,6 +27,7 @@
- #include <strsafe.h>
- #include "nfs41_build_features.h"
- +#include "aclutil.h"
- #include "nfs41_ops.h"
- #include "nfs41_daemon.h"
- #include "delegation.h"
- @@ -807,12 +808,6 @@ out:
- }
- #endif /* NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES */
- -#ifdef NFS41_DRIVER_ALLOW_CREATEFILE_ACLS
- -/* FIXME: Move this into aclutils.h */
- -int map_dacl_2_nfs4acl(PACL acl, PSID sid, PSID gsid, nfsacl41 *nfs4_acl,
- - int file_type, bool named_attr_support, char *domain);
- -#endif /* NFS41_DRIVER_ALLOW_CREATEFILE_ACLS */
- -
- static int handle_open(void *daemon_context, nfs41_upcall *upcall)
- {
- int status = 0;
- --
- 2.51.0
- From 9600b8f7f1c7c7ec9220b7d6e0bbc89cf52a639b Mon Sep 17 00:00:00 2001
- From: Dan Shelton <dan.f.shelton@gmail.com>
- Date: Sat, 15 Nov 2025 15:25:57 +0100
- Subject: [PATCH 2/5] daemon: Fix arithmetic overflow
- Fix arithmetic overflow.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/lock.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/daemon/lock.c b/daemon/lock.c
- index 9bafb66..7265fd4 100644
- --- a/daemon/lock.c
- +++ b/daemon/lock.c
- @@ -305,7 +305,7 @@ retry_lock:
- DPRINTF(1,
- ("handle_lock(state->path.path='%s'): retry in %ldms\n",
- state->path.path, (long)poll_delay));
- - (void)delayxid(upcall->xid, 30+(poll_delay/1000));
- + (void)delayxid(upcall->xid, 30LL+((long long)poll_delay/1000LL));
- Sleep(poll_delay);
- goto retry_lock;
- --
- 2.51.0
- From 54e251b2b53b109dbb843d5f608dc6baa8e90e5f Mon Sep 17 00:00:00 2001
- From: Dan Shelton <dan.f.shelton@gmail.com>
- Date: Sat, 15 Nov 2025 15:49:19 +0100
- Subject: [PATCH 3/5] daemon: Fix printf()-style&co format argument warnings
- Fix printf()-style&co format argument warnings.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/idmap.c | 8 ++++----
- daemon/name_cache.c | 6 +++---
- 2 files changed, 7 insertions(+), 7 deletions(-)
- diff --git a/daemon/idmap.c b/daemon/idmap.c
- index 61fa576..031a840 100644
- --- a/daemon/idmap.c
- +++ b/daemon/idmap.c
- @@ -1156,8 +1156,8 @@ int nfs41_idmap_uid_to_name(
- if (FAILED(StringCchCopyA(name, len, user.username))) {
- status = ERROR_BUFFER_OVERFLOW;
- - eprintf("username buffer overflow: '%s' > %u\n",
- - user.username, len);
- + eprintf("username buffer overflow: '%s' > %lu\n",
- + user.username, (unsigned long)len);
- goto out;
- }
- @@ -1294,8 +1294,8 @@ int nfs41_idmap_gid_to_group(
- if (FAILED(StringCchCopyA(name, len, group.name))) {
- status = ERROR_BUFFER_OVERFLOW;
- - eprintf("group name buffer overflow: '%s' > %u\n",
- - group.name, len);
- + eprintf("group name buffer overflow: '%s' > %lu\n",
- + group.name, (unsigned long)len);
- goto out;
- }
- diff --git a/daemon/name_cache.c b/daemon/name_cache.c
- index 14afb14..3f301ef 100644
- --- a/daemon/name_cache.c
- +++ b/daemon/name_cache.c
- @@ -564,7 +564,7 @@ int icu_strcmpcoll(UCollator *coll, const char *str1, const char *str2, int32_t
- if (U_FAILURE(status)) {
- eprintf("icu_strcmpcoll: "
- "ucol_strcollUTF8(str1='%s',str2='%s') returned status='%s'\n",
- - u_errorName(status));
- + str1, str2, u_errorName(status));
- return -1;
- }
- @@ -579,7 +579,7 @@ int icu_strcmpcoll(UCollator *coll, const char *str1, const char *str2, int32_t
- eprintf("icu_strcmpcoll: "
- "ucol_strcollUTF8(str1='%s',str2='%s') returned unexpected result=0x%lx\n",
- - (long)result);
- + str1, str2, (long)result);
- return -1;
- }
- @@ -1240,7 +1240,7 @@ int nfs41_name_cache_insert(
- int status;
- DPRINTF(NCLVL1, ("--> nfs41_name_cache_insert('%.*s')\n",
- - name->name + name->len - path, path));
- + (unsigned int)(name->name + name->len - path), path));
- NC_SET_NAMECMP(caseinsensitivesearch);
- --
- 2.51.0
- From 641822e3866a872d522b422095bbb228d99cf794 Mon Sep 17 00:00:00 2001
- From: Dan Shelton <dan.f.shelton@gmail.com>
- Date: Sat, 15 Nov 2025 16:29:48 +0100
- Subject: [PATCH 4/5] sys: Remove unused _updowncall_entry.cattrs variable
- Remove unused _updowncall_entry.cattrs variable.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- sys/nfs41sys_driver.h | 1 -
- 1 file changed, 1 deletion(-)
- diff --git a/sys/nfs41sys_driver.h b/sys/nfs41sys_driver.h
- index bf5ebc0..1c327ab 100644
- --- a/sys/nfs41sys_driver.h
- +++ b/sys/nfs41sys_driver.h
- @@ -240,7 +240,6 @@ typedef struct _updowncall_entry {
- PSECURITY_DESCRIPTOR SdBuffer;
- #endif /* NFS41_DRIVER_ALLOW_CREATEFILE_ACLS */
- ULONG disp;
- - ULONG cattrs;
- LONG open_owner_id;
- DWORD mode;
- #ifdef NFS41_DRIVER_FEATURE_LOCAL_UIDGID_IN_NFSV3ATTRIBUTES
- --
- 2.51.0
- From 4dff4fadf58e935432b50bbebfe0a3723799233b Mon Sep 17 00:00:00 2001
- From: Roland Mainz <roland.mainz@nrubsig.org>
- Date: Sat, 15 Nov 2025 16:46:13 +0100
- Subject: [PATCH 5/5] daemon: Fix ACL data alignment in
- |convert_nfs4acl_2_dacl()|
- Fix ACL data alignment in |convert_nfs4acl_2_dacl()|, data should
- be |DWORD|-aligned per Windows spec, but |sizeof(DWORD)| == 4|,
- and not |8|.
- Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
- ---
- daemon/aclutil.c | 2 +-
- 1 file changed, 1 insertion(+), 1 deletion(-)
- diff --git a/daemon/aclutil.c b/daemon/aclutil.c
- index 57c1111..6724543 100644
- --- a/daemon/aclutil.c
- +++ b/daemon/aclutil.c
- @@ -213,7 +213,7 @@ int convert_nfs4acl_2_dacl(nfs41_daemon_globals *nfs41dg,
- win_i++;
- }
- size += sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)*win_i);
- - size = align8(size); /* align size on |DWORD| boundry */
- + size = align4(size); /* align size on |DWORD| boundry */
- dacl = malloc(size);
- if (dacl == NULL)
- goto out_free_sids;
- --
- 2.51.0
msnfs41client: Patches to move ACL code, warning cleanup+misc, 2025-11-15
Posted by Anonymous on Sat 15th Nov 2025 15:57
raw | new post
Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.
rovema.kpaste.net RSS