Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

939 lines
27 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
userkey.c
Abstract:
Implentation of the functions that get and generate user session keys
RtlCalculateUserSessionKeyLm
RtlCalculateUserSessionKeyNt
RtlGetUserSessionKeyClient
RtlGetUserSessionKeyServer
Author:
David Chalmers (Davidc) 10-21-91
Revision History:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <ntddnfs.h>
#include <rpc.h>
#include <rpcndr.h>
#include <crypt.h>
#include <srvfsctl.h> // Server definitions
#include <status.h> // Server return codes
//
// Define this if you want to know all about user session keys
//
// #define DEBUG_USER_SESSION_KEYS
#define REDIRECTOR_DEVICENAME L"\\Device\\LanmanRedirector\\"
#define REDIRECTOR_IPC_FILENAME L"\\IPC$"
//
// Define the user session key to be used for local connections
// Make sure the initial data fills the structure completely !
//
USER_SESSION_KEY LocalSessionKey = { 'S', 'y', 's', 't', 'e', 'm', 'L', 'i',
'b', 'r', 'a', 'r', 'y', 'D', 'T', 'C'
};
//
// Define the user session key that represents an error.
// This value will be generated by other parts of the system on failure.
// We will check for it in our query code and return an error if it's found.
//
USER_SESSION_KEY ErrorSessionKey = { 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0
};
NTSTATUS
RtlCalculateUserSessionKeyLm(
IN PLM_RESPONSE LmResponse,
IN PLM_OWF_PASSWORD LmOwfPassword,
OUT PUSER_SESSION_KEY UserSessionKey)
/*++
Routine Description:
Takes the passed Response and OwfPassword and generates a UserSessionKey.
The current implementation takes the one-way-function of the OwfPassword
and returns this as the key.
Arguments:
LmResponse - The response sent during session setup.
LmOwfPassword - The hashed version of the user's password.
Return Values:
STATUS_SUCCESS - The function was completed successfully.
The UserSessionKey is in UserSessionKey.
STATUS_UNSUCCESSFUL - Something failed. The UserSessionKey is undefined.
--*/
{
NTSTATUS Status;
NT_PASSWORD NtPassword;
//
// Make the Owf password look like an NT password
//
NtPassword.Buffer = (PWSTR)LmOwfPassword; // We can do this cast because we
// know the OWF routine treats this
// pointer as a byte pointer.
NtPassword.Length = sizeof(*LmOwfPassword);
NtPassword.MaximumLength = sizeof(*LmOwfPassword);
//
// Calculate the OWF of the OwfPassword
//
ASSERT(sizeof(NT_OWF_PASSWORD) == sizeof(*UserSessionKey));
Status = RtlCalculateNtOwfPassword( &NtPassword,
(PNT_OWF_PASSWORD)UserSessionKey
);
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlCalculateUserSessionKeyLm : OWF calculation failed, status = 0x%lx\n", Status));
return(Status);
}
//
// Check if we've generated the error session key
//
if (RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
sizeof(*UserSessionKey)) == sizeof(*UserSessionKey)) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlCalculateSessionKeyLm - generated error session key, modifying it\n"));
#endif
//
// Move away from the error session key
//
UserSessionKey->data[0].data[0] ++;
ASSERT(RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
sizeof(*UserSessionKey)) != sizeof(*UserSessionKey));
}
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlCalculateUserSessionKeyLm : Key = 0x%lx : %lx : %lx : %lx\n",
((PULONG)UserSessionKey)[0], ((PULONG)UserSessionKey)[1],
((PULONG)UserSessionKey)[2], ((PULONG)UserSessionKey)[3]));
#endif
return(STATUS_SUCCESS);
UNREFERENCED_PARAMETER(LmResponse);
}
NTSTATUS
RtlCalculateUserSessionKeyNt(
IN PNT_RESPONSE NtResponse,
IN PNT_OWF_PASSWORD NtOwfPassword,
OUT PUSER_SESSION_KEY UserSessionKey)
/*++
Routine Description:
Takes the passed Response and OwfPassword and generates a UserSessionKey.
Arguments:
NtResponse - The response sent during session setup.
NtOwfPassword - The hashed version of the user's password.
Return Values:
STATUS_SUCCESS - The function was completed successfully.
The UserSessionKey is in UserSessionKey.
STATUS_UNSUCCESSFUL - Something failed. The UserSessionKey is undefined.
--*/
{
// Just call the LM version
ASSERT(sizeof(NT_RESPONSE) == sizeof(LM_RESPONSE));
ASSERT(sizeof(NT_OWF_PASSWORD) == sizeof(LM_OWF_PASSWORD));
return(RtlCalculateUserSessionKeyLm((PLM_RESPONSE)NtResponse,
(PLM_OWF_PASSWORD)NtOwfPassword,
UserSessionKey));
}
NTSTATUS
RtlGetUserSessionKeyClientBinding(
IN PVOID RpcBindingHandle,
OUT HANDLE *RedirHandle,
OUT PUSER_SESSION_KEY UserSessionKey)
/*++
Routine Description:
Returns the user session key associated with an rpc connection.
This function should be called by the client side of the connection only.
Arguments:
RpcBindingHandle - The rpc connection we're interested in
RedirHandle - Returns a handle to the redir. Since RpcBindingHandles don't represent
and open connection to the server, we have to ensure the connection stays open
until the server side has a chance to get this same UserSessionKey. The only
way to do that is to keep the connect open.
Returns NULL if no handle is needed.
This handle should be closed by calling NtClose.
UserSessionKey - The user session key is returned here
Return Values:
STATUS_SUCCESS - The function was completed successfully.
The UserSessionKey is in UserSessionKey.
STATUS_LOCAL_USER_SESSION_KEY - An informational status value.
- The rpc connection is local, the usersessionkey returned
- is constant and not unique to this connection.
- There is little to be gained by encrypting data over
- this connection
STATUS_NO_USER_SESSION_KEY - No session key exists for this session.
------ these come from parsebinding -------
RPC_NT_OUT_OF_MEMORY - Insufficent memory is available to allocate
space for the fields of the string binding.
RPC_NT_INVALID_STRING_BINDING - The string binding is syntactically
invalid.
RPC_NT_INVALID_ARG - The string binding is not specified
(ie. ARGUMENT_PRESENT(StringBinding) is false).
--*/
{
NTSTATUS Status, IgnoreStatus;
WCHAR *StringBinding;
WCHAR *ServerNameZ;
WCHAR *BareServerNameZ; // Points to server name minus leading '\'s
OBJECT_ATTRIBUTES Attributes;
UNICODE_STRING ServerName;
UNICODE_STRING RedirDevice;
UNICODE_STRING IpcFileName;
UNICODE_STRING ServerIpcFileName;
USHORT LengthRequired;
IO_STATUS_BLOCK IoStatusBlock;
LMR_REQUEST_PACKET RdrRequestPacket;
LMR_CONNECTION_INFO_2 ConnectionInfo;
//
// Get the string description of the binding from the rpc handle
//
*RedirHandle = NULL;
Status = (NTSTATUS)I_RpcMapWin32Status(
RpcBindingToStringBindingW(RpcBindingHandle, &StringBinding));
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyClient - failed to get stringbinding, Status = 0x%lx\n\r", Status));
return(Status);
}
//
// Parse the stringbinding to get the server name
//
Status = (NTSTATUS)I_RpcMapWin32Status(RpcStringBindingParseW(
StringBinding,
NULL, // object uid
NULL, // protseq !
&ServerNameZ, // network address
NULL, // endpoint
NULL // network options
));
//
// We're finished with the string binding
//
IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&StringBinding));
ASSERT(NT_SUCCESS(IgnoreStatus));
//
// Check the result of binding parse
//
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyClient - failed to parse stringbinding, status = 0x%lx\n\r", Status));
return(Status);
}
//
// Check for a local connection
//
if ( (ServerNameZ == NULL) || (ServerNameZ[0] == UNICODE_NULL) ) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyClient - server name is NULL, returning local key\n"));
#endif
//
// Use a constant, default session key
//
*UserSessionKey = LocalSessionKey;
IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
ASSERT(NT_SUCCESS(IgnoreStatus));
return(STATUS_LOCAL_USER_SESSION_KEY);
}
//
// Strip the leading '\'s from the server name
//
BareServerNameZ = ServerNameZ;
while (*BareServerNameZ == L'\\') {
BareServerNameZ ++;
}
//
// Set up a counted string for out server name
//
RtlInitUnicodeString(&ServerName, BareServerNameZ);
//
// Check for the local server name '.'
//
if ( (ServerName.Length == sizeof(*ServerName.Buffer)) &&
(ServerName.Buffer[0] == L'.') ) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyClient - server name is '.', returning local key\n"));
#endif
//
// Use a constant, default session key
//
*UserSessionKey = LocalSessionKey;
IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
ASSERT(NT_SUCCESS(IgnoreStatus));
return(STATUS_LOCAL_USER_SESSION_KEY);
}
//
// Create a redirector ipc file name for the referenced server
//
RtlInitUnicodeString(&RedirDevice, REDIRECTOR_DEVICENAME);
RtlInitUnicodeString(&IpcFileName, REDIRECTOR_IPC_FILENAME);
LengthRequired = RedirDevice.Length + ServerName.Length + IpcFileName.Length;
//
// Allocate space for the ipc file name we will create
//
ServerIpcFileName.Buffer = RtlAllocateHeap(RtlProcessHeap(), 0, LengthRequired);
if (ServerIpcFileName.Buffer == NULL) {
KdPrint(("RtlGetUserSessionKeyClient - failed to allocate space for server name (%d bytes)\n", LengthRequired));
IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
ASSERT(NT_SUCCESS(IgnoreStatus));
return(STATUS_INSUFFICIENT_RESOURCES);
}
ServerIpcFileName.Length = 0;
ServerIpcFileName.MaximumLength = LengthRequired;
//
// ServerIpcFileName = \Device\LanmanRedirector\ + servername + \ipc$
//
RtlCopyUnicodeString(&ServerIpcFileName, &RedirDevice);
IgnoreStatus = RtlAppendUnicodeStringToString(&ServerIpcFileName, &ServerName);
ASSERT(NT_SUCCESS(IgnoreStatus));
IgnoreStatus = RtlAppendUnicodeStringToString(&ServerIpcFileName, &IpcFileName);
ASSERT(NT_SUCCESS(IgnoreStatus));
//
// Don't need the server name any more
//
IgnoreStatus = I_RpcMapWin32Status(RpcStringFreeW(&ServerNameZ));
ASSERT(NT_SUCCESS(IgnoreStatus));
//
// Open up the redirector ipc file
//
InitializeObjectAttributes( &Attributes,
&ServerIpcFileName,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = NtOpenFile( RedirHandle,
FILE_READ_DATA | // access required to get connection info
SYNCHRONIZE, // access required to wait on object
&Attributes,
&IoStatusBlock,
FILE_SHARE_READ,
FILE_CREATE_TREE_CONNECTION );
//
// We're finished with the ipc filename
//
RtlFreeHeap( RtlProcessHeap(), 0, ServerIpcFileName.Buffer );
ServerIpcFileName.Buffer = NULL;
//
// Check the result of the open
//
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyClient - failed to open redirector, status = 0x%lx\n\r", Status));
*RedirHandle = NULL;
return(Status);
}
//
// Get the connection info for this link
//
RdrRequestPacket.Version = REQUEST_PACKET_VERSION;
RdrRequestPacket.Level = 2; // We want the session key.
Status = NtFsControlFile( *RedirHandle,
NULL, // Event
NULL, // APC routine
NULL, // APC context
&IoStatusBlock,
FSCTL_LMR_GET_CONNECTION_INFO,
&RdrRequestPacket, // Input buffer
sizeof(RdrRequestPacket), // Input buffer length
&ConnectionInfo, // Output buffer
sizeof(ConnectionInfo) // Output buffer length
);
//
// remove the reference created on the existing connection.
// this logic assumes the caller of RtlGetUserSessionKeyClientXXX()
// has already established a connection.
//
{
LMR_REQUEST_PACKET Rrp; // Redirector request packet
NTSTATUS TempStatus;
RtlZeroMemory(&Rrp,sizeof(LMR_REQUEST_PACKET));
Rrp.Level = USE_FORCE; // this tells rdr2 to take away the extra reference
// to connection strucutre even when files are open.
Rrp.Version = REQUEST_PACKET_VERSION;
TempStatus = NtFsControlFile(
*RedirHandle, // handle
NULL, // no event
NULL, // no APC routine
NULL, // no APC context
&IoStatusBlock, // I/O stat blk (set)
FSCTL_LMR_DELETE_CONNECTION, // func code
&Rrp,
sizeof(LMR_REQUEST_PACKET),
NULL,
0
);
//
// block on the delete if necessary.
//
if( TempStatus == STATUS_PENDING )
{
NtWaitForSingleObject( *RedirHandle, TRUE, NULL );
}
}
//
// Check the result of the control file call
//
if (!NT_SUCCESS(Status)) {
IgnoreStatus = NtClose(*RedirHandle);
ASSERT(NT_SUCCESS(IgnoreStatus));
*RedirHandle = NULL;
KdPrint(("RtlGetUserSessionKeyClient - failed to get connection info, status = 0x%lx\n\r", Status));
ASSERT(FALSE);
return(Status);
}
//
// Copy the session key into the passed buffer
//
*UserSessionKey = *(PUSER_SESSION_KEY)(ConnectionInfo.UserSessionKey);
//
// Check for the error session key
//
if (RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
sizeof(*UserSessionKey)) == sizeof(*UserSessionKey)) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyClient - got error session key, returning error\n"));
#endif
Status = STATUS_NO_USER_SESSION_KEY;
IgnoreStatus = NtClose(*RedirHandle);
ASSERT(NT_SUCCESS(IgnoreStatus));
*RedirHandle = NULL;
}
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyClient : Key = 0x%lx : %lx : %lx : %lx\n",
((PULONG)UserSessionKey)[0], ((PULONG)UserSessionKey)[1],
((PULONG)UserSessionKey)[2], ((PULONG)UserSessionKey)[3]));
#endif
return(Status);
}
NTSTATUS
RtlGetUserSessionKeyClient(
IN PVOID RpcContextHandle,
OUT PUSER_SESSION_KEY UserSessionKey)
/*++
Routine Description:
Returns the user session key associated with an rpc connection.
This function should be called by the client side of the connection only.
Arguments:
RpcContextHandle - The rpc connection we're interested in
This can also be an RPC binding handle.
UserSessionKey - The user session key is returned here
Return Values:
STATUS_SUCCESS - The function was completed successfully.
The UserSessionKey is in UserSessionKey.
STATUS_LOCAL_USER_SESSION_KEY - An informational status value.
- The rpc connection is local, the usersessionkey returned
- is constant and not unique to this connection.
- There is little to be gained by encrypting data over
- this connection
STATUS_NO_USER_SESSION_KEY - No session key exists for this session.
------ these come from parsebinding -------
RPC_NT_OUT_OF_MEMORY - Insufficent memory is available to allocate
space for the fields of the string binding.
RPC_NT_INVALID_STRING_BINDING - The string binding is syntactically
invalid.
RPC_NT_INVALID_ARG - The string binding is not specified
(ie. ARGUMENT_PRESENT(StringBinding) is false).
--*/
{
NTSTATUS Status;
HANDLE RedirHandle = NULL;
//
// Call the worker routine.
//
Status = RtlGetUserSessionKeyClientBinding(
NDRCContextBinding((NDR_CCONTEXT)RpcContextHandle),
&RedirHandle,
UserSessionKey );
if ( RedirHandle != NULL ) {
NtClose( RedirHandle );
}
return Status;
}
NTSTATUS
RtlGetUserSessionKeyServer(
IN PVOID RpcContextHandle OPTIONAL,
OUT PUSER_SESSION_KEY UserSessionKey)
/*++
Routine Description:
Returns the user session key associated with an rpc connection.
This function should be called by the server side of the connection only.
Arguments:
RpcBindingHandle - The rpc connection we're interested in
- Note this parameter is ignored for now
UserSessionKey - The user session key is returned here
Return Values:
STATUS_SUCCESS - The function was completed successfully.
The UserSessionKey is in UserSessionKey.
STATUS_LOCAL_USER_SESSION_KEY - An informational status value.
- The rpc connection is local, the usersessionkey returned
- is constant and not unique to this connection.
- There is little to be gained by encrypting data over
- this connection
STATUS_NO_USER_SESSION_KEY - No session key exists for this session.
--*/
{
NTSTATUS Status, IgnoreStatus;
HANDLE TokenHandle;
TOKEN_STATISTICS TokenInfo;
ULONG ReturnedLength;
UNICODE_STRING ServerDevice;
ANSI_STRING AnsiString;
OBJECT_ATTRIBUTES Attributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE ServerHandle;
RPC_BINDING_HANDLE RpcBindingHandle;
unsigned int RpcClientLocalFlag;
//
// Get the binding handle for this connection
//
// LATER RpcBindingHandle = (RPC_BINDING_HANDLE) RpcContextHandle;
RpcBindingHandle = NULL;
//
// If this is a local connection then we can immediately
// return the local session key.
//
Status = I_RpcBindingIsClientLocal(RpcBindingHandle, &RpcClientLocalFlag);
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyServer: RpcBindingIsClientLocal failed, status = 0x%lx\n", Status));
return(Status);
}
if (RpcClientLocalFlag != 0) {
*UserSessionKey = LocalSessionKey;
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyServer: client is local, returning local key\n"));
#endif
return (STATUS_LOCAL_USER_SESSION_KEY);
}
//
// Get a handle to the client's token
//
Status = NtOpenThreadToken(NtCurrentThread(),
TOKEN_QUERY,
TRUE,
&TokenHandle);
//
// If we couldn't open the thread token because we weren't impersonating
// then impersonate and try again.
//
if (!NT_SUCCESS(Status)) {
//
// Check we failed only because we weren't impersonating
//
if (Status != STATUS_NO_TOKEN) {
KdPrint(("RtlGetUserSessionKeyServer - failed to open thread token, status = 0x%lx\n", Status));
ASSERT(FALSE);
return(Status);
}
//
// Impersonate the client ourselves
//
Status = I_RpcMapWin32Status(RpcImpersonateClient(RpcBindingHandle));
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyServer - RpcImpersonateClient failed, status = 0x%lx\n", Status));
ASSERT(FALSE);
return(Status);
}
//
// Try to get a token handle now we're impersonating
//
Status = NtOpenThreadToken(NtCurrentThread(),
TOKEN_QUERY,
TRUE,
&TokenHandle);
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyServer - failed to open thread token after impersonating, status = 0x%lx\n", Status));
ASSERT(FALSE);
IgnoreStatus = I_RpcMapWin32Status(RpcRevertToSelf());
ASSERT(NT_SUCCESS(IgnoreStatus));
return(Status);
}
//
// We've got a token handle, stop impersonating
//
Status = I_RpcMapWin32Status(RpcRevertToSelf());
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyServer - RpcRevertToSelf failed, status = 0x%lx\n", Status));
ASSERT(FALSE);
IgnoreStatus = NtClose(TokenHandle);
ASSERT(NT_SUCCESS(IgnoreStatus));
return(Status);
}
}
//
// We've now got a token handle, get the authentication id from it.
//
Status = NtQueryInformationToken(
TokenHandle,
TokenStatistics,
&TokenInfo,
sizeof(TokenInfo),
&ReturnedLength
);
//
// We're done with the token
//
IgnoreStatus = NtClose(TokenHandle);
ASSERT(NT_SUCCESS(IgnoreStatus));
//
// Check result of token query
//
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyServer - Failed to query token statistics from token, status = 0x%lx\n", Status));
ASSERT(FALSE);
return(Status);
}
//
// Open the server device
//
RtlInitAnsiString(&AnsiString, SERVER_DEVICE_NAME);
Status = RtlAnsiStringToUnicodeString(&ServerDevice, &AnsiString, TRUE);
if (!NT_SUCCESS(Status)) {
KdPrint(("RtlGetUserSessionKeyServer - RtlAnsiToUnicodeString failed, status = 0x%lx\n", Status));
ASSERT(FALSE);
return(Status);
}
InitializeObjectAttributes( &Attributes,
&ServerDevice,
OBJ_CASE_INSENSITIVE,
NULL,
NULL );
Status = NtOpenFile( &ServerHandle,
GENERIC_READ | GENERIC_WRITE, // LATER use correct access
&Attributes,
&IoStatusBlock,
FILE_SHARE_READ,
0 );
RtlFreeUnicodeString(&ServerDevice);
if (!NT_SUCCESS(Status)) {
//
// Check for the case when the server driver is not present
//
if (Status == STATUS_OBJECT_NAME_NOT_FOUND) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyServer - server driver not present, returning local key\n"));
#endif
*UserSessionKey = LocalSessionKey;
Status = STATUS_LOCAL_USER_SESSION_KEY;
} else {
KdPrint(("RtlGetUserSessionKeyServer - Failed to open the server, status = 0x%lx\n", Status));
ASSERT(FALSE);
}
return(Status);
}
//
// Get the session key for this client from the server
//
Status = NtFsControlFile( ServerHandle,
NULL, // Event
NULL, // APC
NULL, // APC Context
&IoStatusBlock,
FSCTL_SRV_GET_CHALLENGE,
&TokenInfo.AuthenticationId,
sizeof(TokenInfo.AuthenticationId),
(PVOID)UserSessionKey,
sizeof(*UserSessionKey));
//
// We're done with the file handle
//
IgnoreStatus = NtClose(ServerHandle);
ASSERT(NT_SUCCESS(IgnoreStatus));
if (NT_SUCCESS(Status)) {
//
// Check for the error session key
//
if (RtlCompareMemory(UserSessionKey, &ErrorSessionKey,
sizeof(*UserSessionKey)) == sizeof(*UserSessionKey)) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyServer - got error session key, returning error\n"));
#endif
Status = STATUS_NO_USER_SESSION_KEY;
}
} else {
//
// If the server is not started or the token couldn't be found in the
// list of server connections, then assume it's a local connection
//
if ( (Status == STATUS_SERVER_NOT_STARTED) ||
(Status == STATUS_NO_TOKEN) ) {
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyServer - server not started or logon id not found (Status = 0x%lx), returning local key\n", Status));
#endif
*UserSessionKey = LocalSessionKey;
Status = STATUS_LOCAL_USER_SESSION_KEY;
} else {
KdPrint(("RtlGetUserSessionKeyServer - Failed to query the user session key from the server, status = 0x%lx\n", Status));
ASSERT(FALSE);
}
}
#ifdef DEBUG_USER_SESSION_KEYS
KdPrint(("RtlGetUserSessionKeyServer : Key = 0x%lx : %lx : %lx : %lx, status = 0x%lx\n",
((PULONG)UserSessionKey)[0], ((PULONG)UserSessionKey)[1],
((PULONG)UserSessionKey)[2], ((PULONG)UserSessionKey)[3], Status));
#endif
return(Status);
}