support for multiuser environment
on a mount request, search a list of existing mounts for a given netroot based on LUID entries (login ids). if an entry is found, then check the current request rpcsec flavor against existing sessions/mounts. If no match found, do another upcall for a mount and store a session of this flavor for this LUID. if no entry found for this LUID, then do a mount upcall, create a new entry and add it to the list.
This commit is contained in:
parent
436df23cba
commit
52081e3175
1 changed files with 210 additions and 40 deletions
|
|
@ -235,6 +235,19 @@ typedef struct _updowncall_list {
|
||||||
} nfs41_updowncall_list;
|
} nfs41_updowncall_list;
|
||||||
nfs41_updowncall_list *upcall = NULL, *downcall = NULL;
|
nfs41_updowncall_list *upcall = NULL, *downcall = NULL;
|
||||||
|
|
||||||
|
typedef struct _nfs41_mount_entry {
|
||||||
|
LIST_ENTRY next;
|
||||||
|
LUID login_id;
|
||||||
|
HANDLE authsys_session;
|
||||||
|
HANDLE gss_session;
|
||||||
|
HANDLE gssi_session;
|
||||||
|
HANDLE gssp_session;
|
||||||
|
} nfs41_mount_entry;
|
||||||
|
|
||||||
|
typedef struct _nfs41_mount_list {
|
||||||
|
LIST_ENTRY head;
|
||||||
|
} nfs41_mount_list;
|
||||||
|
|
||||||
#define nfs41_AddEntry(lock,pList,pEntry) \
|
#define nfs41_AddEntry(lock,pList,pEntry) \
|
||||||
ExAcquireFastMutex(&lock); \
|
ExAcquireFastMutex(&lock); \
|
||||||
InsertTailList(&pList->head, &(pEntry)->next); \
|
InsertTailList(&pList->head, &(pEntry)->next); \
|
||||||
|
|
@ -266,6 +279,15 @@ nfs41_updowncall_list *upcall = NULL, *downcall = NULL;
|
||||||
nfs41_updowncall_entry, \
|
nfs41_updowncall_entry, \
|
||||||
next))); \
|
next))); \
|
||||||
ExReleaseFastMutex(&lock);
|
ExReleaseFastMutex(&lock);
|
||||||
|
#define nfs41_GetFirstMountEntry(lock,pList,pEntry) \
|
||||||
|
ExAcquireFastMutex(&lock); \
|
||||||
|
pEntry = (IsListEmpty(&pList->head) \
|
||||||
|
? NULL \
|
||||||
|
: (nfs41_mount_entry *) \
|
||||||
|
(CONTAINING_RECORD(pList->head.Flink, \
|
||||||
|
nfs41_mount_entry, \
|
||||||
|
next))); \
|
||||||
|
ExReleaseFastMutex(&lock);
|
||||||
#define nfs41_GetNextEntry(pList,pEntry) \
|
#define nfs41_GetNextEntry(pList,pEntry) \
|
||||||
((pEntry->next.Flink == &pList->head) \
|
((pEntry->next.Flink == &pList->head) \
|
||||||
? NULL \
|
? NULL \
|
||||||
|
|
@ -304,10 +326,10 @@ typedef struct _NFS41_MOUNT_CONFIG {
|
||||||
typedef struct _NFS41_NETROOT_EXTENSION {
|
typedef struct _NFS41_NETROOT_EXTENSION {
|
||||||
NODE_TYPE_CODE NodeTypeCode;
|
NODE_TYPE_CODE NodeTypeCode;
|
||||||
NODE_BYTE_SIZE NodeByteSize;
|
NODE_BYTE_SIZE NodeByteSize;
|
||||||
HANDLE auth_sys_session;
|
|
||||||
HANDLE gss_session;
|
|
||||||
DWORD nfs41d_version;
|
DWORD nfs41d_version;
|
||||||
BOOLEAN do_umount;
|
BOOLEAN mounts_init;
|
||||||
|
FAST_MUTEX mountLock;
|
||||||
|
nfs41_mount_list *mounts;
|
||||||
} NFS41_NETROOT_EXTENSION, *PNFS41_NETROOT_EXTENSION;
|
} NFS41_NETROOT_EXTENSION, *PNFS41_NETROOT_EXTENSION;
|
||||||
#define NFS41GetNetRootExtension(pNetRoot) \
|
#define NFS41GetNetRootExtension(pNetRoot) \
|
||||||
(((pNetRoot) == NULL) ? NULL : (PNFS41_NETROOT_EXTENSION)((pNetRoot)->Context))
|
(((pNetRoot) == NULL) ? NULL : (PNFS41_NETROOT_EXTENSION)((pNetRoot)->Context))
|
||||||
|
|
@ -2546,6 +2568,36 @@ static NTSTATUS map_sec_flavor(
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
NTSTATUS nfs41_GetLUID(PLUID id)
|
||||||
|
{
|
||||||
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
SECURITY_SUBJECT_CONTEXT sec_ctx;
|
||||||
|
SECURITY_QUALITY_OF_SERVICE sec_qos;
|
||||||
|
SECURITY_CLIENT_CONTEXT clnt_sec_ctx;
|
||||||
|
|
||||||
|
SeCaptureSubjectContext(&sec_ctx);
|
||||||
|
sec_qos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
|
||||||
|
sec_qos.ImpersonationLevel = SecurityIdentification/*SecurityImpersonation*/;
|
||||||
|
sec_qos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
|
||||||
|
sec_qos.EffectiveOnly = 0;
|
||||||
|
status = SeCreateClientSecurityFromSubjectContext(&sec_ctx, &sec_qos, 1, &clnt_sec_ctx);
|
||||||
|
if (status) {
|
||||||
|
DbgP("SeCreateClientSecurityFromSubjectContext failed %x\n", status);
|
||||||
|
goto release_sec_ctx;
|
||||||
|
}
|
||||||
|
status = SeQueryAuthenticationIdToken(clnt_sec_ctx.ClientToken, id);
|
||||||
|
if (status) {
|
||||||
|
DbgP("SeQueryAuthenticationIdToken failed %x\n", status);
|
||||||
|
goto release_clnt_sec_ctx;
|
||||||
|
}
|
||||||
|
release_clnt_sec_ctx:
|
||||||
|
SeDeleteClientSecurity(&clnt_sec_ctx);
|
||||||
|
release_sec_ctx:
|
||||||
|
SeReleaseSubjectContext(&sec_ctx);
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
NTSTATUS nfs41_CreateVNetRoot(
|
NTSTATUS nfs41_CreateVNetRoot(
|
||||||
IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
|
IN OUT PMRX_CREATENETROOT_CONTEXT pCreateNetRootContext)
|
||||||
{
|
{
|
||||||
|
|
@ -2560,6 +2612,10 @@ NTSTATUS nfs41_CreateVNetRoot(
|
||||||
NFS41GetNetRootExtension(pNetRoot);
|
NFS41GetNetRootExtension(pNetRoot);
|
||||||
NFS41GetDeviceExtension(pCreateNetRootContext->RxContext,DevExt);
|
NFS41GetDeviceExtension(pCreateNetRootContext->RxContext,DevExt);
|
||||||
DWORD nfs41d_version = DevExt->nfs41d_version;
|
DWORD nfs41d_version = DevExt->nfs41d_version;
|
||||||
|
nfs41_mount_entry *existing_mount = NULL;
|
||||||
|
LUID luid;
|
||||||
|
BOOLEAN found_existing_mount = FALSE, found_matching_flavor = FALSE;
|
||||||
|
|
||||||
ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
|
ASSERT((NodeType(pNetRoot) == RDBSS_NTC_NETROOT) &&
|
||||||
(NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
|
(NodeType(pNetRoot->pSrvCall) == RDBSS_NTC_SRVCALL));
|
||||||
|
|
||||||
|
|
@ -2617,32 +2673,125 @@ NTSTATUS nfs41_CreateVNetRoot(
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pVNetRootContext->sec_flavor == RPCSEC_AUTH_SYS &&
|
status = nfs41_GetLUID(&luid);
|
||||||
pNetRootContext->auth_sys_session) {
|
if (status) {
|
||||||
pVNetRootContext->session = pNetRootContext->auth_sys_session;
|
|
||||||
DbgP("Using existing AUTH_SYS session 0x%x\n", pVNetRootContext->session);
|
|
||||||
goto out;
|
|
||||||
} else if ((pVNetRootContext->sec_flavor != RPCSEC_AUTH_SYS ||
|
|
||||||
pNetRoot->Type != NET_ROOT_WILD) &&
|
|
||||||
pNetRootContext->gss_session) {
|
|
||||||
pVNetRootContext->session = pNetRootContext->gss_session;
|
|
||||||
DbgP("Using existing AUTHGSS session 0x%x\n", pVNetRootContext->session);
|
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!pNetRootContext->mounts_init) {
|
||||||
|
DbgP("Initializing mount array\n");
|
||||||
|
ExInitializeFastMutex(&pNetRootContext->mountLock);
|
||||||
|
pNetRootContext->mounts = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_mount_list),
|
||||||
|
NFS41_MM_POOLTAG);
|
||||||
|
if (pNetRootContext->mounts == NULL) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
InitializeListHead(&pNetRootContext->mounts->head);
|
||||||
|
pNetRootContext->mounts_init = TRUE;
|
||||||
|
} else {
|
||||||
|
PLIST_ENTRY pEntry;
|
||||||
|
|
||||||
|
ExAcquireFastMutex(&pNetRootContext->mountLock);
|
||||||
|
pEntry = &pNetRootContext->mounts->head;
|
||||||
|
while (pEntry != NULL) {
|
||||||
|
existing_mount = (nfs41_mount_entry *)CONTAINING_RECORD(pEntry,
|
||||||
|
nfs41_mount_entry, next);
|
||||||
|
DbgP("comparing %x.%x with %x.%x\n", luid.HighPart, luid.LowPart,
|
||||||
|
existing_mount->login_id.HighPart, existing_mount->login_id.LowPart);
|
||||||
|
if (RtlEqualLuid(&luid, &existing_mount->login_id)) {
|
||||||
|
DbgP("Found a matching LUID entry\n");
|
||||||
|
found_existing_mount = TRUE;
|
||||||
|
switch(pVNetRootContext->sec_flavor) {
|
||||||
|
case RPCSEC_AUTH_SYS:
|
||||||
|
if (existing_mount->authsys_session != INVALID_HANDLE_VALUE)
|
||||||
|
pVNetRootContext->session = existing_mount->authsys_session;
|
||||||
|
break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5:
|
||||||
|
if (existing_mount->gssi_session != INVALID_HANDLE_VALUE)
|
||||||
|
pVNetRootContext->session = existing_mount->gss_session;
|
||||||
|
break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5I:
|
||||||
|
if (existing_mount->gss_session != INVALID_HANDLE_VALUE)
|
||||||
|
pVNetRootContext->session = existing_mount->gssi_session;
|
||||||
|
break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5P:
|
||||||
|
if (existing_mount->gssp_session != INVALID_HANDLE_VALUE)
|
||||||
|
pVNetRootContext->session = existing_mount->gssp_session;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pVNetRootContext->session)
|
||||||
|
found_matching_flavor = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (pEntry->Flink == &pNetRootContext->mounts->head) {
|
||||||
|
DbgP("reached end of the list\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pEntry = pEntry->Flink;
|
||||||
|
}
|
||||||
|
ExReleaseFastMutex(&pNetRootContext->mountLock);
|
||||||
|
if (!found_matching_flavor)
|
||||||
|
DbgP("Didn't find matching security flavor\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_existing_mount || !found_matching_flavor) {
|
||||||
/* send the mount upcall */
|
/* send the mount upcall */
|
||||||
DbgP("Server Name %wZ Mount Point %wZ SecFlavor %wZ\n",
|
DbgP("Server Name %wZ Mount Point %wZ SecFlavor %wZ\n",
|
||||||
&Config.SrvName, &Config.MntPt, &Config.SecFlavor);
|
&Config.SrvName, &Config.MntPt, &Config.SecFlavor);
|
||||||
status = nfs41_mount(&Config.SrvName, &Config.MntPt, pVNetRootContext->sec_flavor,
|
status = nfs41_mount(&Config.SrvName, &Config.MntPt, pVNetRootContext->sec_flavor,
|
||||||
&pVNetRootContext->session, &nfs41d_version);
|
&pVNetRootContext->session, &nfs41d_version);
|
||||||
if (status != STATUS_SUCCESS)
|
if (status != STATUS_SUCCESS) {
|
||||||
|
if (!found_existing_mount) {
|
||||||
|
RxFreePool(pNetRootContext->mounts);
|
||||||
|
pNetRootContext->mounts_init = FALSE;
|
||||||
|
pVNetRootContext->session = INVALID_HANDLE_VALUE;
|
||||||
|
}
|
||||||
goto out;
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found_existing_mount) {
|
||||||
|
/* create a new mount entry and add it to the list */
|
||||||
|
nfs41_mount_entry *entry;
|
||||||
|
entry = RxAllocatePoolWithTag(NonPagedPool, sizeof(nfs41_mount_entry),
|
||||||
|
NFS41_MM_POOLTAG);
|
||||||
|
if (entry == NULL) {
|
||||||
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
||||||
|
RxFreePool(pNetRootContext->mounts);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
entry->authsys_session = entry->gss_session =
|
||||||
|
entry->gssi_session = entry->gssp_session = INVALID_HANDLE_VALUE;
|
||||||
|
switch (pVNetRootContext->sec_flavor) {
|
||||||
|
case RPCSEC_AUTH_SYS:
|
||||||
|
entry->authsys_session = pVNetRootContext->session; break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5:
|
||||||
|
entry->gss_session = pVNetRootContext->session; break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5I:
|
||||||
|
entry->gssi_session = pVNetRootContext->session; break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5P:
|
||||||
|
entry->gssp_session = pVNetRootContext->session; break;
|
||||||
|
}
|
||||||
|
RtlCopyLuid(&entry->login_id, &luid);
|
||||||
|
nfs41_AddEntry(pNetRootContext->mountLock, pNetRootContext->mounts, entry);
|
||||||
|
} else if (!found_matching_flavor) {
|
||||||
|
ASSERT(existing_mount != NULL);
|
||||||
|
/* modify existing mount entry */
|
||||||
|
DbgP("Using existing %d flavor session 0x%x\n",
|
||||||
|
pVNetRootContext->sec_flavor);
|
||||||
|
switch (pVNetRootContext->sec_flavor) {
|
||||||
|
case RPCSEC_AUTH_SYS:
|
||||||
|
existing_mount->authsys_session = pVNetRootContext->session; break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5:
|
||||||
|
existing_mount->gss_session = pVNetRootContext->session; break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5I:
|
||||||
|
existing_mount->gssi_session = pVNetRootContext->session; break;
|
||||||
|
case RPCSEC_AUTHGSS_KRB5P:
|
||||||
|
existing_mount->gssp_session = pVNetRootContext->session; break;
|
||||||
|
}
|
||||||
|
}
|
||||||
pNetRootContext->nfs41d_version = nfs41d_version;
|
pNetRootContext->nfs41d_version = nfs41d_version;
|
||||||
pNetRootContext->do_umount = TRUE;
|
|
||||||
if (pVNetRootContext->sec_flavor == RPCSEC_AUTH_SYS)
|
|
||||||
pNetRootContext->auth_sys_session = pVNetRootContext->session;
|
|
||||||
else
|
|
||||||
pNetRootContext->gss_session = pVNetRootContext->session;
|
|
||||||
DbgP("Saving new session 0x%x\n", pVNetRootContext->session);
|
DbgP("Saving new session 0x%x\n", pVNetRootContext->session);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
|
|
@ -2730,6 +2879,7 @@ NTSTATUS nfs41_FinalizeNetRoot(
|
||||||
PNFS41_NETROOT_EXTENSION pNetRootContext =
|
PNFS41_NETROOT_EXTENSION pNetRootContext =
|
||||||
NFS41GetNetRootExtension((PMRX_NET_ROOT)pNetRoot);
|
NFS41GetNetRootExtension((PMRX_NET_ROOT)pNetRoot);
|
||||||
nfs41_updowncall_entry *tmp;
|
nfs41_updowncall_entry *tmp;
|
||||||
|
nfs41_mount_entry *mount_tmp;
|
||||||
|
|
||||||
DbgEn();
|
DbgEn();
|
||||||
print_net_root(1, pNetRoot);
|
print_net_root(1, pNetRoot);
|
||||||
|
|
@ -2739,8 +2889,7 @@ NTSTATUS nfs41_FinalizeNetRoot(
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pNetRootContext == NULL || (pNetRootContext->auth_sys_session == NULL &&
|
if (pNetRootContext == NULL || !pNetRootContext->mounts_init) {
|
||||||
pNetRootContext->gss_session == NULL)) {
|
|
||||||
print_error("No valid session has been established\n");
|
print_error("No valid session has been established\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
@ -2751,20 +2900,41 @@ NTSTATUS nfs41_FinalizeNetRoot(
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pNetRootContext->auth_sys_session && pNetRootContext->do_umount) {
|
do {
|
||||||
status = nfs41_unmount(pNetRootContext->auth_sys_session, pNetRootContext->nfs41d_version);
|
nfs41_GetFirstMountEntry(pNetRootContext->mountLock,
|
||||||
if (status) {
|
pNetRootContext->mounts, mount_tmp);
|
||||||
print_error("nfs41_mount AUTH_SYS failed with %d\n", status);
|
if (mount_tmp == NULL)
|
||||||
goto out;
|
break;
|
||||||
|
DbgP("Removing entry luid %x.%x from mount list\n", mount_tmp->login_id.HighPart,
|
||||||
|
mount_tmp->login_id.LowPart);
|
||||||
|
|
||||||
|
if (mount_tmp->authsys_session != INVALID_HANDLE_VALUE) {
|
||||||
|
status = nfs41_unmount(mount_tmp->authsys_session, pNetRootContext->nfs41d_version);
|
||||||
|
if (status)
|
||||||
|
print_error("nfs41_unmount AUTH_SYS failed with %d\n", status);
|
||||||
}
|
}
|
||||||
|
if (mount_tmp->gss_session != INVALID_HANDLE_VALUE) {
|
||||||
|
status = nfs41_unmount(mount_tmp->gss_session, pNetRootContext->nfs41d_version);
|
||||||
|
if (status)
|
||||||
|
print_error("nfs41_unmount RPCSEC_GSS_KRB5 failed with %d\n", status);
|
||||||
}
|
}
|
||||||
if (pNetRootContext->gss_session) {
|
if (mount_tmp->gssi_session != INVALID_HANDLE_VALUE) {
|
||||||
status = nfs41_unmount(pNetRootContext->gss_session, pNetRootContext->nfs41d_version);
|
status = nfs41_unmount(mount_tmp->gssi_session, pNetRootContext->nfs41d_version);
|
||||||
if (status) {
|
if (status)
|
||||||
print_error("nfs41_mount AUTHGSS failed with %d\n", status);
|
print_error("nfs41_unmount RPCSEC_GSS_KRB5I failed with %d\n", status);
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
if (mount_tmp->gssp_session != INVALID_HANDLE_VALUE) {
|
||||||
|
status = nfs41_unmount(mount_tmp->gssp_session, pNetRootContext->nfs41d_version);
|
||||||
|
if (status)
|
||||||
|
print_error("nfs41_unmount RPCSEC_GSS_KRB5P failed with %d\n", status);
|
||||||
}
|
}
|
||||||
|
nfs41_RemoveEntry(pNetRootContext->mountLock, pNetRootContext->mounts, mount_tmp);
|
||||||
|
RxFreePool(mount_tmp);
|
||||||
|
} while (1);
|
||||||
|
/* ignore any errors from unmount */
|
||||||
|
status = STATUS_SUCCESS;
|
||||||
|
RxFreePool(pNetRootContext->mounts);
|
||||||
|
|
||||||
// check if there is anything waiting in the upcall or downcall queue
|
// check if there is anything waiting in the upcall or downcall queue
|
||||||
do {
|
do {
|
||||||
nfs41_GetFirstEntry(upcallLock, upcall, tmp);
|
nfs41_GetFirstEntry(upcallLock, upcall, tmp);
|
||||||
|
|
@ -2925,7 +3095,7 @@ NTSTATUS nfs41_Create(
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pNetRootContext->auth_sys_session == NULL && pNetRootContext->gss_session == NULL) {
|
if (!pNetRootContext->mounts_init) {
|
||||||
print_error("No valid session established\n");
|
print_error("No valid session established\n");
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue