first stab at handling security irp
Basic handling of owner and group security query (no dacl). Added new upcall for NFS41_ACL_QUERY (driver and daemon code). Daemon, upon getting NFS41_ACL_QUERY first places a getattr that has owner, group attribute request. We currently don't cache them!!! Then, we parse nfs4name format (ie user@domain or group@domain) into user and domain. We currently ignore domain part!!! Then, we assume that whatever we are mapping is "known" locally (ie LookupAccountName() api which retrieves a SID for a given name). Mapping from name to SID can only be done in the userland. We then copy the bytes via the upcall pipe to the kernel. If the received user or group cant be mapped via LookupAccoundName(), we create a well known null SID as the reply. Kernel creates a security descriptor in the absolute-format and adds owner and group sids to it. Important: RtlSetOwner/Group functions only work with absolute-format security descriptor, however the reply to the user needs to be in the self-relative format. The way security query works is that it passes us a buffer to be filled with the security context. However the user doesn't know how big the buffer should be so, the user is allowed to pass a null buffer and have the kernel return how much memory is needed. This leads to 2 security queries => 2 NFS41_ACL_QUERY upcalls => 2 getattr rpcs... It should be improved. TODO: - need to add caching of owner/group attributes for a file? - need to add calls to LDAP for more general mapping? - need to cache reply of the ACL if supplied length is 0?
This commit is contained in:
parent
d2ba08614c
commit
ab55e6e8c5
9 changed files with 440 additions and 1 deletions
|
|
@ -191,6 +191,7 @@
|
||||||
</Link>
|
</Link>
|
||||||
</ItemDefinitionGroup>
|
</ItemDefinitionGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<ClCompile Include="..\daemon\acl.c" />
|
||||||
<ClCompile Include="..\daemon\callback_xdr.c" />
|
<ClCompile Include="..\daemon\callback_xdr.c" />
|
||||||
<ClCompile Include="..\daemon\callback_server.c" />
|
<ClCompile Include="..\daemon\callback_server.c" />
|
||||||
<ClCompile Include="..\daemon\daemon_debug.c" />
|
<ClCompile Include="..\daemon\daemon_debug.c" />
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,9 @@
|
||||||
<ClCompile Include="..\daemon\idmap.c">
|
<ClCompile Include="..\daemon\idmap.c">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="..\daemon\acl.c">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="..\daemon\daemon_debug.h">
|
<ClInclude Include="..\daemon\daemon_debug.h">
|
||||||
|
|
|
||||||
232
daemon/acl.c
Normal file
232
daemon/acl.c
Normal file
|
|
@ -0,0 +1,232 @@
|
||||||
|
/* Copyright (c) 2010
|
||||||
|
* The Regents of the University of Michigan
|
||||||
|
* All Rights Reserved
|
||||||
|
*
|
||||||
|
* Permission is granted to use, copy and redistribute this software
|
||||||
|
* for noncommercial education and research purposes, so long as no
|
||||||
|
* fee is charged, and so long as the name of the University of Michigan
|
||||||
|
* is not used in any advertising or publicity pertaining to the use
|
||||||
|
* or distribution of this software without specific, written prior
|
||||||
|
* authorization. Permission to modify or otherwise create derivative
|
||||||
|
* works of this software is not granted.
|
||||||
|
*
|
||||||
|
* This software is provided as is, without representation or warranty
|
||||||
|
* of any kind either express or implied, including without limitation
|
||||||
|
* the implied warranties of merchantability, fitness for a particular
|
||||||
|
* purpose, or noninfringement. The Regents of the University of
|
||||||
|
* Michigan shall not be liable for any damages, including special,
|
||||||
|
* indirect, incidental, or consequential damages, with respect to any
|
||||||
|
* claim arising out of or in connection with the use of the software,
|
||||||
|
* even if it has been or is hereafter advised of the possibility of
|
||||||
|
* such damages.
|
||||||
|
*/
|
||||||
|
#include <Windows.h>
|
||||||
|
#include <strsafe.h>
|
||||||
|
#include <sddl.h>
|
||||||
|
|
||||||
|
#include "nfs41.h"
|
||||||
|
#include "nfs41_ops.h"
|
||||||
|
#include "daemon_debug.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "upcall.h"
|
||||||
|
|
||||||
|
static int parse_getacl(unsigned char *buffer, uint32_t length, nfs41_upcall *upcall)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
getacl_upcall_args *args = &upcall->args.getacl;
|
||||||
|
|
||||||
|
status = safe_read(&buffer, &length, &args->root, sizeof(HANDLE));
|
||||||
|
if (status) goto out;
|
||||||
|
upcall_root_ref(upcall, args->root);
|
||||||
|
status = safe_read(&buffer, &length, &args->state, sizeof(args->state));
|
||||||
|
if (status) goto out;
|
||||||
|
upcall_open_state_ref(upcall, args->state);
|
||||||
|
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);
|
||||||
|
out:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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 int map_name_2_sid(DWORD *sid_len, PSID *sid, LPCSTR name)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
} else // This shouldn't happen
|
||||||
|
status = ERROR_INTERNAL_ERROR;
|
||||||
|
out:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_getacl(nfs41_upcall *upcall)
|
||||||
|
{
|
||||||
|
int status = ERROR_NOT_SUPPORTED;
|
||||||
|
getacl_upcall_args *args = &upcall->args.getacl;
|
||||||
|
nfs41_open_state *state = args->state;
|
||||||
|
nfs41_file_info info;
|
||||||
|
bitmap4 attr_request;
|
||||||
|
LPSTR domain = NULL;
|
||||||
|
|
||||||
|
// need to cache owner/group information XX
|
||||||
|
ZeroMemory(&info, sizeof(info));
|
||||||
|
init_getattr_request(&attr_request);
|
||||||
|
status = nfs41_getattr(state->session, &state->file, &attr_request, &info);
|
||||||
|
if (status) {
|
||||||
|
eprintf("nfs41_cached_getattr() 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
|
||||||
|
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:"<null>");
|
||||||
|
status = map_name_2_sid(&args->osid_len, &args->osid, (LPSTR)info.owner);
|
||||||
|
if (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:"<null>");
|
||||||
|
status = map_name_2_sid(&args->gsid_len, &args->gsid, (LPSTR)info.owner_group);
|
||||||
|
if (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");
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
const nfs41_upcall_op nfs41_op_getacl = {
|
||||||
|
parse_getacl,
|
||||||
|
handle_getacl,
|
||||||
|
marshall_getacl
|
||||||
|
};
|
||||||
|
|
@ -281,6 +281,7 @@ const char* opcode2string(DWORD opcode)
|
||||||
case NFS41_EA_SET: return "NFS41_EA_SET";
|
case NFS41_EA_SET: return "NFS41_EA_SET";
|
||||||
case NFS41_SYMLINK: return "NFS41_SYMLINK";
|
case NFS41_SYMLINK: return "NFS41_SYMLINK";
|
||||||
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
|
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
|
||||||
|
case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY";
|
||||||
default: return "UNKNOWN";
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ extern const nfs41_upcall_op nfs41_op_setattr;
|
||||||
extern const nfs41_upcall_op nfs41_op_setexattr;
|
extern const nfs41_upcall_op nfs41_op_setexattr;
|
||||||
extern const nfs41_upcall_op nfs41_op_symlink;
|
extern const nfs41_upcall_op nfs41_op_symlink;
|
||||||
extern const nfs41_upcall_op nfs41_op_volume;
|
extern const nfs41_upcall_op nfs41_op_volume;
|
||||||
|
extern const nfs41_upcall_op nfs41_op_getacl;
|
||||||
|
|
||||||
static const nfs41_upcall_op *g_upcall_op_table[] = {
|
static const nfs41_upcall_op *g_upcall_op_table[] = {
|
||||||
&nfs41_op_mount,
|
&nfs41_op_mount,
|
||||||
|
|
@ -61,6 +62,7 @@ static const nfs41_upcall_op *g_upcall_op_table[] = {
|
||||||
&nfs41_op_setexattr,
|
&nfs41_op_setexattr,
|
||||||
&nfs41_op_symlink,
|
&nfs41_op_symlink,
|
||||||
&nfs41_op_volume,
|
&nfs41_op_volume,
|
||||||
|
&nfs41_op_getacl,
|
||||||
NULL,
|
NULL,
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -155,6 +155,16 @@ typedef struct __volume_upcall_args {
|
||||||
} info;
|
} info;
|
||||||
} volume_upcall_args;
|
} volume_upcall_args;
|
||||||
|
|
||||||
|
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;
|
||||||
|
} getacl_upcall_args;
|
||||||
|
|
||||||
typedef union __upcall_args {
|
typedef union __upcall_args {
|
||||||
mount_upcall_args mount;
|
mount_upcall_args mount;
|
||||||
unmount_upcall_args unmount;
|
unmount_upcall_args unmount;
|
||||||
|
|
@ -169,6 +179,7 @@ typedef union __upcall_args {
|
||||||
readdir_upcall_args readdir;
|
readdir_upcall_args readdir;
|
||||||
symlink_upcall_args symlink;
|
symlink_upcall_args symlink;
|
||||||
volume_upcall_args volume;
|
volume_upcall_args volume;
|
||||||
|
getacl_upcall_args getacl;
|
||||||
} upcall_args;
|
} upcall_args;
|
||||||
|
|
||||||
typedef struct __nfs41_upcall {
|
typedef struct __nfs41_upcall {
|
||||||
|
|
|
||||||
|
|
@ -613,6 +613,7 @@ const char *opcode2string(int opcode)
|
||||||
case NFS41_EA_SET: return "NFS41_EA_SET";
|
case NFS41_EA_SET: return "NFS41_EA_SET";
|
||||||
case NFS41_SYMLINK: return "NFS41_SYMLINK";
|
case NFS41_SYMLINK: return "NFS41_SYMLINK";
|
||||||
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
|
case NFS41_VOLUME_QUERY: return "NFS41_VOLUME_QUERY";
|
||||||
|
case NFS41_ACL_QUERY: return "NFS41_ACL_QUERY";
|
||||||
default: return "UNKNOWN";
|
default: return "UNKNOWN";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -216,6 +216,15 @@ typedef struct _updowncall_entry {
|
||||||
PVOID buf;
|
PVOID buf;
|
||||||
LONG buf_len;
|
LONG buf_len;
|
||||||
} Volume;
|
} 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;
|
||||||
} u;
|
} u;
|
||||||
|
|
||||||
} nfs41_updowncall_entry;
|
} nfs41_updowncall_entry;
|
||||||
|
|
@ -1088,6 +1097,41 @@ out:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS marshal_nfs41_getacl(nfs41_updowncall_entry *entry,
|
||||||
|
unsigned char *buf,
|
||||||
|
ULONG buf_len,
|
||||||
|
ULONG *len)
|
||||||
|
{
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
ULONG header_len = 0;
|
||||||
|
unsigned char *tmp = buf;
|
||||||
|
|
||||||
|
DbgEn();
|
||||||
|
status = marshal_nfs41_header(entry, tmp, buf_len, len);
|
||||||
|
if (status == STATUS_INSUFFICIENT_RESOURCES)
|
||||||
|
goto out;
|
||||||
|
else
|
||||||
|
tmp += *len;
|
||||||
|
header_len = *len + 2 * sizeof(HANDLE) + sizeof(SECURITY_INFORMATION);
|
||||||
|
if (header_len > buf_len) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
RtlCopyMemory(tmp, &entry->u.Volume.session, sizeof(HANDLE));
|
||||||
|
tmp += sizeof(HANDLE);
|
||||||
|
RtlCopyMemory(tmp, &entry->u.Volume.open_state, sizeof(HANDLE));
|
||||||
|
tmp += sizeof(HANDLE);
|
||||||
|
RtlCopyMemory(tmp, &entry->u.Volume.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);
|
||||||
|
out:
|
||||||
|
DbgEx();
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS marshal_nfs41_shutdown(nfs41_updowncall_entry *entry,
|
NTSTATUS marshal_nfs41_shutdown(nfs41_updowncall_entry *entry,
|
||||||
unsigned char *buf,
|
unsigned char *buf,
|
||||||
ULONG buf_len,
|
ULONG buf_len,
|
||||||
|
|
@ -1180,6 +1224,9 @@ handle_upcall(
|
||||||
case NFS41_VOLUME_QUERY:
|
case NFS41_VOLUME_QUERY:
|
||||||
status = marshal_nfs41_volume(entry, pbOut, cbOut, len);
|
status = marshal_nfs41_volume(entry, pbOut, cbOut, len);
|
||||||
break;
|
break;
|
||||||
|
case NFS41_ACL_QUERY:
|
||||||
|
status = marshal_nfs41_getacl(entry, pbOut, cbOut, len);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
status = STATUS_INVALID_PARAMETER;
|
status = STATUS_INVALID_PARAMETER;
|
||||||
print_error("Unknown nfs41 ops %d\n", entry->opcode);
|
print_error("Unknown nfs41 ops %d\n", entry->opcode);
|
||||||
|
|
@ -1517,6 +1564,32 @@ nfs41_downcall (
|
||||||
cur->u.Volume.buf_len = tmp->u.Volume.buf_len;
|
cur->u.Volume.buf_len = tmp->u.Volume.buf_len;
|
||||||
RtlCopyMemory(cur->u.Volume.buf, buf, tmp->u.Volume.buf_len);
|
RtlCopyMemory(cur->u.Volume.buf, buf, tmp->u.Volume.buf_len);
|
||||||
break;
|
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;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
DbgP("[downcall] About to signal waiting IO thread\n");
|
DbgP("[downcall] About to signal waiting IO thread\n");
|
||||||
|
|
@ -3609,12 +3682,125 @@ out:
|
||||||
DbgEx();
|
DbgEx();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
static NTSTATUS map_query_acl_error(DWORD error)
|
||||||
|
{
|
||||||
|
switch (error) {
|
||||||
|
case ERROR_NOT_SUPPORTED: return STATUS_NOT_SUPPORTED;
|
||||||
|
case ERROR_ACCESS_DENIED: return STATUS_ACCESS_DENIED;
|
||||||
|
case ERROR_FILE_NOT_FOUND: return STATUS_OBJECT_NAME_NOT_FOUND;
|
||||||
|
case ERROR_INVALID_PARAMETER: return STATUS_INVALID_PARAMETER;
|
||||||
|
default:
|
||||||
|
print_error("failed to map windows error %d to NTSTATUS; "
|
||||||
|
"defaulting to STATUS_INVALID_NETWORK_RESPONSE\n", error);
|
||||||
|
case ERROR_BAD_NET_RESP: return STATUS_INVALID_NETWORK_RESPONSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
NTSTATUS nfs41_QuerySecurityInformation (
|
NTSTATUS nfs41_QuerySecurityInformation (
|
||||||
IN OUT PRX_CONTEXT RxContext)
|
IN OUT PRX_CONTEXT RxContext)
|
||||||
{
|
{
|
||||||
NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS;
|
NTSTATUS status = STATUS_NOT_SUPPORTED; //STATUS_SUCCESS;
|
||||||
|
nfs41_updowncall_entry *entry;
|
||||||
|
PNFS41_FOBX nfs41_fobx = (PNFS41_FOBX)(RxContext->pFobx)->Context;
|
||||||
|
__notnull PMRX_SRV_OPEN SrvOpen = RxContext->pRelevantSrvOpen;
|
||||||
|
PNFS41_V_NET_ROOT_EXTENSION pVNetRootContext =
|
||||||
|
NFS41GetVNetRootExtension(SrvOpen->pVNetRoot);
|
||||||
|
PNFS41_NETROOT_EXTENSION pNetRootContext =
|
||||||
|
NFS41GetNetRootExtension(SrvOpen->pVNetRoot->pNetRoot);
|
||||||
|
BYTE owner_buf[SECURITY_MAX_SID_SIZE], group_buf[SECURITY_MAX_SID_SIZE];
|
||||||
|
|
||||||
DbgEn();
|
DbgEn();
|
||||||
|
print_debug_header(RxContext);
|
||||||
|
|
||||||
|
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 = RxContext->CurrentIrpSp->Parameters.QuerySecurity.SecurityInformation;
|
||||||
|
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->version = pNetRootContext->nfs41d_version;
|
||||||
|
|
||||||
|
if (nfs41_UpcallWaitForReply(entry) != STATUS_SUCCESS) {
|
||||||
|
status = STATUS_INTERNAL_ERROR;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
} 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");
|
||||||
|
} 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
RxContext->IoStatusBlock.Information = RxContext->InformationToReturn =
|
||||||
|
RtlLengthSecurityDescriptor(sec_desc);
|
||||||
|
RxContext->IoStatusBlock.Status = status = STATUS_SUCCESS;
|
||||||
|
} else {
|
||||||
|
status = map_query_acl_error(entry->status);
|
||||||
|
}
|
||||||
|
out_free:
|
||||||
|
RxFreePool(entry);
|
||||||
|
out:
|
||||||
DbgEx();
|
DbgEx();
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,6 +66,8 @@ typedef enum _nfs41_opcodes {
|
||||||
NFS41_EA_SET,
|
NFS41_EA_SET,
|
||||||
NFS41_SYMLINK,
|
NFS41_SYMLINK,
|
||||||
NFS41_VOLUME_QUERY,
|
NFS41_VOLUME_QUERY,
|
||||||
|
NFS41_ACL_QUERY,
|
||||||
|
NFS41_ACL_SET,
|
||||||
NFS41_SHUTDOWN,
|
NFS41_SHUTDOWN,
|
||||||
INVALID_OPCODE
|
INVALID_OPCODE
|
||||||
} nfs41_opcodes;
|
} nfs41_opcodes;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue