mirror of https://github.com/lianthony/NT4.0
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.
1565 lines
35 KiB
1565 lines
35 KiB
//+-----------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
//
|
|
// Copyright (c) Microsoft Corporation 1992 - 1994
|
|
//
|
|
// File: stubs.cxx
|
|
//
|
|
// Contents: user-mode stubs for security API
|
|
//
|
|
//
|
|
// History: 3/5/94 MikeSw Created
|
|
//
|
|
//------------------------------------------------------------------------
|
|
#include <sspdrv.h>
|
|
|
|
#pragma alloc_text(PAGE, AcquireCredentialsHandleW)
|
|
#pragma alloc_text(PAGE, FreeCredentialsHandle)
|
|
#pragma alloc_text(PAGE, InitializeSecurityContextW)
|
|
#pragma alloc_text(PAGE, AcceptSecurityContext)
|
|
#pragma alloc_text(PAGE, DeleteSecurityContext)
|
|
#pragma alloc_text(PAGE, ApplyControlToken)
|
|
#pragma alloc_text(PAGE, EnumerateSecurityPackagesW)
|
|
#pragma alloc_text(PAGE, QuerySecurityPackageInfoW)
|
|
#pragma alloc_text(PAGE, FreeContextBuffer)
|
|
|
|
static CtxtHandle NullContext = {0,0};
|
|
static CredHandle NullCredential = {0,0};
|
|
static LUID lFake = {0, 0};
|
|
static SECURITY_STRING sFake = {0, 0, NULL};
|
|
static TOKEN_SOURCE KsecTokenSource = {"KSecDD", {0, 0} };
|
|
|
|
#define NTLMSSP_REQUIRED_NEGOTIATE_FLAGS ( NTLMSSP_NEGOTIATE_UNICODE | \
|
|
NTLMSSP_REQUEST_INIT_RESPONSE )
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: AcquireCredentialsHandleW
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
AcquireCredentialsHandleW(
|
|
PSECURITY_STRING pssPrincipal, // Name of principal
|
|
PSECURITY_STRING pssPackageName, // Name of package
|
|
unsigned long fCredentialUse, // Flags indicating use
|
|
void SEC_FAR * pvLogonId, // Pointer to logon ID
|
|
void SEC_FAR * pAuthData, // Package specific data
|
|
SEC_GET_KEY_FN pGetKeyFn, // Pointer to GetKey() func
|
|
void SEC_FAR * pvGetKeyArgument, // Value to pass to GetKey()
|
|
PCredHandle phCredential, // (out) Cred Handle
|
|
PTimeStamp ptsExpiry // (out) Lifetime (optional)
|
|
)
|
|
{
|
|
SECURITY_STATUS scRet;
|
|
SECURITY_STRING Principal;
|
|
TimeStamp OptionalTimeStamp;
|
|
UNICODE_STRING PackageName;
|
|
|
|
PAGED_CODE();
|
|
|
|
if (!pssPackageName)
|
|
{
|
|
return(SEC_E_SECPKG_NOT_FOUND);
|
|
}
|
|
|
|
//
|
|
// We don't accept principal names either.
|
|
//
|
|
|
|
if (pssPrincipal)
|
|
{
|
|
return(SEC_E_UNKNOWN_CREDENTIALS);
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure they want the NTLM security package
|
|
//
|
|
RtlInitUnicodeString(
|
|
&PackageName,
|
|
NTLMSP_NAME
|
|
);
|
|
|
|
|
|
if (!RtlEqualUnicodeString(
|
|
pssPackageName,
|
|
&PackageName,
|
|
TRUE))
|
|
{
|
|
return(SEC_E_SECPKG_NOT_FOUND);
|
|
}
|
|
|
|
//
|
|
// The credential handle is the logon id
|
|
//
|
|
|
|
if (fCredentialUse & SECPKG_CRED_OUTBOUND)
|
|
{
|
|
if (pvLogonId != NULL)
|
|
{
|
|
*phCredential = *(PCredHandle) pvLogonId;
|
|
}
|
|
else
|
|
{
|
|
return(SEC_E_UNKNOWN_CREDENTIALS);
|
|
}
|
|
|
|
}
|
|
else if (fCredentialUse & SECPKG_CRED_INBOUND)
|
|
{
|
|
//
|
|
// For inbound credentials, we will accept a logon id but
|
|
// we don't require it.
|
|
//
|
|
|
|
if (pvLogonId != NULL)
|
|
{
|
|
*phCredential = *(PCredHandle) pvLogonId;
|
|
}
|
|
else
|
|
{
|
|
*phCredential = NullCredential;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
return(SEC_E_UNSUPPORTED_FUNCTION);
|
|
}
|
|
|
|
|
|
return(SEC_E_OK);
|
|
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeCredentialsHandle
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
FreeCredentialsHandle(
|
|
PCredHandle phCredential // Handle to free
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Since the credential handle is just the LogonId, do nothing.
|
|
//
|
|
|
|
return(SEC_E_OK);
|
|
}
|
|
|
|
|
|
VOID
|
|
PutString(
|
|
OUT PSTRING Destination,
|
|
IN PSTRING Source,
|
|
IN PVOID Base,
|
|
IN OUT PUCHAR * Where
|
|
)
|
|
{
|
|
Destination->Buffer = (PCHAR) *Where - (ULONG) Base;
|
|
Destination->Length =
|
|
Source->Length;
|
|
Destination->MaximumLength =
|
|
Source->Length;
|
|
|
|
RtlCopyMemory(
|
|
*Where,
|
|
Source->Buffer,
|
|
Source->Length
|
|
);
|
|
*Where += Source->Length;
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: InitializeSecurityContextW
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
InitializeSecurityContextW(
|
|
PCredHandle phCredential, // Cred to base context
|
|
PCtxtHandle phContext, // Existing context (OPT)
|
|
PSECURITY_STRING pssTargetName, // Name of target
|
|
unsigned long fContextReq, // Context Requirements
|
|
unsigned long Reserved1, // Reserved, MBZ
|
|
unsigned long TargetDataRep, // Data rep of target
|
|
PSecBufferDesc pInput, // Input Buffers
|
|
unsigned long Reserved2, // Reserved, MBZ
|
|
PCtxtHandle phNewContext, // (out) New Context handle
|
|
PSecBufferDesc pOutput, // (inout) Output Buffers
|
|
unsigned long SEC_FAR * pfContextAttr, // (out) Context attrs
|
|
PTimeStamp ptsExpiry // (out) Life span (OPT)
|
|
)
|
|
{
|
|
SECURITY_STATUS scRet;
|
|
PMSV1_0_GETCHALLENRESP_REQUEST ChallengeRequest = NULL;
|
|
ULONG ChallengeRequestSize;
|
|
PMSV1_0_GETCHALLENRESP_RESPONSE ChallengeResponse = NULL;
|
|
ULONG ChallengeResponseSize;
|
|
PCHALLENGE_MESSAGE ChallengeMessage = NULL;
|
|
ULONG ChallengeMessageSize;
|
|
PNTLM_CHALLENGE_MESSAGE NtlmChallengeMessage = NULL;
|
|
ULONG NtlmChallengeMessageSize;
|
|
PAUTHENTICATE_MESSAGE AuthenticateMessage = NULL;
|
|
ULONG AuthenticateMessageSize;
|
|
PNTLM_INITIALIZE_RESPONSE NtlmInitializeResponse = NULL;
|
|
PClient Client = NULL;
|
|
UNICODE_STRING PasswordToUse;
|
|
UNICODE_STRING UserNameToUse;
|
|
UNICODE_STRING DomainNameToUse;
|
|
ULONG ParameterControl = USE_PRIMARY_PASSWORD |
|
|
RETURN_PRIMARY_USERNAME |
|
|
RETURN_PRIMARY_LOGON_DOMAINNAME;
|
|
|
|
NTSTATUS FinalStatus = STATUS_SUCCESS;
|
|
PUCHAR Where;
|
|
PSecBuffer AuthenticationToken = NULL;
|
|
PSecBuffer InitializeResponseToken = NULL;
|
|
BOOLEAN UseSuppliedCreds = FALSE;
|
|
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(
|
|
&PasswordToUse,
|
|
NULL
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&UserNameToUse,
|
|
NULL
|
|
);
|
|
|
|
RtlInitUnicodeString(
|
|
&DomainNameToUse,
|
|
NULL
|
|
);
|
|
|
|
//
|
|
// Check for valid sizes, pointers, etc.:
|
|
//
|
|
|
|
|
|
if (!phCredential)
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
|
|
//
|
|
// Check that we can indeed call the LSA and get the client
|
|
// handle to it.
|
|
//
|
|
|
|
scRet = IsOkayToExec(&Client);
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
return(scRet);
|
|
}
|
|
|
|
//
|
|
// Locate the buffers with the input data
|
|
//
|
|
|
|
if (!GetTokenBuffer(
|
|
pInput,
|
|
0, // get the first security token
|
|
(PVOID *) &ChallengeMessage,
|
|
&ChallengeMessageSize,
|
|
TRUE // may be readonly
|
|
))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// If we are using supplied creds, get them now too.
|
|
//
|
|
|
|
|
|
if (fContextReq & ISC_REQ_USE_SUPPLIED_CREDS)
|
|
{
|
|
if (!GetTokenBuffer(
|
|
pInput,
|
|
1, // get the second security token
|
|
(PVOID *) &NtlmChallengeMessage,
|
|
&NtlmChallengeMessageSize,
|
|
TRUE // may be readonly
|
|
))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
else
|
|
{
|
|
UseSuppliedCreds = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Get the output tokens
|
|
//
|
|
|
|
if (!GetSecurityToken(
|
|
pOutput,
|
|
0,
|
|
&AuthenticationToken) ||
|
|
!GetSecurityToken(
|
|
pOutput,
|
|
1,
|
|
&InitializeResponseToken ) )
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Make sure the sizes are o.k.
|
|
//
|
|
|
|
if ((ChallengeMessageSize < sizeof(CHALLENGE_MESSAGE)) ||
|
|
(UseSuppliedCreds &&
|
|
!(NtlmChallengeMessageSize < sizeof(NTLM_CHALLENGE_MESSAGE))))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
}
|
|
|
|
//
|
|
// Make sure the caller wants us to allocate memory:
|
|
//
|
|
|
|
if (!(fContextReq & ISC_REQ_ALLOCATE_MEMORY))
|
|
{
|
|
scRet = SEC_E_UNSUPPORTED_FUNCTION;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// BUGBUG: allow calls requesting PROMPT_FOR_CREDS to go through.
|
|
// We won't prompt, but we will setup a context properly.
|
|
//
|
|
|
|
// if ((fContextReq & ISC_REQ_PROMPT_FOR_CREDS) != 0)
|
|
// {
|
|
// scRet = SEC_E_UNSUPPORTED_FUNCTION;
|
|
// goto Cleanup;
|
|
// }
|
|
|
|
//
|
|
// Verify the validity of the challenge message.
|
|
//
|
|
|
|
if (strncmp(
|
|
ChallengeMessage->Signature,
|
|
NTLMSSP_SIGNATURE,
|
|
sizeof(NTLMSSP_SIGNATURE)))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (ChallengeMessage->MessageType != NtLmChallenge)
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (ChallengeMessage->NegotiateFlags & NTLMSSP_REQUIRED_NEGOTIATE_FLAGS !=
|
|
NTLMSSP_REQUIRED_NEGOTIATE_FLAGS)
|
|
{
|
|
scRet = SEC_E_UNSUPPORTED_FUNCTION;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ((ChallengeMessage->NegotiateFlags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY) != 0)
|
|
{
|
|
ParameterControl |= RETURN_NON_NT_USER_SESSION_KEY;
|
|
}
|
|
|
|
if ((fContextReq & ISC_REQ_USE_SUPPLIED_CREDS) != 0)
|
|
{
|
|
if ( NtlmChallengeMessage->Password.Buffer != NULL)
|
|
{
|
|
ParameterControl &= ~USE_PRIMARY_PASSWORD;
|
|
PasswordToUse = NtlmChallengeMessage->Password;
|
|
PasswordToUse.Buffer = (LPWSTR) ((PCHAR) PasswordToUse.Buffer +
|
|
(ULONG) NtlmChallengeMessage);
|
|
}
|
|
|
|
if (NtlmChallengeMessage->UserName.Length != 0)
|
|
{
|
|
UserNameToUse = NtlmChallengeMessage->UserName;
|
|
UserNameToUse.Buffer = (LPWSTR) ((PCHAR) UserNameToUse.Buffer +
|
|
(ULONG) NtlmChallengeMessage);
|
|
ParameterControl &= ~RETURN_PRIMARY_USERNAME;
|
|
}
|
|
if (NtlmChallengeMessage->DomainName.Length != 0)
|
|
{
|
|
DomainNameToUse = NtlmChallengeMessage->DomainName;
|
|
DomainNameToUse.Buffer = (LPWSTR) ((PCHAR) DomainNameToUse.Buffer +
|
|
(ULONG) NtlmChallengeMessage);
|
|
ParameterControl &= ~RETURN_PRIMARY_LOGON_DOMAINNAME;
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Package up the parameter for a call to the LSA.
|
|
//
|
|
|
|
ChallengeRequestSize = sizeof(MSV1_0_GETCHALLENRESP_REQUEST) +
|
|
PasswordToUse.Length;
|
|
|
|
scRet = ZwAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&ChallengeRequest,
|
|
0L,
|
|
&ChallengeRequestSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Build the challenge request message.
|
|
//
|
|
|
|
ChallengeRequest->MessageType = MsV1_0Lm20GetChallengeResponse;
|
|
ChallengeRequest->ParameterControl = ParameterControl;
|
|
ChallengeRequest->LogonId = * (PLUID) phCredential;
|
|
RtlCopyMemory(
|
|
ChallengeRequest->ChallengeToClient,
|
|
ChallengeMessage->Challenge,
|
|
MSV1_0_CHALLENGE_LENGTH
|
|
);
|
|
if ((ParameterControl & USE_PRIMARY_PASSWORD) == 0)
|
|
{
|
|
ChallengeRequest->Password.Buffer = (LPWSTR) (ChallengeRequest+1);
|
|
RtlCopyMemory(
|
|
ChallengeRequest->Password.Buffer,
|
|
PasswordToUse.Buffer,
|
|
PasswordToUse.Length
|
|
);
|
|
ChallengeRequest->Password.Length = PasswordToUse.Length;
|
|
ChallengeRequest->Password.MaximumLength = PasswordToUse.Length;
|
|
}
|
|
|
|
//
|
|
// Call the LSA to get the challenge response.
|
|
//
|
|
|
|
scRet = LsaCallAuthenticationPackage(
|
|
Client->hPort,
|
|
PackageId,
|
|
ChallengeRequest,
|
|
ChallengeRequestSize,
|
|
&ChallengeResponse,
|
|
&ChallengeResponseSize,
|
|
&FinalStatus
|
|
);
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
if (!NT_SUCCESS(FinalStatus))
|
|
{
|
|
scRet = FinalStatus;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(ChallengeResponse->MessageType == MsV1_0Lm20GetChallengeResponse);
|
|
//
|
|
// Now prepare the output message.
|
|
//
|
|
|
|
if (UserNameToUse.Buffer == NULL)
|
|
{
|
|
UserNameToUse = ChallengeResponse->UserName;
|
|
}
|
|
if (DomainNameToUse.Buffer == NULL)
|
|
{
|
|
DomainNameToUse = ChallengeResponse->LogonDomainName;
|
|
}
|
|
|
|
AuthenticateMessageSize = sizeof(AUTHENTICATE_MESSAGE) +
|
|
UserNameToUse.Length +
|
|
DomainNameToUse.Length +
|
|
ChallengeResponse->CaseSensitiveChallengeResponse.Length +
|
|
ChallengeResponse->CaseInsensitiveChallengeResponse.Length;
|
|
|
|
//
|
|
// BUGBUG: where do I get the workstation name from?
|
|
//
|
|
|
|
AuthenticateMessage = (PAUTHENTICATE_MESSAGE) SecAllocate(AuthenticateMessageSize);
|
|
if (AuthenticateMessage == NULL)
|
|
{
|
|
scRet = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
Where = (PUCHAR) (AuthenticateMessage + 1);
|
|
RtlCopyMemory(
|
|
AuthenticateMessage->Signature,
|
|
NTLMSSP_SIGNATURE,
|
|
sizeof(NTLMSSP_SIGNATURE)
|
|
);
|
|
AuthenticateMessage->MessageType = NtLmAuthenticate;
|
|
|
|
PutString(
|
|
&AuthenticateMessage->LmChallengeResponse,
|
|
&ChallengeResponse->CaseInsensitiveChallengeResponse,
|
|
AuthenticateMessage,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
&AuthenticateMessage->NtChallengeResponse,
|
|
&ChallengeResponse->CaseSensitiveChallengeResponse,
|
|
AuthenticateMessage,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
&AuthenticateMessage->DomainName,
|
|
(PSTRING) &DomainNameToUse,
|
|
AuthenticateMessage,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
&AuthenticateMessage->UserName,
|
|
(PSTRING) &UserNameToUse,
|
|
AuthenticateMessage,
|
|
&Where
|
|
);
|
|
|
|
//
|
|
// BUGBUG: no workstation name to fill in.
|
|
//
|
|
|
|
AuthenticateMessage->Workstation.Length = 0;
|
|
AuthenticateMessage->Workstation.MaximumLength = 0;
|
|
AuthenticateMessage->Workstation.Buffer = NULL;
|
|
|
|
|
|
//
|
|
// Build the initialize response.
|
|
//
|
|
|
|
NtlmInitializeResponse = (PNTLM_INITIALIZE_RESPONSE) SecAllocate(sizeof(NTLM_INITIALIZE_RESPONSE));
|
|
if (NtlmInitializeResponse == NULL)
|
|
{
|
|
scRet = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
RtlCopyMemory(
|
|
NtlmInitializeResponse->UserSessionKey,
|
|
ChallengeResponse->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
NtlmInitializeResponse->LanmanSessionKey,
|
|
ChallengeResponse->LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH
|
|
);
|
|
|
|
//
|
|
// Fill in the output buffers now.
|
|
//
|
|
|
|
AuthenticationToken->pvBuffer = AuthenticateMessage;
|
|
AuthenticationToken->cbBuffer = AuthenticateMessageSize;
|
|
InitializeResponseToken->pvBuffer = NtlmInitializeResponse;
|
|
InitializeResponseToken->cbBuffer = sizeof(NTLM_INITIALIZE_RESPONSE);
|
|
|
|
|
|
//
|
|
// Make a local context for this
|
|
//
|
|
|
|
scRet = NtlmInitKernelContext(
|
|
NtlmInitializeResponse->UserSessionKey,
|
|
NtlmInitializeResponse->LanmanSessionKey,
|
|
NULL, // no token,
|
|
phNewContext
|
|
);
|
|
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
scRet = SEC_E_OK;
|
|
|
|
|
|
|
|
|
|
Cleanup:
|
|
|
|
if (ChallengeRequest != NULL)
|
|
{
|
|
ZwFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&ChallengeRequest,
|
|
&ChallengeRequestSize,
|
|
MEM_RELEASE
|
|
);
|
|
}
|
|
|
|
if (ChallengeResponse != NULL)
|
|
{
|
|
LsaFreeReturnBuffer( ChallengeResponse );
|
|
}
|
|
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
if (AuthenticateMessage != NULL)
|
|
{
|
|
SecFree(AuthenticateMessage);
|
|
}
|
|
if (NtlmInitializeResponse != NULL)
|
|
{
|
|
SecFree(NtlmInitializeResponse);
|
|
}
|
|
}
|
|
return(scRet);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: AcceptSecurityContext
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
AcceptSecurityContext(
|
|
PCredHandle phCredential, // Cred to base context
|
|
PCtxtHandle phContext, // Existing context (OPT)
|
|
PSecBufferDesc pInput, // Input buffer
|
|
unsigned long fContextReq, // Context Requirements
|
|
unsigned long TargetDataRep, // Target Data Rep
|
|
PCtxtHandle phNewContext, // (out) New context handle
|
|
PSecBufferDesc pOutput, // (inout) Output buffers
|
|
unsigned long SEC_FAR * pfContextAttr, // (out) Context attributes
|
|
PTimeStamp ptsExpiry // (out) Life span (OPT)
|
|
)
|
|
{
|
|
SECURITY_STATUS scRet;
|
|
NTSTATUS SubStatus;
|
|
PAUTHENTICATE_MESSAGE AuthenticateMessage;
|
|
ULONG AuthenticateMessageSize;
|
|
PNTLM_AUTHENTICATE_MESSAGE NtlmAuthenticateMessage;
|
|
ULONG NtlmAuthenticateMessageSize;
|
|
PNTLM_ACCEPT_RESPONSE NtlmAcceptResponse = NULL;
|
|
PMSV1_0_LM20_LOGON LogonBuffer = NULL;
|
|
ULONG LogonBufferSize;
|
|
PMSV1_0_LM20_LOGON_PROFILE LogonProfile = NULL;
|
|
ULONG LogonProfileSize;
|
|
PSecBuffer AcceptResponseToken = NULL;
|
|
PClient Client = NULL;
|
|
ANSI_STRING SourceName;
|
|
LUID LogonId;
|
|
LUID UNALIGNED * TempLogonId;
|
|
LARGE_INTEGER UNALIGNED * TempKickoffTime;
|
|
HANDLE TokenHandle = NULL;
|
|
QUOTA_LIMITS Quotas;
|
|
PUCHAR Where;
|
|
STRING DomainName;
|
|
STRING UserName;
|
|
STRING Workstation;
|
|
STRING NtChallengeResponse;
|
|
STRING LmChallengeResponse;
|
|
ULONG EffectivePackageId;
|
|
|
|
|
|
RtlInitString(
|
|
&SourceName,
|
|
NULL
|
|
);
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Check for valid sizes, pointers, etc.:
|
|
//
|
|
|
|
|
|
if (!phCredential)
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
|
|
//
|
|
// Check that we can indeed call the LSA and get the client
|
|
// handle to it.
|
|
//
|
|
|
|
scRet = IsOkayToExec(&Client);
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
return(scRet);
|
|
}
|
|
|
|
//
|
|
// Locate the buffers with the input data
|
|
//
|
|
|
|
if (!GetTokenBuffer(
|
|
pInput,
|
|
0, // get the first security token
|
|
(PVOID *) &AuthenticateMessage,
|
|
&AuthenticateMessageSize,
|
|
TRUE // may be readonly
|
|
) ||
|
|
(!GetTokenBuffer(
|
|
pInput,
|
|
1, // get the second security token
|
|
(PVOID *) &NtlmAuthenticateMessage,
|
|
&NtlmAuthenticateMessageSize,
|
|
TRUE // may be readonly
|
|
)))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Get the output tokens
|
|
//
|
|
|
|
if (!GetSecurityToken(
|
|
pOutput,
|
|
0,
|
|
&AcceptResponseToken ) )
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Make sure the sizes are o.k.
|
|
//
|
|
|
|
if ((AuthenticateMessageSize < sizeof(AUTHENTICATE_MESSAGE)) ||
|
|
(NtlmAuthenticateMessageSize < sizeof(NTLM_AUTHENTICATE_MESSAGE)))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
}
|
|
|
|
//
|
|
// Make sure the caller does not want us to allocate memory:
|
|
//
|
|
|
|
if (fContextReq & ISC_REQ_ALLOCATE_MEMORY)
|
|
{
|
|
scRet = SEC_E_UNSUPPORTED_FUNCTION;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (AcceptResponseToken->cbBuffer < sizeof(NTLM_ACCEPT_RESPONSE))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
//
|
|
// Verify the validity of the Authenticate message.
|
|
//
|
|
|
|
if (strncmp(
|
|
AuthenticateMessage->Signature,
|
|
NTLMSSP_SIGNATURE,
|
|
sizeof(NTLMSSP_SIGNATURE)))
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
if (AuthenticateMessage->MessageType != NtLmAuthenticate)
|
|
{
|
|
scRet = SEC_E_INVALID_TOKEN;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Fixup the buffer pointers
|
|
//
|
|
|
|
UserName = AuthenticateMessage->UserName;
|
|
UserName.Buffer = UserName.Buffer + (ULONG) AuthenticateMessage;
|
|
|
|
DomainName = AuthenticateMessage->DomainName;
|
|
DomainName.Buffer = DomainName.Buffer + (ULONG) AuthenticateMessage;
|
|
|
|
Workstation = AuthenticateMessage->Workstation;
|
|
Workstation.Buffer = Workstation.Buffer + (ULONG) AuthenticateMessage;
|
|
|
|
NtChallengeResponse = AuthenticateMessage->NtChallengeResponse;
|
|
NtChallengeResponse.Buffer = NtChallengeResponse.Buffer + (ULONG) AuthenticateMessage;
|
|
|
|
LmChallengeResponse = AuthenticateMessage->LmChallengeResponse;
|
|
LmChallengeResponse.Buffer = LmChallengeResponse.Buffer + (ULONG) AuthenticateMessage;
|
|
|
|
//
|
|
// Allocate a buffer to pass into LsaLogonUser
|
|
//
|
|
|
|
LogonBufferSize = sizeof(MSV1_0_LM20_LOGON) +
|
|
UserName.Length +
|
|
DomainName.Length +
|
|
Workstation.Length +
|
|
LmChallengeResponse.Length +
|
|
NtChallengeResponse.Length;
|
|
|
|
scRet = ZwAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&LogonBuffer,
|
|
0L,
|
|
&LogonBufferSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Fill in the fixed-length portions
|
|
//
|
|
|
|
LogonBuffer->MessageType = MsV1_0NetworkLogon;
|
|
|
|
RtlCopyMemory(
|
|
LogonBuffer->ChallengeToClient,
|
|
NtlmAuthenticateMessage->ChallengeToClient,
|
|
MSV1_0_CHALLENGE_LENGTH
|
|
);
|
|
|
|
//
|
|
// Fill in the variable length pieces
|
|
//
|
|
|
|
Where = (PUCHAR) (LogonBuffer + 1);
|
|
|
|
PutString(
|
|
(PSTRING) &LogonBuffer->LogonDomainName,
|
|
&DomainName,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
(PSTRING) &LogonBuffer->UserName,
|
|
&UserName,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
(PSTRING) &LogonBuffer->Workstation,
|
|
&Workstation,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
(PSTRING) &LogonBuffer->CaseSensitiveChallengeResponse,
|
|
&NtChallengeResponse,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
(PSTRING) &LogonBuffer->CaseInsensitiveChallengeResponse,
|
|
&LmChallengeResponse,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
LogonBuffer->ParameterControl = MSV1_0_CLEARTEXT_PASSWORD_ALLOWED |
|
|
NtlmAuthenticateMessage->ParameterControl;
|
|
|
|
scRet = RtlUnicodeStringToAnsiString(
|
|
&SourceName,
|
|
(PUNICODE_STRING) &Workstation,
|
|
TRUE
|
|
);
|
|
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
if ( fContextReq & ASC_REQ_LICENSING )
|
|
{
|
|
EffectivePackageId = PackageId | LSA_CALL_LICENSE_SERVER ;
|
|
}
|
|
else
|
|
{
|
|
EffectivePackageId = PackageId ;
|
|
}
|
|
|
|
scRet = LsaLogonUser(
|
|
Client->hPort,
|
|
&SourceName,
|
|
Network,
|
|
EffectivePackageId,
|
|
LogonBuffer,
|
|
LogonBufferSize,
|
|
NULL, // token groups
|
|
&KsecTokenSource,
|
|
(PVOID *) &LogonProfile,
|
|
&LogonProfileSize,
|
|
&LogonId,
|
|
&TokenHandle,
|
|
&Quotas,
|
|
&SubStatus
|
|
);
|
|
|
|
if (scRet == STATUS_ACCOUNT_RESTRICTION)
|
|
{
|
|
scRet = SubStatus;
|
|
}
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
//
|
|
// LsaLogonUser returns garbage for the token if it fails,
|
|
// so zero it now so we don't try to close it later.
|
|
//
|
|
|
|
TokenHandle = NULL;
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Create the kernel context
|
|
//
|
|
|
|
scRet = NtlmInitKernelContext(
|
|
LogonProfile->UserSessionKey,
|
|
LogonProfile->LanmanSessionKey,
|
|
TokenHandle,
|
|
phNewContext
|
|
);
|
|
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
TokenHandle = NULL;
|
|
|
|
//
|
|
// Allocate the return buffer.
|
|
//
|
|
|
|
|
|
NtlmAcceptResponse = (PNTLM_ACCEPT_RESPONSE) AcceptResponseToken->pvBuffer;
|
|
if (NtlmAcceptResponse == NULL)
|
|
{
|
|
scRet = SEC_E_INSUFFICIENT_MEMORY;
|
|
goto Cleanup;
|
|
}
|
|
|
|
TempLogonId = (LUID UNALIGNED *) &NtlmAcceptResponse->LogonId;
|
|
*TempLogonId = LogonId;
|
|
NtlmAcceptResponse->UserFlags = LogonProfile->UserFlags;
|
|
|
|
RtlCopyMemory(
|
|
NtlmAcceptResponse->UserSessionKey,
|
|
LogonProfile->UserSessionKey,
|
|
MSV1_0_USER_SESSION_KEY_LENGTH
|
|
);
|
|
|
|
RtlCopyMemory(
|
|
NtlmAcceptResponse->LanmanSessionKey,
|
|
LogonProfile->LanmanSessionKey,
|
|
MSV1_0_LANMAN_SESSION_KEY_LENGTH
|
|
);
|
|
|
|
TempKickoffTime = (LARGE_INTEGER UNALIGNED *) &NtlmAcceptResponse->KickoffTime;
|
|
*TempKickoffTime = LogonProfile->KickOffTime;
|
|
|
|
AcceptResponseToken->cbBuffer = sizeof(NTLM_ACCEPT_RESPONSE);
|
|
|
|
if ( fContextReq & ASC_REQ_LICENSING )
|
|
{
|
|
*pfContextAttr = ASC_RET_ALLOCATED_MEMORY | ASC_RET_LICENSING ;
|
|
}
|
|
else
|
|
{
|
|
*pfContextAttr = ASC_RET_ALLOCATED_MEMORY;
|
|
}
|
|
|
|
*ptsExpiry = LogonProfile->LogoffTime;
|
|
scRet = SEC_E_OK;
|
|
|
|
|
|
Cleanup:
|
|
if (SourceName.Buffer != NULL)
|
|
{
|
|
RtlFreeAnsiString(&SourceName);
|
|
}
|
|
|
|
if (LogonBuffer != NULL)
|
|
{
|
|
ZwFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&LogonBuffer,
|
|
&LogonBufferSize,
|
|
MEM_RELEASE
|
|
);
|
|
}
|
|
|
|
if (LogonProfile != NULL)
|
|
{
|
|
LsaFreeReturnBuffer(LogonProfile);
|
|
}
|
|
|
|
|
|
if (TokenHandle != NULL)
|
|
{
|
|
NtClose(TokenHandle);
|
|
}
|
|
|
|
return(scRet);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: DeleteSecurityContext
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
DeleteSecurityContext(
|
|
PCtxtHandle phContext // Context to delete
|
|
)
|
|
{
|
|
SECURITY_STATUS scRet;
|
|
|
|
PAGED_CODE();
|
|
|
|
// For now, just delete the LSA context:
|
|
|
|
if (!phContext)
|
|
{
|
|
return(SEC_E_INVALID_HANDLE);
|
|
}
|
|
|
|
scRet = NtlmDeleteKernelContext(phContext);
|
|
|
|
|
|
return(scRet);
|
|
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: ApplyControlToken
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
ApplyControlToken(
|
|
PCtxtHandle phContext, // Context to modify
|
|
PSecBufferDesc pInput // Input token to apply
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
|
|
|
|
return(SEC_E_UNSUPPORTED_FUNCTION);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: EnumerateSecurityPackagesW
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
EnumerateSecurityPackagesW(
|
|
unsigned long SEC_FAR * pcPackages, // Receives num. packages
|
|
PSecPkgInfo SEC_FAR * ppPackageInfo // Receives array of info
|
|
)
|
|
{
|
|
ULONG PackageInfoSize;
|
|
PSecPkgInfoW PackageInfo = NULL;
|
|
PUCHAR Where;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Figure out the size of the returned data
|
|
//
|
|
|
|
PackageInfoSize = sizeof(SecPkgInfoW) +
|
|
sizeof(NTLMSP_NAME) +
|
|
sizeof(NTLMSP_COMMENT);
|
|
|
|
PackageInfo = (PSecPkgInfoW) SecAllocate(PackageInfoSize);
|
|
|
|
if (PackageInfo == NULL)
|
|
{
|
|
return(SEC_E_INSUFFICIENT_MEMORY);
|
|
}
|
|
|
|
//
|
|
// Fill in the fixed length fields
|
|
//
|
|
|
|
PackageInfo->fCapabilities = SECPKG_FLAG_CONNECTION |
|
|
SECPKG_FLAG_TOKEN_ONLY;
|
|
PackageInfo->wVersion = NTLMSP_VERSION;
|
|
PackageInfo->wRPCID = NTLMSP_RPCID;
|
|
PackageInfo->cbMaxToken = NTLMSSP_MAX_MESSAGE_SIZE;
|
|
|
|
//
|
|
// Fill in the fields
|
|
//
|
|
|
|
Where = (PUCHAR) (PackageInfo+1);
|
|
PackageInfo->Name = (LPWSTR) Where;
|
|
RtlCopyMemory(
|
|
PackageInfo->Name,
|
|
NTLMSP_NAME,
|
|
sizeof(NTLMSP_NAME)
|
|
);
|
|
Where += sizeof(NTLMSP_NAME);
|
|
|
|
PackageInfo->Comment = (LPWSTR) Where;
|
|
RtlCopyMemory(
|
|
PackageInfo->Comment,
|
|
NTLMSP_COMMENT,
|
|
sizeof(NTLMSP_COMMENT)
|
|
);
|
|
Where += sizeof(NTLMSP_COMMENT);
|
|
|
|
|
|
*pcPackages = 1;
|
|
*ppPackageInfo = PackageInfo;
|
|
return(SEC_E_OK);
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: QuerySecurityPackageInfoW
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
QuerySecurityPackageInfoW(
|
|
PSECURITY_STRING pssPackageName, // Name of package
|
|
PSecPkgInfo * ppPackageInfo // Receives package info
|
|
)
|
|
{
|
|
|
|
UNICODE_STRING PackageName;
|
|
ULONG PackageCount;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(
|
|
&PackageName,
|
|
NTLMSP_NAME
|
|
);
|
|
|
|
|
|
if (!RtlEqualUnicodeString(
|
|
pssPackageName,
|
|
&PackageName,
|
|
TRUE // case insensitive
|
|
))
|
|
{
|
|
return(SEC_E_SECPKG_NOT_FOUND);
|
|
}
|
|
|
|
return(EnumerateSecurityPackages(&PackageCount,ppPackageInfo));
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: FreeContextBuffer
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Effects:
|
|
//
|
|
// Arguments:
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
FreeContextBuffer(
|
|
void SEC_FAR * pvContextBuffer
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
|
|
SecFree(pvContextBuffer);
|
|
|
|
return(SEC_E_OK);
|
|
}
|
|
|
|
|
|
//+-------------------------------------------------------------------------
|
|
//
|
|
// Function: GetSecurityUserData
|
|
//
|
|
// Synopsis: retrieves information about a logged on user.
|
|
//
|
|
// Effects: allocates memory to be freed with FreeContextBuffer
|
|
//
|
|
// Arguments: pLogonId - Logon id of the user in question
|
|
// fFlags - Indicates whether the caller want Cairo style names
|
|
// or NT styles names. For NT, this is ignored.
|
|
// ppUserInfo - Recieves information about user
|
|
//
|
|
// Requires:
|
|
//
|
|
// Returns:
|
|
//
|
|
// Notes:
|
|
//
|
|
//
|
|
//--------------------------------------------------------------------------
|
|
|
|
|
|
SECURITY_STATUS SEC_ENTRY
|
|
GetSecurityUserInfo(
|
|
IN PLUID pLogonId,
|
|
IN ULONG fFlags,
|
|
OUT PSecurityUserData * ppUserInfo)
|
|
{
|
|
NTSTATUS Status, FinalStatus;
|
|
PVOID GetInfoBuffer = NULL;
|
|
PVOID GetInfoResponseBuffer = NULL;
|
|
PMSV1_0_GETUSERINFO_REQUEST GetInfoRequest;
|
|
PMSV1_0_GETUSERINFO_RESPONSE GetInfoResponse;
|
|
ULONG ResponseSize;
|
|
ULONG RegionSize = sizeof(MSV1_0_GETUSERINFO_REQUEST);
|
|
PSecurityUserData UserInfo = NULL;
|
|
ULONG UserInfoSize;
|
|
PUCHAR Where;
|
|
SECURITY_STATUS scRet;
|
|
PClient Client = NULL;
|
|
|
|
|
|
scRet = IsOkayToExec(&Client);
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
return(scRet);
|
|
}
|
|
|
|
//
|
|
// Allocate virtual memory for the response buffer.
|
|
//
|
|
|
|
Status = ZwAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&GetInfoBuffer, 0L,
|
|
&RegionSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
GetInfoRequest = GetInfoBuffer;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
scRet = Status;
|
|
goto Cleanup;
|
|
}
|
|
|
|
GetInfoRequest->MessageType = MsV1_0GetUserInfo;
|
|
|
|
RtlCopyLuid(&GetInfoRequest->LogonId, pLogonId);
|
|
|
|
Status = LsaCallAuthenticationPackage(
|
|
Client->hPort,
|
|
PackageId,
|
|
GetInfoRequest,
|
|
RegionSize,
|
|
&GetInfoResponseBuffer,
|
|
&ResponseSize,
|
|
&FinalStatus);
|
|
|
|
GetInfoResponse = GetInfoResponseBuffer;
|
|
|
|
if (!NT_SUCCESS(Status)) {
|
|
GetInfoResponseBuffer = NULL;
|
|
scRet = Status;
|
|
goto Cleanup;
|
|
}
|
|
|
|
|
|
if (!NT_SUCCESS(FinalStatus)) {
|
|
scRet = FinalStatus;
|
|
goto Cleanup;
|
|
}
|
|
|
|
ASSERT(GetInfoResponse->MessageType == MsV1_0GetUserInfo);
|
|
|
|
//
|
|
// Build a SecurityUserData
|
|
//
|
|
|
|
UserInfoSize = sizeof(SecurityUserData) +
|
|
GetInfoResponse->UserName.MaximumLength +
|
|
GetInfoResponse->LogonDomainName.MaximumLength +
|
|
GetInfoResponse->LogonServer.MaximumLength +
|
|
RtlLengthSid(GetInfoResponse->UserSid);
|
|
|
|
|
|
|
|
scRet = ZwAllocateVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&UserInfo,
|
|
0L,
|
|
&UserInfoSize,
|
|
MEM_COMMIT,
|
|
PAGE_READWRITE
|
|
);
|
|
if (!NT_SUCCESS(scRet))
|
|
{
|
|
goto Cleanup;
|
|
}
|
|
|
|
//
|
|
// Pack in the SID first, to respectalignment boundaries.
|
|
//
|
|
|
|
Where = (PUCHAR) (UserInfo + 1);
|
|
UserInfo->pSid = (PSID) (Where);
|
|
RtlCopySid(
|
|
UserInfoSize,
|
|
Where,
|
|
GetInfoResponse->UserSid
|
|
);
|
|
Where += RtlLengthSid(Where);
|
|
|
|
//
|
|
// Pack in the strings
|
|
//
|
|
|
|
PutString(
|
|
(PSTRING) &UserInfo->UserName,
|
|
(PSTRING) &GetInfoResponse->UserName,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
(PSTRING) &UserInfo->LogonDomainName,
|
|
(PSTRING) &GetInfoResponse->LogonDomainName,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
PutString(
|
|
(PSTRING) &UserInfo->LogonServer,
|
|
(PSTRING) &GetInfoResponse->LogonServer,
|
|
0,
|
|
&Where
|
|
);
|
|
|
|
*ppUserInfo = UserInfo;
|
|
UserInfo = NULL;
|
|
scRet = STATUS_SUCCESS;
|
|
|
|
Cleanup:
|
|
if (GetInfoRequest != NULL)
|
|
{
|
|
ZwFreeVirtualMemory(
|
|
NtCurrentProcess(),
|
|
&GetInfoRequest,
|
|
&RegionSize,
|
|
MEM_RELEASE
|
|
);
|
|
|
|
}
|
|
|
|
if (UserInfo != NULL)
|
|
{
|
|
FreeContextBuffer(UserInfo);
|
|
}
|
|
|
|
if (GetInfoResponseBuffer != NULL)
|
|
{
|
|
LsaFreeReturnBuffer(GetInfoResponseBuffer);
|
|
}
|
|
|
|
return(scRet);
|
|
}
|
|
|