diff --git a/daemon/acl.c b/daemon/acl.c index ce062d1..d25ba1b 100644 --- a/daemon/acl.c +++ b/daemon/acl.c @@ -150,6 +150,7 @@ static int handle_getacl(nfs41_upcall *upcall) nfs41_file_info info; bitmap4 attr_request; LPSTR domain = NULL; + SECURITY_DESCRIPTOR sec_desc; // need to cache owner/group information XX ZeroMemory(&info, sizeof(info)); @@ -168,6 +169,13 @@ static int handle_getacl(nfs41_upcall *upcall) goto out; } + status = InitializeSecurityDescriptor(&sec_desc, SECURITY_DESCRIPTOR_REVISION); + if (!status) { + status = GetLastError(); + eprintf("handle_getacl: InitializeSecurityDescriptor failed with %d\n", status); + goto out; + } + args->osid_len = args->gsid_len = 0; if (args->query & OWNER_SECURITY_INFORMATION) { // parse user@domain. currently ignoring domain part XX @@ -177,6 +185,13 @@ static int handle_getacl(nfs41_upcall *upcall) status = map_name_2_sid(&args->osid_len, &args->osid, (LPSTR)info.owner); if (status) goto out; + status = SetSecurityDescriptorOwner(&sec_desc, args->osid, TRUE); + free(args->osid); + if (!status) { + status = GetLastError(); + 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); @@ -185,12 +200,45 @@ static int handle_getacl(nfs41_upcall *upcall) status = map_name_2_sid(&args->gsid_len, &args->gsid, (LPSTR)info.owner_group); if (status) goto out; + status = SetSecurityDescriptorGroup(&sec_desc, args->gsid, TRUE); + free(args->gsid); + if (!status) { + status = GetLastError(); + eprintf("handle_getacl: SetSecurityDescriptorGroup failed with %d\n", status); + goto out; + } } 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"); + 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 + status = ERROR_INTERNAL_ERROR; + goto out; + } + out: if (args->query & DACL_SECURITY_INFORMATION) { nfsacl41_free(info.acl); @@ -199,41 +247,16 @@ out: return status; } -static int marshall_acl(unsigned char **buffer, uint32_t *remaining, uint32_t sid_len, PSID sid) -{ - int status; - status = safe_write(buffer, remaining, &sid_len, sizeof(sid_len)); - if (status) goto out; - if (*remaining < sid_len) - return ERROR_BUFFER_OVERFLOW; - status = CopySid(sid_len, *buffer, sid); - free(sid); - if (!status) { - status = GetLastError(); - dprintf(1, "marshall_acl: CopySid failed %d\n", status); - goto out; - } else { - status = 0; - *buffer += sid_len; - *remaining -= sid_len; - } -out: - return status; -} - 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; - if (args->query & OWNER_SECURITY_INFORMATION) { - status = marshall_acl(&buffer, length, args->osid_len, args->osid); - if (status) goto out; - } - if (args->query & GROUP_SECURITY_INFORMATION) { - status = marshall_acl(&buffer, length, args->gsid_len, args->gsid); - if (status) goto out; - } + status = safe_write(&buffer, length, &args->sec_desc_len, sizeof(DWORD)); + if (status) goto out; + status = safe_write(&buffer, length, args->sec_desc, args->sec_desc_len); + free(args->sec_desc); + if (status) goto out; out: return status; } diff --git a/daemon/upcall.h b/daemon/upcall.h index 5d73abf..87d1607 100644 --- a/daemon/upcall.h +++ b/daemon/upcall.h @@ -164,6 +164,8 @@ typedef struct __getacl_upcall_args { DWORD osid_len; PSID gsid; DWORD gsid_len; + PSECURITY_DESCRIPTOR sec_desc; + DWORD sec_desc_len; } getacl_upcall_args; typedef struct __setacl_upcall_args { diff --git a/sys/nfs41_driver.c b/sys/nfs41_driver.c index 51ed41b..4a3e989 100644 --- a/sys/nfs41_driver.c +++ b/sys/nfs41_driver.c @@ -216,22 +216,13 @@ typedef struct _updowncall_entry { PVOID buf; LONG buf_len; } Volume; - struct { - HANDLE open_state; - HANDLE session; - SECURITY_INFORMATION query; - PVOID owner_buf; - LONG owner_buf_len; - PVOID owner_group_buf; - LONG owner_group_buf_len; - } QueryAcl; struct { HANDLE open_state; HANDLE session; SECURITY_INFORMATION query; PVOID buf; - LONG buf_len; - } SetAcl; + DWORD buf_len; + } Acl; } u; } nfs41_updowncall_entry; @@ -1131,15 +1122,15 @@ NTSTATUS marshal_nfs41_getacl(nfs41_updowncall_entry *entry, goto out; } - RtlCopyMemory(tmp, &entry->u.QueryAcl.session, sizeof(HANDLE)); + RtlCopyMemory(tmp, &entry->u.Acl.session, sizeof(HANDLE)); tmp += sizeof(HANDLE); - RtlCopyMemory(tmp, &entry->u.QueryAcl.open_state, sizeof(HANDLE)); + RtlCopyMemory(tmp, &entry->u.Acl.open_state, sizeof(HANDLE)); tmp += sizeof(HANDLE); - RtlCopyMemory(tmp, &entry->u.QueryAcl.query, sizeof(SECURITY_INFORMATION)); + RtlCopyMemory(tmp, &entry->u.Acl.query, sizeof(SECURITY_INFORMATION)); *len = header_len; - DbgP("session=0x%x open_state=0x%x query=%d\n", entry->u.QueryAcl.session, - entry->u.QueryAcl.open_state, entry->u.QueryAcl.query); + DbgP("session=0x%x open_state=0x%x query=%d\n", entry->u.Acl.session, + entry->u.Acl.open_state, entry->u.Acl.query); out: DbgEx(); return status; @@ -1161,26 +1152,26 @@ NTSTATUS marshal_nfs41_setacl(nfs41_updowncall_entry *entry, else tmp += *len; header_len = *len + 2 * sizeof(HANDLE) + sizeof(SECURITY_INFORMATION) + - sizeof(ULONG) + entry->u.SetAcl.buf_len; + sizeof(ULONG) + entry->u.Acl.buf_len; if (header_len > buf_len) { status = STATUS_INSUFFICIENT_RESOURCES; goto out; } - RtlCopyMemory(tmp, &entry->u.SetAcl.session, sizeof(HANDLE)); + RtlCopyMemory(tmp, &entry->u.Acl.session, sizeof(HANDLE)); tmp += sizeof(HANDLE); - RtlCopyMemory(tmp, &entry->u.SetAcl.open_state, sizeof(HANDLE)); + RtlCopyMemory(tmp, &entry->u.Acl.open_state, sizeof(HANDLE)); tmp += sizeof(HANDLE); - RtlCopyMemory(tmp, &entry->u.SetAcl.query, sizeof(SECURITY_INFORMATION)); + RtlCopyMemory(tmp, &entry->u.Acl.query, sizeof(SECURITY_INFORMATION)); tmp += sizeof(SECURITY_INFORMATION); - RtlCopyMemory(tmp, &entry->u.SetAcl.buf_len, sizeof(ULONG)); - tmp += sizeof(ULONG); - RtlCopyMemory(tmp, entry->u.SetAcl.buf, entry->u.SetAcl.buf_len); + RtlCopyMemory(tmp, &entry->u.Acl.buf_len, sizeof(DWORD)); + tmp += sizeof(DWORD); + RtlCopyMemory(tmp, entry->u.Acl.buf, entry->u.Acl.buf_len); *len = header_len; DbgP("session=0x%x open_state=0x%x query=%d sec_desc_len=%d\n", - entry->u.SetAcl.session, entry->u.SetAcl.open_state, - entry->u.SetAcl.query, entry->u.SetAcl.buf_len); + entry->u.Acl.session, entry->u.Acl.open_state, + entry->u.Acl.query, entry->u.Acl.buf_len); out: DbgEx(); return status; @@ -1622,29 +1613,21 @@ nfs41_downcall ( RtlCopyMemory(cur->u.Volume.buf, buf, tmp->u.Volume.buf_len); break; case NFS41_ACL_QUERY: - if (cur->u.QueryAcl.query & OWNER_SECURITY_INFORMATION) { - RtlCopyMemory(&tmp->u.QueryAcl.owner_buf_len, buf, sizeof(LONG)); - buf += sizeof(LONG); - if (tmp->u.QueryAcl.owner_buf_len > cur->u.QueryAcl.owner_buf_len) { - cur->status = STATUS_BUFFER_TOO_SMALL; - cur->u.QueryAcl.owner_buf_len = tmp->u.QueryAcl.owner_buf_len; - break; + RtlCopyMemory(&tmp->u.Acl.buf_len, buf, sizeof(DWORD)); + buf += sizeof(DWORD); + if (tmp->u.Acl.buf_len > cur->u.Acl.buf_len) { + cur->status = STATUS_BUFFER_TOO_SMALL; + cur->u.Acl.buf_len = tmp->u.Acl.buf_len; + break; + } else { + cur->u.Acl.buf = RxAllocatePoolWithTag(NonPagedPool, + tmp->u.Acl.buf_len, NFS41_MM_POOLTAG); + if (cur->u.Acl.buf == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + goto out_free; } - cur->u.QueryAcl.owner_buf_len = tmp->u.QueryAcl.owner_buf_len; - RtlCopySid(cur->u.QueryAcl.owner_buf_len, cur->u.QueryAcl.owner_buf, buf); - buf += tmp->u.QueryAcl.owner_buf_len; - } - if (cur->u.QueryAcl.query & GROUP_SECURITY_INFORMATION) { - RtlCopyMemory(&tmp->u.QueryAcl.owner_group_buf_len, buf, sizeof(LONG)); - buf += sizeof(LONG); - if (tmp->u.QueryAcl.owner_group_buf_len > cur->u.QueryAcl.owner_group_buf_len) { - cur->status = STATUS_BUFFER_TOO_SMALL; - cur->u.QueryAcl.owner_group_buf_len = tmp->u.QueryAcl.owner_group_buf_len; - break; - } - cur->u.QueryAcl.owner_group_buf_len = tmp->u.QueryAcl.owner_group_buf_len; - RtlCopySid(cur->u.QueryAcl.owner_group_buf_len, cur->u.QueryAcl.owner_group_buf, buf); - buf += tmp->u.QueryAcl.owner_group_buf_len; + RtlCopyMemory(cur->u.Acl.buf, buf, tmp->u.Acl.buf_len); + cur->u.Acl.buf_len = tmp->u.Acl.buf_len; } break; } @@ -3778,7 +3761,6 @@ NTSTATUS nfs41_QuerySecurityInformation ( NFS41GetVNetRootExtension(SrvOpen->pVNetRoot); PNFS41_NETROOT_EXTENSION pNetRootContext = NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot); - BYTE owner_buf[SECURITY_MAX_SID_SIZE], group_buf[SECURITY_MAX_SID_SIZE]; SECURITY_INFORMATION info_class = RxContext->CurrentIrpSp->Parameters.QuerySecurity.SecurityInformation; @@ -3793,14 +3775,15 @@ NTSTATUS nfs41_QuerySecurityInformation ( status = nfs41_UpcallCreate(NFS41_ACL_QUERY, &nfs41_fobx->sec_ctx, &entry); if (status) goto out; - entry->u.QueryAcl.open_state = nfs41_fobx->nfs41_open_state; - entry->u.QueryAcl.session = pVNetRootContext->session; - entry->u.QueryAcl.query = info_class; - entry->u.QueryAcl.owner_buf = owner_buf; - entry->u.QueryAcl.owner_buf_len = SECURITY_MAX_SID_SIZE; - entry->u.QueryAcl.owner_group_buf = group_buf; - entry->u.QueryAcl.owner_group_buf_len = SECURITY_MAX_SID_SIZE; + entry->u.Acl.open_state = nfs41_fobx->nfs41_open_state; + entry->u.Acl.session = pVNetRootContext->session; + entry->u.Acl.query = info_class; entry->version = pNetRootContext->nfs41d_version; + /* we can't provide RxContext->CurrentIrp->UserBuffer to the upcall thread + * because it becomes an invalid pointer with that execution context + */ + entry->u.Acl.buf_len = RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length; + DbgP("security buffer len %d\n", entry->u.Acl.buf_len); if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) { status = STATUS_INTERNAL_ERROR; @@ -3808,76 +3791,35 @@ NTSTATUS nfs41_QuerySecurityInformation ( } if (entry->status == STATUS_BUFFER_TOO_SMALL) { - DbgP("nfs41_QuerySecurityInformation: our SID buffers are %d but we need %d\n", - SECURITY_MAX_SID_SIZE, entry->u.QueryFile.buf_len); - status = STATUS_INTERNAL_ERROR; + DbgP("nfs41_QuerySecurityInformation: provided buffer size=%d but we need %d\n", + RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length, + entry->u.Acl.buf_len); + status = STATUS_BUFFER_TOO_SMALL; + RxContext->InformationToReturn = entry->u.Acl.buf_len; } else if (entry->status == STATUS_SUCCESS) { - PSECURITY_DESCRIPTOR sec_desc = (PSECURITY_DESCRIPTOR) - RxContext->CurrentIrp->UserBuffer; - SECURITY_DESCRIPTOR tmp_sec_desc; - ULONG tmpLength = RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length; - status = RtlCreateSecurityDescriptor(&tmp_sec_desc, SECURITY_DESCRIPTOR_REVISION); - if (status) { - DbgP("RtlCreateSecurityDescriptor failed %x\n", status); - goto out_free; - } - if (entry->u.QueryAcl.query & OWNER_SECURITY_INFORMATION) { - PSID osid = (PSID)owner_buf; - if (RtlValidSid(osid)) { - status = RtlSetOwnerSecurityDescriptor(&tmp_sec_desc, osid, TRUE); - if (status) { - DbgP("RtlSetOwnerSecurityDescriptor returned %x\n", status); - goto out_free; - } - DbgP("added owner sid\n"); + if (RtlValidSecurityDescriptor(entry->u.Acl.buf)) { + DbgP("Received a valid security descriptor\n"); + if (MmIsAddressValid(RxContext->CurrentIrp->UserBuffer)) { + PSECURITY_DESCRIPTOR sec_desc = (PSECURITY_DESCRIPTOR) + RxContext->CurrentIrp->UserBuffer; + DbgP("Received a valid user pointer\n"); + RtlCopyMemory(sec_desc, entry->u.Acl.buf, entry->u.Acl.buf_len); } else { - DbgP("INVALID OWNER SID: adding NULL sid\n"); - status = RtlSetOwnerSecurityDescriptor(&tmp_sec_desc, NULL, TRUE); - if (status) { - DbgP("RtlSetOwnerSecurityDescriptor returned %x\n", status); - goto out_free; - } + DbgP("Received invalid user pointer\n"); + status = STATUS_INTERNAL_ERROR; } + } else { + DbgP("Received invalid security descriptor\n"); + status = STATUS_INTERNAL_ERROR; } - if (entry->u.QueryAcl.query & GROUP_SECURITY_INFORMATION) { - PSID gsid = (PSID)group_buf; - if (RtlValidSid(gsid)) { - status = RtlSetGroupSecurityDescriptor(&tmp_sec_desc, gsid, TRUE); - if (status) { - DbgP("RtlSetOwnerSecurityDescriptor returned %x\n", status); - goto out_free; - } - DbgP("adder group sid\n"); - } else { - DbgP("INVAID GROUP SID: adding NULL sid\n"); - status = RtlSetGroupSecurityDescriptor(&tmp_sec_desc, NULL, TRUE); - if (status) { - DbgP("RtlSetOwnerSecurityDescriptor returned %x\n", status); - goto out_free; - } - } - } - if (entry->u.QueryAcl.query & DACL_SECURITY_INFORMATION) - DbgP("handle_getacl: DACL_SECURITY_INFORMATION\n"); - if (entry->u.QueryAcl.query & SACL_SECURITY_INFORMATION) - DbgP("handle_getacl: SACL_SECURITY_INFORMATION\n"); - - status = RtlAbsoluteToSelfRelativeSD(&tmp_sec_desc, sec_desc, &tmpLength); - if (status) { - DbgP("RtlAbsoluteToSelfRelativeSD failed %x have %dbytes need %dbytes\n", - status, RxContext->CurrentIrpSp->Parameters.QuerySecurity.Length, tmpLength); - if (status == STATUS_BUFFER_TOO_SMALL) - RxContext->InformationToReturn = tmpLength; - goto out_free; - } - + RxFreePool(entry->u.Acl.buf); RxContext->IoStatusBlock.Information = RxContext->InformationToReturn = - RtlLengthSecurityDescriptor(sec_desc); - RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS; + entry->u.Acl.buf_len; + if (!status) + RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS; } else { status = map_query_acl_error(entry->status); } -out_free: RxFreePool(entry); out: DbgEx(); @@ -3924,11 +3866,11 @@ NTSTATUS nfs41_SetSecurityInformation ( status = nfs41_UpcallCreate(NFS41_ACL_SET, &nfs41_fobx->sec_ctx, &entry); if (status) goto out; - entry->u.SetAcl.open_state = nfs41_fobx->nfs41_open_state; - entry->u.SetAcl.session = pVNetRootContext->session; - entry->u.SetAcl.query = info_class; - entry->u.SetAcl.buf = sec_desc; - entry->u.SetAcl.buf_len = RtlLengthSecurityDescriptor(sec_desc); + entry->u.Acl.open_state = nfs41_fobx->nfs41_open_state; + entry->u.Acl.session = pVNetRootContext->session; + entry->u.Acl.query = info_class; + entry->u.Acl.buf = sec_desc; + entry->u.Acl.buf_len = RtlLengthSecurityDescriptor(sec_desc); entry->version = pNetRootContext->nfs41d_version; if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) {