diff --git a/daemon/acl.c b/daemon/acl.c index d25ba1b..eae529b 100644 --- a/daemon/acl.c +++ b/daemon/acl.c @@ -31,7 +31,8 @@ #include "upcall.h" #include "nfs41_xdr.h" -static int parse_getacl(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +static int parse_getacl(unsigned char *buffer, uint32_t length, + nfs41_upcall *upcall) { int status; getacl_upcall_args *args = &upcall->args.getacl; @@ -45,34 +46,42 @@ static int parse_getacl(unsigned char *buffer, uint32_t length, nfs41_upcall *up status = safe_read(&buffer, &length, &args->query, sizeof(args->query)); if (status) goto out; - dprintf(1, "parsing NFS41_ACL_QUERY: info_class=%d root=0x%p open_state=0x%p\n", - args->query, args->root, args->state); + dprintf(1, "parsing NFS41_ACL_QUERY: info_class=%d root=0x%p " + "open_state=0x%p\n", args->query, args->root, args->state); out: return status; } -static int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, DWORD *sid_len) +static int create_unknownsid(WELL_KNOWN_SID_TYPE type, PSID *sid, + DWORD *sid_len) { int status; *sid_len = 0; *sid = NULL; - if (!CreateWellKnownSid(type, NULL, *sid, sid_len)) { - status = GetLastError(); - if (status == ERROR_INSUFFICIENT_BUFFER) { - *sid = malloc(*sid_len); - if (*sid == NULL) return ERROR_INSUFFICIENT_BUFFER; - if (!CreateWellKnownSid(type, NULL, *sid, sid_len)) { - free(*sid); - status = GetLastError(); - dprintf(1, "CreateWellKnownSid failed with %d\n", status); - return status; - } else return 0; - } else return status; - } else return ERROR_INTERNAL_ERROR; + + status = CreateWellKnownSid(type, NULL, *sid, sid_len); + dprintf(1, "create_unknownsid: CreateWellKnownSid type %d returned %d " + "GetLastError %d sid len %d needed\n", type, status, + GetLastError(), *sid_len); + if (status) + return ERROR_INTERNAL_ERROR; + status = GetLastError(); + if (status != ERROR_INSUFFICIENT_BUFFER) + return status; + *sid = malloc(*sid_len); + if (*sid == NULL) + return ERROR_INSUFFICIENT_BUFFER; + status = CreateWellKnownSid(type, NULL, *sid, sid_len); + if (status) + return ERROR_SUCCESS; + free(*sid); + status = GetLastError(); + eprintf("create_unknownsid: CreateWellKnownSid failed with %d\n", status); + return status; } static void convert_nfs4name_2_user_domain(LPSTR nfs4name, - LPSTR *domain) + LPSTR *domain) { LPSTR p = nfs4name; for(; p[0] != '\0'; p++) { @@ -86,60 +95,178 @@ static void convert_nfs4name_2_user_domain(LPSTR nfs4name, static int map_name_2_sid(DWORD *sid_len, PSID *sid, LPCSTR name) { - int status; + int status = ERROR_INTERNAL_ERROR; SID_NAME_USE sid_type; LPSTR tmp_buf = NULL; DWORD tmp = 0; status = LookupAccountName(NULL, name, NULL, sid_len, NULL, &tmp, &sid_type); - dprintf(1, "LookupAccountName returned %d GetLastError %d owner len %d " - "domain len %d\n", status, GetLastError(), *sid_len, tmp); - if (!status) { - status = GetLastError(); - switch(status) { - case ERROR_INSUFFICIENT_BUFFER: - *sid = malloc(*sid_len); - if (*sid == NULL) { - status = GetLastError(); - goto out; - } - tmp_buf = (LPSTR) malloc(tmp); - if (tmp_buf == NULL) { - status = GetLastError(); - free(*sid); - goto out; - } - status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf, - &tmp, &sid_type); - dprintf(1, "sid_type = %d\n", sid_type); - free(tmp_buf); - if (!status) { - status = GetLastError(); - free(*sid); - dprintf(1, "handle_getacl: LookupAccountName for owner failed " - "with %d\n", status); - goto out; - } else { - LPSTR ssid = NULL; - if (IsValidSid(*sid)) - if (ConvertSidToStringSidA(*sid, &ssid)) - printf("SID %s\n", ssid); - else - printf("ConvertSidToStringSidA failed with %d\n", GetLastError()); - else - printf("Invalid Sid\n"); - if (ssid) LocalFree(ssid); - } - status = 0; - break; - case ERROR_NONE_MAPPED: - status = create_unknownsid(WinNullSid, sid, sid_len); - break; + dprintf(1, "map_name_2_sid: LookupAccountName for %s returned %d " + "GetLastError %d name len %d domain len %d\n", name, status, + GetLastError(), *sid_len, tmp); + if (status) + return ERROR_INTERNAL_ERROR; + + status = GetLastError(); + switch(status) { + case ERROR_INSUFFICIENT_BUFFER: + *sid = malloc(*sid_len); + if (*sid == NULL) { + status = GetLastError(); + goto out; } - } else // This shouldn't happen - status = ERROR_INTERNAL_ERROR; + tmp_buf = (LPSTR) malloc(tmp); + if (tmp_buf == NULL) + goto out_free_sid; + status = LookupAccountName(NULL, name, *sid, sid_len, tmp_buf, + &tmp, &sid_type); + free(tmp_buf); + if (!status) { + eprintf("map_name_2_sid: LookupAccountName for %s failed " + "with %d\n", name, GetLastError()); + goto out_free_sid; + } else { + LPSTR ssid = NULL; + if (IsValidSid(*sid)) + if (ConvertSidToStringSidA(*sid, &ssid)) + dprintf(1, "map_name_2_sid: sid_type = %d SID %s\n", + sid_type, ssid); + else + dprintf(1, "map_name_2_sid: ConvertSidToStringSidA failed " + "with %d\n", GetLastError()); + else + dprintf(1, "map_name_2_sid: Invalid Sid ?\n"); + if (ssid) LocalFree(ssid); + } + status = ERROR_SUCCESS; + break; + case ERROR_NONE_MAPPED: + status = create_unknownsid(WinNullSid, sid, sid_len); + if (status) + goto out_free_sid; + } out: return status; +out_free_sid: + status = GetLastError(); + free(*sid); + goto out; +} + +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(char *who, PSID *sid, DWORD *sid_len, + BOOLEAN *flag) +{ + int status = ERROR_SUCCESS; + WELL_KNOWN_SID_TYPE type = 0; + *flag = TRUE; + if (!strncmp(who, ACE4_OWNER, strlen(ACE4_OWNER)-1)) + type = WinCreatorOwnerSid; + else if (!strncmp(who, ACE4_GROUP, strlen(ACE4_GROUP)-1)) + type = WinCreatorGroupSid; + else if (!strncmp(who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)-1)) + type = WinWorldSid; + else if (!strncmp(who, ACE4_NOBODY, strlen(ACE4_NOBODY))) + type = WinNullSid; + else + *flag = FALSE; + if (*flag) + status = create_unknownsid(type, sid, sid_len); + return status; +} + +static int convert_nfs4acl_2_dacl(nfsacl41 *acl, int file_type, + PACL *dacl_out, PSID **sids_out) +{ + int status = ERROR_NOT_SUPPORTED, size = 0; + uint32_t i; + DWORD sid_len; + PSID *sids; + PACL dacl; + LPSTR domain = NULL; + BOOLEAN flag; + + sids = malloc(acl->count * sizeof(PSID)); + if (sids == NULL) { + status = GetLastError(); + goto out; + } + for (i = 0; i < acl->count; i++) { + convert_nfs4name_2_user_domain((LPSTR)acl->aces[i].who, &domain); + dprintf(1, "handle_getacl: for user=%s domain=%s\n", + acl->aces[i].who, domain?domain:""); + status = check_4_special_identifiers(acl->aces[i].who, &sids[i], + &sid_len, &flag); + if (status) { + free_sids(sids, i); + goto out; + } + if (!flag) { + status = map_name_2_sid(&sid_len, &sids[i], (LPSTR)acl->aces[i].who); + if (status) { + free_sids(sids, i); + goto out; + } + } + size += sid_len - sizeof(DWORD); + } + size += sizeof(ACL) + (sizeof(ACCESS_ALLOWED_ACE)*acl->count); + size = (size + sizeof(DWORD) - 1) & 0xfffffffc; //align size on word boundry + dacl = malloc(size); + if (dacl == NULL) + goto out_free_sids; + + if (InitializeAcl(dacl, size, ACL_REVISION)) { + ACCESS_MASK mask; + for (i = 0; i < acl->count; i++) { + // nfs4 acemask should be exactly the same as file access mask + mask = acl->aces[i].acemask; + if (acl->aces[i].acetype == ACE4_ACCESS_ALLOWED_ACE_TYPE) { + status = AddAccessAllowedAce(dacl, ACL_REVISION, mask, sids[i]); + if (!status) { + eprintf("convert_nfs4acl_2_dacl: AddAccessAllowedAce failed " + "with %d\n", status); + goto out_free_dacl; + } + else status = ERROR_SUCCESS; + } else if (acl->aces[i].acetype == ACE4_ACCESS_DENIED_ACE_TYPE) { + status = AddAccessDeniedAce(dacl, ACL_REVISION, mask, sids[i]); + if (!status) { + eprintf("convert_nfs4acl_2_dacl: AddAccessDeniedAce failed " + "with %d\n", status); + goto out_free_dacl; + } + else status = ERROR_SUCCESS; + } else { + eprintf("convert_nfs4acl_2_dacl: unknown acetype %d\n", + acl->aces[i].acetype); + status = ERROR_INTERNAL_ERROR; + free(dacl); + free_sids(sids, acl->count); + goto out; + } + } + } else { + eprintf("convert_nfs4acl_2_dacl: InitializeAcl failed with %d\n", status); + goto out_free_dacl; + } + *sids_out = sids; + *dacl_out = dacl; +out: + return status; +out_free_dacl: + free(dacl); +out_free_sids: + free_sids(sids, acl->count); + status = GetLastError(); + goto out; } static int handle_getacl(nfs41_upcall *upcall) @@ -151,6 +278,10 @@ static int handle_getacl(nfs41_upcall *upcall) bitmap4 attr_request; LPSTR domain = NULL; SECURITY_DESCRIPTOR sec_desc; + PACL dacl = NULL; + PSID *sids = NULL; + PSID osid = NULL, gsid = NULL; + DWORD sid_len; // need to cache owner/group information XX ZeroMemory(&info, sizeof(info)); @@ -165,89 +296,113 @@ static int handle_getacl(nfs41_upcall *upcall) } status = nfs41_getattr(state->session, &state->file, &attr_request, &info); if (status) { - eprintf("nfs41_cached_getattr() failed with %d\n", status); + eprintf("handle_getacl: nfs41_cached_getattr() failed with %d\n", + status); goto out; } - status = InitializeSecurityDescriptor(&sec_desc, SECURITY_DESCRIPTOR_REVISION); + status = InitializeSecurityDescriptor(&sec_desc, + SECURITY_DESCRIPTOR_REVISION); if (!status) { status = GetLastError(); - eprintf("handle_getacl: InitializeSecurityDescriptor failed with %d\n", status); + eprintf("handle_getacl: InitializeSecurityDescriptor failed with %d\n", + status); goto out; } - - args->osid_len = args->gsid_len = 0; + /* can't (re)use the same sid variable for both owner and group sids + * because security descriptor is created in absolute-form and it just + * stores pointers to the sids. thus each owner and group needs its own + * memory. free them after creating self-relative security descriptor. + */ if (args->query & OWNER_SECURITY_INFORMATION) { // parse user@domain. currently ignoring domain part XX convert_nfs4name_2_user_domain((LPSTR)info.owner, &domain); - dprintf(1, "handle_getacl: OWNER_SECURITY_INFORMATION: for user=%s domain=%s\n", - info.owner, domain?domain:""); - status = map_name_2_sid(&args->osid_len, &args->osid, (LPSTR)info.owner); + dprintf(1, "handle_getacl: OWNER_SECURITY_INFORMATION: for user=%s " + "domain=%s\n", info.owner, domain?domain:""); + sid_len = 0; + status = map_name_2_sid(&sid_len, &osid, (LPSTR)info.owner); if (status) goto out; - status = SetSecurityDescriptorOwner(&sec_desc, args->osid, TRUE); - free(args->osid); + status = SetSecurityDescriptorOwner(&sec_desc, osid, TRUE); if (!status) { status = GetLastError(); - eprintf("handle_getacl: SetSecurityDescriptorOwner failed with %d\n", status); + eprintf("handle_getacl: SetSecurityDescriptorOwner failed with " + "%d\n", status); goto out; } } if (args->query & GROUP_SECURITY_INFORMATION) { convert_nfs4name_2_user_domain((LPSTR)info.owner_group, &domain); - dprintf(1, "handle_getacl: GROUP_SECURITY_INFORMATION: for %s domain=%s\n", - info.owner_group, domain?domain:""); - status = map_name_2_sid(&args->gsid_len, &args->gsid, (LPSTR)info.owner_group); + dprintf(1, "handle_getacl: GROUP_SECURITY_INFORMATION: for %s " + "domain=%s\n", info.owner_group, domain?domain:""); + sid_len = 0; + status = map_name_2_sid(&sid_len, &gsid, (LPSTR)info.owner_group); if (status) goto out; - status = SetSecurityDescriptorGroup(&sec_desc, args->gsid, TRUE); - free(args->gsid); + status = SetSecurityDescriptorGroup(&sec_desc, gsid, TRUE); if (!status) { status = GetLastError(); - eprintf("handle_getacl: SetSecurityDescriptorGroup failed with %d\n", status); + eprintf("handle_getacl: SetSecurityDescriptorGroup failed with " + "%d\n", status); goto out; } } - if (args->query & DACL_SECURITY_INFORMATION) + if (args->query & DACL_SECURITY_INFORMATION) { dprintf(1, "handle_getacl: DACL_SECURITY_INFORMATION\n"); - if (args->query & SACL_SECURITY_INFORMATION) - dprintf(1, "handle_getacl: SACL_SECURITY_INFORMATION\n"); + status = convert_nfs4acl_2_dacl(info.acl, state->type, &dacl, &sids); + if (status) + goto out; + status = SetSecurityDescriptorDacl(&sec_desc, TRUE, dacl, TRUE); + if (!status) { + status = GetLastError(); + eprintf("handle_getacl: SetSecurityDescriptorDacl failed with " + "%d\n", status); + goto out; + } + } args->sec_desc_len = 0; status = MakeSelfRelativeSD(&sec_desc, args->sec_desc, &args->sec_desc_len); - if (!status) { - status = GetLastError(); - if (status == ERROR_INSUFFICIENT_BUFFER) { - args->sec_desc = malloc(args->sec_desc_len); - if (args->sec_desc == NULL) { - status = GetLastError(); - goto out; - } - status = MakeSelfRelativeSD(&sec_desc, args->sec_desc, &args->sec_desc_len); - if (!status) { - status = GetLastError(); - eprintf("handle_getacl: MakeSelfRelativeSD failes with %d\n", status); - free(args->sec_desc); - goto out; - } else status = 0; - } else { - eprintf("handle_getacl: MakeSelfRelativeSD failes with %d\n", status); - goto out; - } - } else { // this shouldn't happen + if (status) { status = ERROR_INTERNAL_ERROR; goto out; } + status = GetLastError(); + if (status != ERROR_INSUFFICIENT_BUFFER) { + eprintf("handle_getacl: MakeSelfRelativeSD failes with %d\n", status); + goto out; + } + args->sec_desc = malloc(args->sec_desc_len); + if (args->sec_desc == NULL) { + status = GetLastError(); + goto out; + } + status = MakeSelfRelativeSD(&sec_desc, args->sec_desc, &args->sec_desc_len); + if (!status) { + status = GetLastError(); + eprintf("handle_getacl: MakeSelfRelativeSD failes with %d\n", status); + free(args->sec_desc); + goto out; + } else status = ERROR_SUCCESS; out: + if (args->query & OWNER_SECURITY_INFORMATION) { + if (osid) free(osid); + } + if (args->query & GROUP_SECURITY_INFORMATION) { + if (gsid) free(gsid); + } if (args->query & DACL_SECURITY_INFORMATION) { + if (sids) free_sids(sids, info.acl->count); + free(dacl); nfsacl41_free(info.acl); free(info.acl); } return status; } -static int marshall_getacl(unsigned char *buffer, uint32_t *length, nfs41_upcall *upcall) +static int marshall_getacl(unsigned char *buffer, uint32_t *length, + nfs41_upcall *upcall) { int status = ERROR_NOT_SUPPORTED; getacl_upcall_args *args = &upcall->args.getacl; @@ -267,7 +422,8 @@ const nfs41_upcall_op nfs41_op_getacl = { marshall_getacl }; -static int parse_setacl(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall) +static int parse_setacl(unsigned char *buffer, uint32_t length, + nfs41_upcall *upcall) { int status; setacl_upcall_args *args = &upcall->args.setacl; @@ -297,8 +453,9 @@ static int parse_setacl(unsigned char *buffer, uint32_t length, nfs41_upcall *up goto out_free; } else status = 0; - dprintf(1, "parsing NFS41_ACL_SET: info_class=%d root=0x%p open_state=0x%p " - "sec_desc_len=%d\n", args->query, args->root, args->state, sec_desc_len); + dprintf(1, "parsing NFS41_ACL_SET: info_class=%d root=0x%p open_state=0x%p" + " sec_desc_len=%d\n", args->query, args->root, args->state, + sec_desc_len); out: return status; out_free: @@ -316,30 +473,41 @@ static int is_well_known_sid(PSID sid, char *who) dprintf(1, "WELL_KNOWN_SID_TYPE %d\n", i); switch((WELL_KNOWN_SID_TYPE)i) { case WinCreatorOwnerSid: - memcpy(who, ACE4_OWNER, strlen(ACE4_OWNER)+1); return TRUE; + memcpy(who, ACE4_OWNER, strlen(ACE4_OWNER)+1); + return TRUE; case WinNullSid: - memcpy(who, ACE4_NOBODY, strlen(ACE4_NOBODY)+1); return TRUE; + memcpy(who, ACE4_NOBODY, strlen(ACE4_NOBODY)+1); + return TRUE; case WinAnonymousSid: - memcpy(who, ACE4_ANONYMOUS, strlen(ACE4_ANONYMOUS)+1); return TRUE; + memcpy(who, ACE4_ANONYMOUS, strlen(ACE4_ANONYMOUS)+1); + return TRUE; case WinWorldSid: - memcpy(who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)+1); return TRUE; + memcpy(who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)+1); + return TRUE; case WinCreatorGroupSid: case WinBuiltinUsersSid: - memcpy(who, ACE4_GROUP, strlen(ACE4_GROUP)+1); return TRUE; + memcpy(who, ACE4_GROUP, strlen(ACE4_GROUP)+1); + return TRUE; case WinAuthenticatedUserSid: - memcpy(who, ACE4_AUTHENTICATED, strlen(ACE4_AUTHENTICATED)+1); return TRUE; + memcpy(who, ACE4_AUTHENTICATED, strlen(ACE4_AUTHENTICATED)+1); + return TRUE; case WinDialupSid: - memcpy(who, ACE4_DIALUP, strlen(ACE4_DIALUP)+1); return TRUE; + memcpy(who, ACE4_DIALUP, strlen(ACE4_DIALUP)+1); + return TRUE; case WinNetworkSid: - memcpy(who, ACE4_NETWORK, strlen(ACE4_NETWORK)+1); return TRUE; + memcpy(who, ACE4_NETWORK, strlen(ACE4_NETWORK)+1); + return TRUE; case WinBatchSid: - memcpy(who, ACE4_BATCH, strlen(ACE4_BATCH)+1); return TRUE; + memcpy(who, ACE4_BATCH, strlen(ACE4_BATCH)+1); + return TRUE; case WinInteractiveSid: - memcpy(who, ACE4_INTERACTIVE, strlen(ACE4_INTERACTIVE)+1); return TRUE; + memcpy(who, ACE4_INTERACTIVE, strlen(ACE4_INTERACTIVE)+1); + return TRUE; case WinNetworkServiceSid: case WinLocalServiceSid: case WinServiceSid: - memcpy(who, ACE4_SERVICE, strlen(ACE4_SERVICE)+1); return TRUE; + memcpy(who, ACE4_SERVICE, strlen(ACE4_SERVICE)+1); + return TRUE; default: return FALSE; } } @@ -359,151 +527,36 @@ static void map_aceflags(BYTE win_aceflags, uint32_t *nfs4_aceflags) *nfs4_aceflags |= ACE4_INHERIT_ONLY_ACE; if (win_aceflags & INHERITED_ACE) *nfs4_aceflags |= ACE4_INHERITED_ACE; - dprintf(1, "ACE FLAGS: %x nfs4 aceflags %x\n", win_aceflags, *nfs4_aceflags); -} - -static void set_ace4_read_data(ACCESS_MASK mask, int file_type, uint32_t *nfs4_mask) -{ - /* excluding STANDARD_RIGHTS_READ . winnt.h defines that as read_control which is acl/owner */ - /* excluding STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_ALL, SPECIFIC_RIGHTS_ALL, - * FILE_GENERIC_READ, FILE_ALL_ACCESS */ - if (mask & FILE_READ_DATA || mask & GENERIC_READ || mask & GENERIC_ALL /*|| - (mask & FILE_GENERIC_READ || mask & FILE_ALL_ACCESS)*/) - *nfs4_mask |= ACE4_READ_DATA; -} - -static void set_ace4_list_directory(ACCESS_MASK mask, int file_type, uint32_t *nfs4_mask) -{ - if (file_type == NF4DIR && (mask & FILE_TRAVERSE)) - *nfs4_mask |= ACE4_LIST_DIRECTORY; -} - -static void set_ace4_writeappend_data(ACCESS_MASK mask, int file_type, uint32_t *nfs4_mask) -{ - /* excluding STANDARD_RIGHTS_WRITE . winnt.h defines that as read_control which is acl/owner */ - /* excluding STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_ALL and SPECIFIC_RIGHTS_ALL, - * FILE_GENERIC_WRITE, FILE_ALL_ACCESS NEED IT ???*/ - if (mask & FILE_WRITE_DATA || mask & GENERIC_WRITE - || mask & GENERIC_ALL || mask & FILE_APPEND_DATA || - (mask & FILE_GENERIC_WRITE /*|| mask & FILE_ALL_ACCESS*/)) - *nfs4_mask |= ACE4_WRITE_DATA | ACE4_APPEND_DATA; -} - -static void set_ace4_read_named_attributes(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding FILE_GENERIC_READ, FILE_ALL_ACCESS, GENERIC_ALL */ - if (mask & FILE_READ_EA /*|| - (mask & FILE_GENERIC_READ || mask & FILE_ALL_ACCESS || mask & GENERIC_ALL)*/) - *nfs4_mask |= ACE4_READ_NAMED_ATTRS; -} - -static void set_ace4_write_named_attributes(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding FILE_GENERIC_WRITE, FILE_ALL_ACCESS, GENERIC_ALL */ - if (mask & FILE_WRITE_EA /*|| - (mask & FILE_GENERIC_WRITE || mask & FILE_ALL_ACCESS || mask & GENERIC_ALL)*/) - *nfs4_mask |= ACE4_WRITE_NAMED_ATTRS; -} - -static void set_ace4_execute(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding STANDARD_RIGHTS_EXECUTE . winnt.h defines that as read_control which is acl/owner */ - /* excluding STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_ALL and SPECIFIC_RIGHTS_ALL, - * FILE_GENERIC_EXECUTE, FILE_ALL_ACCESS NEED IT ???*/ - if (mask & FILE_EXECUTE || mask & GENERIC_EXECUTE || mask & GENERIC_ALL || - (mask & FILE_GENERIC_EXECUTE || mask & FILE_ALL_ACCESS)) - *nfs4_mask |= ACE4_EXECUTE; -} - -static void set_ace4_delete(ACCESS_MASK mask, int file_type, uint32_t *nfs4_mask) -{ - /* excluding FILE_ALL_ACCESS, GENERIC_ALL */ - if (mask & FILE_DELETE_CHILD || mask & DELETE || - mask & STANDARD_RIGHTS_REQUIRED || mask & STANDARD_RIGHTS_ALL || - mask & SPECIFIC_RIGHTS_ALL) - if (file_type == NF4DIR) - *nfs4_mask |= ACE4_DELETE_CHILD; - else - *nfs4_mask |= ACE4_DELETE; -} - -static void set_ace4_read_attributes(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_ALL and SPECIFIC_RIGHTS_ALL, - * FILE_GENERIC_READ, FILE_ALL_ACCESS, GENERIC_ALL*/ - if (mask & FILE_READ_ATTRIBUTES) - *nfs4_mask |= ACE4_READ_ATTRIBUTES; -} - -static void set_ace4_write_attributes(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding STANDARD_RIGHTS_REQUIRED, STANDARD_RIGHTS_ALL and SPECIFIC_RIGHTS_ALL, - * FILE_GENERIC_WRITE, FILE_ALL_ACCESS, GENERIC_ALL*/ - if (mask & FILE_WRITE_ATTRIBUTES) - *nfs4_mask |= ACE4_WRITE_ATTRIBUTES; -} - -static void set_ace4_read_acl(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding FILE_ALL_ACCESS */ - if (mask & READ_CONTROL || mask & STANDARD_RIGHTS_READ || - mask & STANDARD_RIGHTS_ALL || mask & SPECIFIC_RIGHTS_ALL || - mask & STANDARD_RIGHTS_REQUIRED) - *nfs4_mask |= ACE4_READ_ACL; -} - -static void set_ace4_write_acl(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding FILE_ALL_ACCESS */ - if (mask & WRITE_DAC || mask & STANDARD_RIGHTS_WRITE || - mask & STANDARD_RIGHTS_ALL || mask & SPECIFIC_RIGHTS_ALL || - mask & STANDARD_RIGHTS_REQUIRED) - *nfs4_mask |= ACE4_WRITE_ACL; -} - -static void set_ace4_write_owner(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding FILE_ALL_ACCESS */ - if (mask & WRITE_OWNER || mask & STANDARD_RIGHTS_WRITE || - mask & STANDARD_RIGHTS_ALL || mask & SPECIFIC_RIGHTS_ALL || - mask & STANDARD_RIGHTS_REQUIRED) - *nfs4_mask |= ACE4_WRITE_OWNER; -} - -static void set_ace4_synchronize(ACCESS_MASK mask, uint32_t *nfs4_mask) -{ - /* excluding FILE_GENERIC_READ, FILE_GENERIC_WRITE, FILE_GENERIC_EXECUTE, - * FILE_ALL_ACCESS */ - if (mask & SYNCHRONIZE || mask & STANDARD_RIGHTS_ALL || - mask & SPECIFIC_RIGHTS_ALL) - *nfs4_mask |= ACE4_SYNCHRONIZE; + dprintf(1, "ACE FLAGS: %x nfs4 aceflags %x\n", + win_aceflags, *nfs4_aceflags); } static void map_acemask(ACCESS_MASK mask, int file_type, uint32_t *nfs4_mask) { - /* 03/31/2011 NOT HANDLING LINKS */ - print_windows_access_mask(mask); - - set_ace4_read_data(mask, file_type, nfs4_mask); - set_ace4_list_directory(mask, file_type, nfs4_mask); - set_ace4_writeappend_data(mask, file_type, nfs4_mask); - set_ace4_read_named_attributes(mask, nfs4_mask); - set_ace4_write_named_attributes(mask, nfs4_mask); - set_ace4_execute(mask, nfs4_mask); - set_ace4_delete(mask, file_type, nfs4_mask); - set_ace4_read_attributes(mask, nfs4_mask); - set_ace4_write_attributes(mask, nfs4_mask); - set_ace4_read_acl(mask, nfs4_mask); - set_ace4_write_acl(mask, nfs4_mask); - set_ace4_write_owner(mask, nfs4_mask); - set_ace4_synchronize(mask, nfs4_mask); - - dprintf(1, "ACCESS MASK %d object type=%d nfs4 mask %x\n", - mask, file_type, *nfs4_mask); - print_nfs_access_mask(*nfs4_mask); + dprintf(1, "ACE MASK: %x\n", mask); + print_windows_access_mask(0, mask); + /* check if any GENERIC bits set */ + if (mask & 0xf000000) { + if (mask & GENERIC_ALL) { + if (file_type == NF4DIR) + *nfs4_mask |= ACE4_ALL_DIR; + else + *nfs4_mask |= ACE4_ALL_FILE; + } else { + if (mask & GENERIC_READ) + *nfs4_mask |= ACE4_GENERIC_READ; + if (mask & GENERIC_WRITE) + *nfs4_mask |= ACE4_GENERIC_WRITE; + if (mask & GENERIC_EXECUTE) + *nfs4_mask |= ACE4_GENERIC_EXECUTE; + } + } + else /* ignoring generic and reserved bits */ + *nfs4_mask = mask & 0x00ffffff; + print_nfs_access_mask(0, *nfs4_mask); } -static int map_who(PSID sid, char *who_out) +static int map_nfs4ace_who(PSID sid, PSID owner_sid, char *who_out, char *domain) { int status = ERROR_INTERNAL_ERROR; DWORD size = 0, tmp_size = 0; @@ -516,53 +569,63 @@ static int map_who(PSID sid, char *who_out) status = GetLastError(); goto out; } + if (EqualSid(sid, owner_sid)) { + dprintf(1, "map_nfs4ace_who: this is owner's sid\n"); + memcpy(who_out, ACE4_OWNER, strlen(ACE4_OWNER)+1); + return ERROR_SUCCESS; + } status = is_well_known_sid(sid, who_out); - if (status) - return 0; + if (status) { + if (!strncmp(who_out, ACE4_NOBODY, strlen(ACE4_NOBODY))) { + size = strlen(ACE4_NOBODY); + goto add_domain; + } + else + return ERROR_SUCCESS; + } + status = LookupAccountSid(NULL, sid, who, &size, tmp_buf, &tmp_size, &sid_type); - if (!status) { + dprintf(1, "map_nfs4ace_who: LookupAccountSid returned %d GetLastError " + "%d name len %d domain len %d\n", status, GetLastError(), + size, tmp_size); + if (status) + return ERROR_INTERNAL_ERROR; + status = GetLastError(); + if (status != ERROR_INSUFFICIENT_BUFFER) + return ERROR_INTERNAL_ERROR; + who = malloc(size); + if (who == NULL) { status = GetLastError(); - if (status == ERROR_INSUFFICIENT_BUFFER) { - who = malloc(size); - if (who == NULL) { - status = GetLastError(); - goto out; - } - tmp_buf = malloc(tmp_size); - if (tmp_buf == NULL) { - status = GetLastError(); - free(who); - goto out; - } - status = LookupAccountSid(NULL, sid, who, &size, tmp_buf, - &tmp_size, &sid_type); - free(tmp_buf); - if (!status) { - status = GetLastError(); - eprintf("map_dacl_2_nfs4acl: failed to lookup account name " - "for sid %d\n", status); - free(who); - goto out; - } - memcpy(who_out, who, size); - memcpy(who_out+size, "@citi.umich.edu", 15); - - free(who); - status = 0; - } else { - eprintf("map_dacl_2_nfs4acl: failed to lookup account name for " - "sid %d\n", status); - goto out; - } - } else { - dprintf(1, "this shouldn't happen\n"); goto out; } + tmp_buf = malloc(tmp_size); + if (tmp_buf == NULL) + goto out_free_who; + status = LookupAccountSid(NULL, sid, who, &size, tmp_buf, + &tmp_size, &sid_type); + free(tmp_buf); + if (!status) { + eprintf("map_nfs4ace_who: LookupAccountSid failed with %d\n", + GetLastError()); + goto out_free_who; + } + memcpy(who_out, who, size); +add_domain: + memcpy(who_out+size, "@", sizeof(char)); + memcpy(who_out+size+1, domain, strlen(domain)+1); + dprintf(1, "map_nfs4ace_who: who=%s\n", who_out); + if (who) free(who); + status = ERROR_SUCCESS; out: return status; +out_free_who: + free(who); + status = GetLastError(); + goto out; } -static int map_dacl_2_nfs4acl(PACL acl, nfsacl41 *nfs4_acl, int file_type) +static int map_dacl_2_nfs4acl(PACL acl, PSID sid, nfsacl41 *nfs4_acl, + int file_type, char *domain) { int status; if (acl == NULL) { @@ -576,7 +639,10 @@ static int map_dacl_2_nfs4acl(PACL acl, nfsacl41 *nfs4_acl, int file_type) nfs4_acl->flag = 0; memcpy(nfs4_acl->aces->who, ACE4_EVERYONE, strlen(ACE4_EVERYONE)+1); nfs4_acl->aces->acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE; - nfs4_acl->aces->acemask = ACE4_ALL; + if (file_type == NF4DIR) + nfs4_acl->aces->acemask = ACE4_ALL_DIR; + else + nfs4_acl->aces->acemask = ACE4_ALL_FILE; nfs4_acl->aces->aceflag = 0; } else { int i; @@ -584,7 +650,8 @@ static int map_dacl_2_nfs4acl(PACL acl, nfsacl41 *nfs4_acl, int file_type) PBYTE tmp_pointer; dprintf(1, "NON-NULL dacl with %d ACEs\n", acl->AceCount); - print_hexbuf_no_asci(3, (unsigned char *)"ACL\n", (unsigned char *)acl, acl->AclSize); + print_hexbuf_no_asci(3, (unsigned char *)"ACL\n", + (unsigned char *)acl, acl->AclSize); nfs4_acl->count = acl->AceCount; nfs4_acl->aces = calloc(nfs4_acl->count, sizeof(nfsace4)); if (nfs4_acl->aces == NULL) { @@ -596,10 +663,12 @@ static int map_dacl_2_nfs4acl(PACL acl, nfsacl41 *nfs4_acl, int file_type) status = GetAce(acl, i, &ace); if (!status) { status = GetLastError(); - goto out; + eprintf("map_dacl_2_nfs4acl: GetAce failed with %d\n", status); + goto out_free; } tmp_pointer = (PBYTE)ace; - print_hexbuf_no_asci(3, (unsigned char *)"ACE\n", (unsigned char *)ace, ace->AceSize); + print_hexbuf_no_asci(3, (unsigned char *)"ACE\n", + (unsigned char *)ace, ace->AceSize); dprintf(1, "ACE TYPE: %x\n", ace->AceType); if (ace->AceType == ACCESS_ALLOWED_ACE_TYPE) nfs4_acl->aces[i].acetype = ACE4_ACCESS_ALLOWED_ACE_TYPE; @@ -613,15 +682,17 @@ static int map_dacl_2_nfs4acl(PACL acl, nfsacl41 *nfs4_acl, int file_type) } map_aceflags(ace->AceFlags, &nfs4_acl->aces[i].aceflag); - map_acemask(*(PACCESS_MASK)(ace + 1), file_type, &nfs4_acl->aces[i].acemask); + map_acemask(*(PACCESS_MASK)(ace + 1), file_type, + &nfs4_acl->aces[i].acemask); tmp_pointer += sizeof(ACCESS_MASK) + sizeof(ACE_HEADER); - status = map_who(tmp_pointer, nfs4_acl->aces[i].who); + status = map_nfs4ace_who(tmp_pointer, sid, nfs4_acl->aces[i].who, + domain); if (status) goto out_free; } } - status = 0; + status = ERROR_SUCCESS; out: return status; out_free: @@ -645,17 +716,25 @@ static int handle_setacl(nfs41_upcall *upcall) if (args->query & GROUP_SECURITY_INFORMATION) dprintf(1, "handle_setacl: GROUP_SECURITY_INFORMATION\n"); if (args->query & DACL_SECURITY_INFORMATION) { - BOOL dacl_present, dacl_default; + BOOL dacl_present, dacl_default, sid_default; PACL acl; + PSID sid; dprintf(1, "handle_setacl: DACL_SECURITY_INFORMATION\n"); status = GetSecurityDescriptorDacl(args->sec_desc, &dacl_present, - &acl, &dacl_default); + &acl, &dacl_default); if (!status) { status = GetLastError(); eprintf("GetSecurityDescriptorDacl failed with %d\n", status); goto out; } - status = map_dacl_2_nfs4acl(acl, &nfs4_acl, state->type); + status = GetSecurityDescriptorOwner(args->sec_desc, &sid, &sid_default); + if (!status) { + status = GetLastError(); + eprintf("GetSecurityDescriptorOwner failed with %d\n", status); + goto out; + } + status = map_dacl_2_nfs4acl(acl, sid, &nfs4_acl, state->type, + state->session->client->domain_name); if (status) goto out; else { @@ -669,13 +748,11 @@ static int handle_setacl(nfs41_upcall *upcall) status = nfs41_setattr(state->session, &state->file, &stateid, &info); if (status) { dprintf(1, "handle_setacl: nfs41_setattr() failed with error %s.\n", - nfs_error_string(status)); + nfs_error_string(status)); status = nfs_to_windows_error(status, ERROR_NOT_SUPPORTED); } - if (args->query & DACL_SECURITY_INFORMATION) free(nfs4_acl.aces); - out: free(args->sec_desc); return status; diff --git a/daemon/upcall.h b/daemon/upcall.h index 87d1607..6ca03f6 100644 --- a/daemon/upcall.h +++ b/daemon/upcall.h @@ -160,10 +160,6 @@ typedef struct __getacl_upcall_args { nfs41_root *root; nfs41_open_state *state; SECURITY_INFORMATION query; - PSID osid; - DWORD osid_len; - PSID gsid; - DWORD gsid_len; PSECURITY_DESCRIPTOR sec_desc; DWORD sec_desc_len; } getacl_upcall_args;