2595 lines
63 KiB
C
2595 lines
63 KiB
C
/*++
|
||
|
||
Copyright (c) 1991 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
nlp.c
|
||
|
||
Abstract:
|
||
|
||
This file is the contains private routines which support
|
||
for the LAN Manager portions of the MSV1_0 authentication package.
|
||
|
||
Author:
|
||
|
||
Cliff Van Dyke 29-Apr-1991
|
||
|
||
Revision History:
|
||
Chandana Surlu 21-Jul-96 Stolen from \\kernel\razzle3\src\security\msv1_0\nlp.c
|
||
|
||
--*/
|
||
|
||
#include <global.h>
|
||
|
||
#include "msp.h"
|
||
#include "nlp.h"
|
||
#include "nlpcache.h"
|
||
|
||
#include "msvwow.h"
|
||
|
||
DWORD
|
||
NlpCopyDomainRelativeSid(
|
||
OUT PSID TargetSid,
|
||
IN PSID DomainId,
|
||
IN ULONG RelativeId
|
||
);
|
||
|
||
VOID
|
||
NlpPutString(
|
||
IN PUNICODE_STRING OutString,
|
||
IN PUNICODE_STRING InString,
|
||
IN PUCHAR *Where
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the InString string to the memory pointed to by
|
||
the Where parameter, and fixes the OutString string to point to that
|
||
new copy.
|
||
|
||
Parameters:
|
||
|
||
OutString - A pointer to a destination NT string
|
||
|
||
InString - A pointer to an NT string to be copied
|
||
|
||
Where - A pointer to space to put the actual string for the
|
||
OutString. The pointer is adjusted to point to the first byte
|
||
following the copied string.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSERT( OutString != NULL );
|
||
ASSERT( InString != NULL );
|
||
ASSERT( Where != NULL && *Where != NULL);
|
||
ASSERT( *Where == ROUND_UP_POINTER( *Where, sizeof(WCHAR) ) );
|
||
#ifdef notdef
|
||
KdPrint(("NlpPutString: %ld %Z\n", InString->Length, InString ));
|
||
KdPrint((" InString: %lx %lx OutString: %lx Where: %lx\n", InString,
|
||
InString->Buffer, OutString, *Where ));
|
||
#endif
|
||
|
||
if ( InString->Length > 0 ) {
|
||
|
||
OutString->Buffer = (PWCH) *Where;
|
||
OutString->MaximumLength = (USHORT)(InString->Length + sizeof(WCHAR));
|
||
|
||
RtlCopyUnicodeString( OutString, InString );
|
||
|
||
*Where += InString->Length;
|
||
// *((WCHAR *)(*Where)) = L'\0';
|
||
*(*Where) = '\0';
|
||
*(*Where + 1) = '\0';
|
||
*Where += 2;
|
||
|
||
} else {
|
||
RtlInitUnicodeString(OutString, NULL);
|
||
}
|
||
#ifdef notdef
|
||
KdPrint((" OutString: %ld %lx\n", OutString->Length, OutString->Buffer));
|
||
#endif
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
NlpInitClientBuffer(
|
||
OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
|
||
IN PLSA_CLIENT_REQUEST ClientRequest
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine initializes a ClientBufferDescriptor to known values.
|
||
This routine must be called before any of the other routines that use
|
||
the ClientBufferDescriptor.
|
||
|
||
Parameters:
|
||
|
||
ClientBufferDesc - Descriptor of a buffer allocated in the client's
|
||
address space.
|
||
|
||
ClientRequest - Is a pointer to an opaque data structure
|
||
representing the client's request.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Fill in a pointer to the ClientRequest and zero the rest.
|
||
//
|
||
|
||
ClientBufferDesc->ClientRequest = ClientRequest;
|
||
ClientBufferDesc->UserBuffer = NULL;
|
||
ClientBufferDesc->MsvBuffer = NULL;
|
||
ClientBufferDesc->StringOffset = 0;
|
||
ClientBufferDesc->TotalSize = 0;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpAllocateClientBuffer(
|
||
IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
|
||
IN ULONG FixedSize,
|
||
IN ULONG TotalSize
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates a buffer in the clients address space.
|
||
It also allocates a mirror buffer in MSV's address space.
|
||
|
||
The data will be constructed in the MSV's address space then 'flushed'
|
||
into the client's address space.
|
||
|
||
Parameters:
|
||
|
||
ClientBufferDesc - Descriptor of a buffer allocated in the client's
|
||
address space.
|
||
|
||
FixedSize - The size in bytes of the fixed portion of the buffer.
|
||
|
||
TotalSize - The size in bytes of the entire buffer.
|
||
|
||
Return Values:
|
||
|
||
Status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Allocate the Mirror buffer.
|
||
//
|
||
|
||
ASSERT( ClientBufferDesc->MsvBuffer == NULL );
|
||
ClientBufferDesc->MsvBuffer = I_NtLmAllocate( TotalSize );
|
||
|
||
if ( ClientBufferDesc->MsvBuffer == NULL ) {
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
|
||
|
||
//
|
||
// Allocate the client's buffer
|
||
//
|
||
|
||
ASSERT( ClientBufferDesc->UserBuffer == NULL );
|
||
if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
|
||
{
|
||
ClientBufferDesc->UserBuffer = (*(Lsa.AllocateLsaHeap))(TotalSize);
|
||
}
|
||
else
|
||
{
|
||
Status = (*Lsa.AllocateClientBuffer)(
|
||
ClientBufferDesc->ClientRequest,
|
||
TotalSize,
|
||
(PVOID *)&ClientBufferDesc->UserBuffer );
|
||
}
|
||
|
||
if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
|
||
{
|
||
if (ClientBufferDesc->UserBuffer == NULL)
|
||
{
|
||
NlpFreeClientBuffer( ClientBufferDesc );
|
||
return STATUS_NO_MEMORY;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
ClientBufferDesc->UserBuffer = NULL;
|
||
NlpFreeClientBuffer( ClientBufferDesc );
|
||
return Status;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Return
|
||
//
|
||
|
||
ClientBufferDesc->StringOffset = FixedSize;
|
||
ClientBufferDesc->TotalSize = TotalSize;
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpFlushClientBuffer(
|
||
IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
|
||
OUT PVOID* UserBuffer
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Copy the Mirror Buffer into the Client's address space.
|
||
|
||
Parameters:
|
||
|
||
ClientBufferDesc - Descriptor of a buffer allocated in the client's
|
||
address space.
|
||
|
||
UserBuffer - If successful, returns a pointer to the user's buffer.
|
||
(The caller is now resposible for deallocating the buffer.)
|
||
|
||
Return Values:
|
||
|
||
Status of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
|
||
//
|
||
// Copy the data to the client's address space.
|
||
//
|
||
|
||
if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
|
||
{
|
||
RtlCopyMemory(
|
||
ClientBufferDesc->UserBuffer,
|
||
ClientBufferDesc->MsvBuffer,
|
||
ClientBufferDesc->TotalSize);
|
||
}
|
||
else
|
||
{
|
||
Status = (*Lsa.CopyToClientBuffer)(
|
||
ClientBufferDesc->ClientRequest,
|
||
ClientBufferDesc->TotalSize,
|
||
ClientBufferDesc->UserBuffer,
|
||
ClientBufferDesc->MsvBuffer );
|
||
}
|
||
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Mark that we're no longer responsible for the client's buffer.
|
||
//
|
||
|
||
*UserBuffer = (PVOID) ClientBufferDesc->UserBuffer;
|
||
ClientBufferDesc->UserBuffer = NULL;
|
||
|
||
//
|
||
// Free the mirror buffer
|
||
//
|
||
|
||
NlpFreeClientBuffer( ClientBufferDesc );
|
||
|
||
|
||
return STATUS_SUCCESS;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NlpFreeClientBuffer(
|
||
IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Free any Mirror Buffer or Client buffer.
|
||
|
||
Parameters:
|
||
|
||
ClientBufferDesc - Descriptor of a buffer allocated in the client's
|
||
address space.
|
||
|
||
Return Values:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Free the mirror buffer.
|
||
//
|
||
|
||
if ( ClientBufferDesc->MsvBuffer != NULL ) {
|
||
I_NtLmFree( ClientBufferDesc->MsvBuffer );
|
||
ClientBufferDesc->MsvBuffer = NULL;
|
||
}
|
||
|
||
//
|
||
// Free the Client's buffer
|
||
//
|
||
|
||
if ((ClientBufferDesc->ClientRequest == (PLSA_CLIENT_REQUEST) (-1)))
|
||
{
|
||
if ( ClientBufferDesc->UserBuffer != NULL ) {
|
||
(*Lsa.FreeLsaHeap)(ClientBufferDesc->UserBuffer);
|
||
ClientBufferDesc->UserBuffer = NULL;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if ( ClientBufferDesc->UserBuffer != NULL ) {
|
||
(VOID) (*Lsa.FreeClientBuffer)( ClientBufferDesc->ClientRequest,
|
||
ClientBufferDesc->UserBuffer );
|
||
ClientBufferDesc->UserBuffer = NULL;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NlpPutClientString(
|
||
IN OUT PCLIENT_BUFFER_DESC ClientBufferDesc,
|
||
IN PUNICODE_STRING OutString,
|
||
IN PUNICODE_STRING InString
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine copies the InString string to the memory pointed to by
|
||
ClientBufferDesc->StringOffset, and fixes the OutString string to point
|
||
to that new copy.
|
||
|
||
|
||
Parameters:
|
||
|
||
ClientBufferDesc - Descriptor of a buffer allocated in the client's
|
||
address space.
|
||
|
||
InString - A pointer to an NT string to be copied
|
||
|
||
OutString - A pointer to a destination NT string. This string structure
|
||
is in the "Mirror" allocated buffer.
|
||
|
||
Return Status:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
//
|
||
// Ensure our caller passed good data.
|
||
//
|
||
|
||
ASSERT( OutString != NULL );
|
||
ASSERT( InString != NULL );
|
||
ASSERT( COUNT_IS_ALIGNED( ClientBufferDesc->StringOffset, sizeof(WCHAR)) );
|
||
ASSERT( (LPBYTE)OutString >= ClientBufferDesc->MsvBuffer );
|
||
ASSERT( (LPBYTE)OutString <
|
||
ClientBufferDesc->MsvBuffer + ClientBufferDesc->TotalSize - sizeof(UNICODE_STRING) );
|
||
|
||
ASSERT( ClientBufferDesc->StringOffset + InString->Length + sizeof(WCHAR) <=
|
||
ClientBufferDesc->TotalSize );
|
||
|
||
#ifdef notdef
|
||
KdPrint(("NlpPutClientString: %ld %Z\n", InString->Length, InString ));
|
||
KdPrint((" Orig: UserBuffer: %lx Offset: 0x%lx TotalSize: 0x%lx\n",
|
||
ClientBufferDesc->UserBuffer,
|
||
ClientBufferDesc->StringOffset,
|
||
ClientBufferDesc->TotalSize ));
|
||
#endif
|
||
|
||
//
|
||
// Build a string structure and copy the text to the Mirror buffer.
|
||
//
|
||
|
||
if ( InString->Length > 0 ) {
|
||
|
||
//
|
||
// Copy the string (Add a zero character)
|
||
//
|
||
|
||
RtlCopyMemory(
|
||
ClientBufferDesc->MsvBuffer + ClientBufferDesc->StringOffset,
|
||
InString->Buffer,
|
||
InString->Length );
|
||
|
||
// Do one byte at a time since some callers don't pass in an even
|
||
// InString->Length
|
||
*(ClientBufferDesc->MsvBuffer + ClientBufferDesc->StringOffset +
|
||
InString->Length) = '\0';
|
||
*(ClientBufferDesc->MsvBuffer + ClientBufferDesc->StringOffset +
|
||
InString->Length+1) = '\0';
|
||
|
||
//
|
||
// Build the string structure to point to the data in the client's
|
||
// address space.
|
||
//
|
||
|
||
OutString->Buffer = (PWSTR)(ClientBufferDesc->UserBuffer +
|
||
ClientBufferDesc->StringOffset);
|
||
OutString->Length = InString->Length;
|
||
OutString->MaximumLength = OutString->Length + sizeof(WCHAR);
|
||
|
||
//
|
||
// Adjust the offset to past the newly copied string.
|
||
//
|
||
|
||
ClientBufferDesc->StringOffset += OutString->MaximumLength;
|
||
|
||
} else {
|
||
RtlInitUnicodeString(OutString, NULL);
|
||
}
|
||
|
||
#ifdef notdef
|
||
KdPrint((" New: Offset: 0x%lx StringStart: %lx\n",
|
||
ClientBufferDesc->StringOffset,
|
||
OutString->Buffer ));
|
||
#endif
|
||
|
||
return;
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
NlpMakeRelativeString(
|
||
IN PUCHAR BaseAddress,
|
||
IN OUT PUNICODE_STRING String
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts the buffer address in the specified string to
|
||
be a byte offset from BaseAddress.
|
||
|
||
Parameters:
|
||
|
||
BaseAddress - A pointer to make the destination address relative to.
|
||
|
||
String - A pointer to a NT string to make relative.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSERT( BaseAddress != NULL );
|
||
ASSERT( String != NULL );
|
||
ASSERT( sizeof(ULONG_PTR) == sizeof(String->Buffer) );
|
||
|
||
if ( String->Buffer != NULL ) {
|
||
*((PULONG_PTR)(&String->Buffer)) =
|
||
(ULONG_PTR)((PUCHAR)String->Buffer - (PUCHAR)BaseAddress);
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
VOID
|
||
NlpRelativeToAbsolute(
|
||
IN PVOID BaseAddress,
|
||
IN OUT PULONG_PTR RelativeValue
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine converts the byte offset from BaseAddress to be an
|
||
absolute address.
|
||
|
||
Parameters:
|
||
|
||
BaseAddress - A pointer the destination address is relative to.
|
||
|
||
RelativeValue - A pointer to a relative value to make absolute.
|
||
|
||
Return Values:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
ASSERT( BaseAddress != NULL );
|
||
ASSERT( RelativeValue != NULL );
|
||
|
||
if ( *((PUCHAR *)RelativeValue) != NULL ) {
|
||
*RelativeValue = (ULONG_PTR)((PUCHAR)BaseAddress + (*RelativeValue));
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
BOOLEAN
|
||
NlpFindActiveLogon(
|
||
IN PLUID LogonId,
|
||
OUT PACTIVE_LOGON **ActiveLogon
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine finds the specified Logon Id in the ActiveLogon table.
|
||
It returns a boolean indicating whether the Logon Id exists in the
|
||
ActiveLogon Table. If so, this routine also returns a pointer to a
|
||
pointer to the appropriate entry in the table. If not, this routine
|
||
returns a pointer to where such an entry would be inserted in the table.
|
||
|
||
This routine must be called with the NlpActiveLogonLock locked.
|
||
|
||
Parameters:
|
||
|
||
LogonId - The LogonId of the logon to find in the table.
|
||
|
||
ActiveLogon - If the specified logon Id exists, returns a pointer to a
|
||
pointer to the appropriate entry in the table. Otherwise,
|
||
returns a pointer to where such an entry would be inserted in the
|
||
table.
|
||
|
||
Return Values:
|
||
|
||
TRUE - The specified LogonId already exists in the table.
|
||
|
||
FALSE - The specified LogonId does not exist in the table.
|
||
|
||
--*/
|
||
|
||
{
|
||
PACTIVE_LOGON *Logon;
|
||
|
||
//
|
||
// Loop through the table looking for this particular LogonId.
|
||
//
|
||
|
||
for( Logon = &NlpActiveLogons; *Logon != NULL; Logon = &((*Logon)->Next) ) {
|
||
if (RtlCompareMemory( &(*Logon)->LogonId, LogonId, sizeof(*LogonId))
|
||
== sizeof(*LogonId) ) {
|
||
|
||
*ActiveLogon = Logon;
|
||
return TRUE;
|
||
}
|
||
}
|
||
|
||
//
|
||
// By returning a pointer to the NULL at the end of the list, we
|
||
// are forcing new entries to be placed at the end. The list is
|
||
// thereby maintained in the order that the logon occurred.
|
||
// MsV1_0EnumerateUsers relies on this behavior.
|
||
//
|
||
|
||
*ActiveLogon = Logon;
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
ULONG
|
||
NlpCountActiveLogon(
|
||
IN PUNICODE_STRING LogonDomainName,
|
||
IN PUNICODE_STRING UserName
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine counts the number of time a particular user is logged on
|
||
in the Active Logon Table.
|
||
|
||
Parameters:
|
||
|
||
LogonDomainName - Domain in which this user account is defined.
|
||
|
||
UserName - The user name to count the active logons for.
|
||
|
||
Return Values:
|
||
|
||
The count of active logons for the specified user.
|
||
|
||
--*/
|
||
|
||
{
|
||
PACTIVE_LOGON Logon;
|
||
ULONG LogonCount = 0;
|
||
|
||
|
||
//
|
||
// Loop through the table looking for this particular LogonId.
|
||
//
|
||
|
||
NlpLockActiveLogonsRead();
|
||
|
||
for( Logon = NlpActiveLogons; Logon != NULL; Logon = Logon->Next ) {
|
||
|
||
if(RtlEqualUnicodeString( UserName, &Logon->UserName, (BOOLEAN) TRUE) &&
|
||
RtlEqualDomainName(LogonDomainName,&Logon->LogonDomainName )){
|
||
LogonCount ++;
|
||
}
|
||
|
||
}
|
||
|
||
NlpUnlockActiveLogons();
|
||
|
||
return LogonCount;
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
NlpAllocateInteractiveProfile (
|
||
IN PLSA_CLIENT_REQUEST ClientRequest,
|
||
OUT PMSV1_0_INTERACTIVE_PROFILE *ProfileBuffer,
|
||
OUT PULONG ProfileBufferSize,
|
||
IN PNETLOGON_VALIDATION_SAM_INFO4 NlpUser
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This allocates and fills in the clients interactive profile.
|
||
|
||
Arguments:
|
||
|
||
ClientRequest - Is a pointer to an opaque data structure
|
||
representing the client's request.
|
||
|
||
ProfileBuffer - Is used to return the address of the profile
|
||
buffer in the client process. This routine is
|
||
responsible for allocating and returning the profile buffer
|
||
within the client process. However, if the caller subsequently
|
||
encounters an error which prevents a successful logon, then
|
||
then it will take care of deallocating the buffer. This
|
||
buffer is allocated with the AllocateClientBuffer() service.
|
||
|
||
ProfileBufferSize - Receives the Size (in bytes) of the
|
||
returned profile buffer.
|
||
|
||
NlpUser - Contains the validation information which is
|
||
to be copied in the ProfileBuffer.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
CLIENT_BUFFER_DESC ClientBufferDesc;
|
||
PMSV1_0_INTERACTIVE_PROFILE LocalProfileBuffer;
|
||
|
||
#if _WIN64
|
||
|
||
if( ClientRequest != (PLSA_CLIENT_REQUEST)( -1 ) )
|
||
{
|
||
SECPKG_CALL_INFO CallInfo;
|
||
|
||
//
|
||
// if the call originated outproc, need to check if wow64.
|
||
//
|
||
|
||
if(!LsaFunctions->GetCallInfo(&CallInfo))
|
||
{
|
||
Status = STATUS_INTERNAL_ERROR;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
|
||
{
|
||
return MsvAllocateInteractiveWOWProfile (
|
||
ClientRequest,
|
||
ProfileBuffer,
|
||
ProfileBufferSize,
|
||
NlpUser
|
||
);
|
||
}
|
||
}
|
||
#endif // _WIN64
|
||
|
||
|
||
//
|
||
// Alocate the profile buffer to return to the client
|
||
//
|
||
|
||
NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );
|
||
|
||
*ProfileBuffer = NULL;
|
||
|
||
*ProfileBufferSize = sizeof(MSV1_0_INTERACTIVE_PROFILE) +
|
||
NlpUser->LogonScript.Length + sizeof(WCHAR) +
|
||
NlpUser->HomeDirectory.Length + sizeof(WCHAR) +
|
||
NlpUser->HomeDirectoryDrive.Length + sizeof(WCHAR) +
|
||
NlpUser->FullName.Length + sizeof(WCHAR) +
|
||
NlpUser->ProfilePath.Length + sizeof(WCHAR) +
|
||
NlpUser->LogonServer.Length + sizeof(WCHAR);
|
||
|
||
Status = NlpAllocateClientBuffer( &ClientBufferDesc,
|
||
sizeof(MSV1_0_INTERACTIVE_PROFILE),
|
||
*ProfileBufferSize );
|
||
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
LocalProfileBuffer = (PMSV1_0_INTERACTIVE_PROFILE) ClientBufferDesc.MsvBuffer;
|
||
|
||
//
|
||
// Copy the scalar fields into the profile buffer.
|
||
//
|
||
|
||
LocalProfileBuffer->MessageType = MsV1_0InteractiveProfile;
|
||
LocalProfileBuffer->LogonCount = NlpUser->LogonCount;
|
||
LocalProfileBuffer->BadPasswordCount= NlpUser->BadPasswordCount;
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->LogonTime,
|
||
LocalProfileBuffer->LogonTime );
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->LogoffTime,
|
||
LocalProfileBuffer->LogoffTime );
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->KickOffTime,
|
||
LocalProfileBuffer->KickOffTime );
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordLastSet,
|
||
LocalProfileBuffer->PasswordLastSet );
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordCanChange,
|
||
LocalProfileBuffer->PasswordCanChange );
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordMustChange,
|
||
LocalProfileBuffer->PasswordMustChange );
|
||
LocalProfileBuffer->UserFlags = NlpUser->UserFlags;
|
||
|
||
//
|
||
// Copy the Unicode strings into the profile buffer.
|
||
//
|
||
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfileBuffer->LogonScript,
|
||
&NlpUser->LogonScript );
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfileBuffer->HomeDirectory,
|
||
&NlpUser->HomeDirectory );
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfileBuffer->HomeDirectoryDrive,
|
||
&NlpUser->HomeDirectoryDrive );
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfileBuffer->FullName,
|
||
&NlpUser->FullName );
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfileBuffer->ProfilePath,
|
||
&NlpUser->ProfilePath );
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfileBuffer->LogonServer,
|
||
&NlpUser->LogonServer );
|
||
|
||
|
||
//
|
||
// Flush the buffer to the client's address space.
|
||
//
|
||
|
||
Status = NlpFlushClientBuffer( &ClientBufferDesc,
|
||
(PVOID *) ProfileBuffer );
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// If the copy wasn't successful,
|
||
// cleanup resources we would have returned to the caller.
|
||
//
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
NlpFreeClientBuffer( &ClientBufferDesc );
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
|
||
|
||
NTSTATUS
|
||
NlpAllocateNetworkProfile (
|
||
IN PLSA_CLIENT_REQUEST ClientRequest,
|
||
OUT PMSV1_0_LM20_LOGON_PROFILE *ProfileBuffer,
|
||
OUT PULONG ProfileBufferSize,
|
||
IN PNETLOGON_VALIDATION_SAM_INFO4 NlpUser,
|
||
IN ULONG ParameterControl
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This allocates and fills in the clients network profile.
|
||
|
||
Arguments:
|
||
|
||
ClientRequest - Is a pointer to an opaque data structure
|
||
representing the client's request.
|
||
|
||
ProfileBuffer - Is used to return the address of the profile
|
||
buffer in the client process. This routine is
|
||
responsible for allocating and returning the profile buffer
|
||
within the client process. However, if the caller subsequently
|
||
encounters an error which prevents a successful logon, then
|
||
then it will take care of deallocating the buffer. This
|
||
buffer is allocated with the AllocateClientBuffer() service.
|
||
|
||
ProfileBufferSize - Receives the Size (in bytes) of the
|
||
returned profile buffer.
|
||
|
||
NlpUser - Contains the validation information which is
|
||
to be copied in the ProfileBuffer. Will be NULL to indicate a
|
||
NULL session.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
NTSTATUS SubAuthStatus = STATUS_SUCCESS;
|
||
|
||
CLIENT_BUFFER_DESC ClientBufferDesc;
|
||
PMSV1_0_LM20_LOGON_PROFILE LocalProfile;
|
||
|
||
#if _WIN64
|
||
|
||
if( ClientRequest != (PLSA_CLIENT_REQUEST)( -1 ) )
|
||
{
|
||
SECPKG_CALL_INFO CallInfo;
|
||
|
||
//
|
||
// if the call originated outproc, need to check if wow64.
|
||
//
|
||
|
||
if(!LsaFunctions->GetCallInfo(&CallInfo))
|
||
{
|
||
Status = STATUS_INTERNAL_ERROR;
|
||
goto Cleanup;
|
||
}
|
||
|
||
if (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT)
|
||
{
|
||
return MsvAllocateNetworkWOWProfile (
|
||
ClientRequest,
|
||
ProfileBuffer,
|
||
ProfileBufferSize,
|
||
NlpUser,
|
||
ParameterControl
|
||
);
|
||
}
|
||
}
|
||
#endif // _WIN64
|
||
|
||
|
||
//
|
||
// Alocate the profile buffer to return to the client
|
||
//
|
||
|
||
NlpInitClientBuffer( &ClientBufferDesc, ClientRequest );
|
||
|
||
*ProfileBuffer = NULL;
|
||
*ProfileBufferSize = sizeof(MSV1_0_LM20_LOGON_PROFILE);
|
||
|
||
if ( NlpUser != NULL ) {
|
||
*ProfileBufferSize += NlpUser->LogonDomainName.Length + sizeof(WCHAR) +
|
||
NlpUser->LogonServer.Length + sizeof(WCHAR) +
|
||
NlpUser->HomeDirectoryDrive.Length + sizeof(WCHAR);
|
||
}
|
||
|
||
|
||
Status = NlpAllocateClientBuffer( &ClientBufferDesc,
|
||
sizeof(MSV1_0_LM20_LOGON_PROFILE),
|
||
*ProfileBufferSize );
|
||
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
goto Cleanup;
|
||
}
|
||
|
||
LocalProfile = (PMSV1_0_LM20_LOGON_PROFILE) ClientBufferDesc.MsvBuffer;
|
||
LocalProfile->MessageType = MsV1_0Lm20LogonProfile;
|
||
|
||
|
||
//
|
||
// For a NULL session, return a constant profile buffer
|
||
//
|
||
|
||
if ( NlpUser == NULL ) {
|
||
|
||
LocalProfile->KickOffTime.HighPart = 0x7FFFFFFF;
|
||
LocalProfile->KickOffTime.LowPart = 0xFFFFFFFF;
|
||
LocalProfile->LogoffTime.HighPart = 0x7FFFFFFF;
|
||
LocalProfile->LogoffTime.LowPart = 0xFFFFFFFF;
|
||
LocalProfile->UserFlags = 0;
|
||
RtlZeroMemory( LocalProfile->UserSessionKey,
|
||
sizeof(LocalProfile->UserSessionKey));
|
||
RtlZeroMemory( LocalProfile->LanmanSessionKey,
|
||
sizeof(LocalProfile->LanmanSessionKey));
|
||
RtlInitUnicodeString( &LocalProfile->LogonDomainName, NULL );
|
||
RtlInitUnicodeString( &LocalProfile->LogonServer, NULL );
|
||
RtlInitUnicodeString( &LocalProfile->UserParameters, NULL );
|
||
|
||
|
||
//
|
||
// For non-null sessions,
|
||
// fill in the profile buffer.
|
||
//
|
||
|
||
} else {
|
||
|
||
//
|
||
// Copy the individual scalar fields into the profile buffer.
|
||
//
|
||
|
||
if ((ParameterControl & MSV1_0_RETURN_PASSWORD_EXPIRY) != 0) {
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->PasswordMustChange,
|
||
LocalProfile->LogoffTime);
|
||
} else {
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->LogoffTime,
|
||
LocalProfile->LogoffTime);
|
||
}
|
||
OLD_TO_NEW_LARGE_INTEGER( NlpUser->KickOffTime,
|
||
LocalProfile->KickOffTime);
|
||
LocalProfile->UserFlags = NlpUser->UserFlags;
|
||
|
||
RtlCopyMemory( LocalProfile->UserSessionKey,
|
||
&NlpUser->UserSessionKey,
|
||
sizeof(LocalProfile->UserSessionKey) );
|
||
|
||
ASSERT( SAMINFO_LM_SESSION_KEY_SIZE ==
|
||
sizeof(LocalProfile->LanmanSessionKey) );
|
||
RtlCopyMemory(
|
||
LocalProfile->LanmanSessionKey,
|
||
&NlpUser->ExpansionRoom[SAMINFO_LM_SESSION_KEY],
|
||
SAMINFO_LM_SESSION_KEY_SIZE );
|
||
|
||
|
||
// We need to extract the true status sent back for subauth users,
|
||
// but not by a sub auth package
|
||
|
||
SubAuthStatus = NlpUser->ExpansionRoom[SAMINFO_SUBAUTH_STATUS];
|
||
|
||
//
|
||
// Copy the Unicode strings into the profile buffer.
|
||
//
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfile->LogonDomainName,
|
||
&NlpUser->LogonDomainName );
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfile->LogonServer,
|
||
&NlpUser->LogonServer );
|
||
|
||
//
|
||
// Kludge: Pass back UserParameters in HomeDirectoryDrive since we
|
||
// can't change the NETLOGON_VALIDATION_SAM_INFO structure between
|
||
// releases NT 1.0 and NT 1.0A. HomeDirectoryDrive was NULL for release 1.0A
|
||
// so we'll use that field.
|
||
//
|
||
|
||
NlpPutClientString( &ClientBufferDesc,
|
||
&LocalProfile->UserParameters,
|
||
&NlpUser->HomeDirectoryDrive );
|
||
|
||
}
|
||
|
||
//
|
||
// Flush the buffer to the client's address space.
|
||
//
|
||
|
||
Status = NlpFlushClientBuffer( &ClientBufferDesc,
|
||
ProfileBuffer );
|
||
|
||
Cleanup:
|
||
|
||
//
|
||
// If the copy wasn't successful,
|
||
// cleanup resources we would have returned to the caller.
|
||
//
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
NlpFreeClientBuffer( &ClientBufferDesc );
|
||
}
|
||
|
||
// Save the status for subauth logons
|
||
|
||
if (NT_SUCCESS(Status) && !NT_SUCCESS(SubAuthStatus))
|
||
{
|
||
Status = SubAuthStatus;
|
||
}
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
PSID
|
||
NlpMakeDomainRelativeSid(
|
||
IN PSID DomainId,
|
||
IN ULONG RelativeId
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a domain Id and a relative ID create the corresponding SID allocated
|
||
from the LSA heap.
|
||
|
||
Arguments:
|
||
|
||
DomainId - The template SID to use.
|
||
|
||
RelativeId - The relative Id to append to the DomainId.
|
||
|
||
Return Value:
|
||
|
||
Sid - Returns a pointer to a buffer allocated from the LsaHeap
|
||
containing the resultant Sid.
|
||
|
||
--*/
|
||
{
|
||
UCHAR DomainIdSubAuthorityCount;
|
||
ULONG Size;
|
||
PSID Sid;
|
||
|
||
//
|
||
// Allocate a Sid which has one more sub-authority than the domain ID.
|
||
//
|
||
|
||
DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
|
||
Size = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
|
||
|
||
if ((Sid = (*Lsa.AllocateLsaHeap)( Size )) == NULL ) {
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Initialize the new SID to have the same inital value as the
|
||
// domain ID.
|
||
//
|
||
|
||
if ( !NT_SUCCESS( RtlCopySid( Size, Sid, DomainId ) ) ) {
|
||
(*Lsa.FreeLsaHeap)( Sid );
|
||
return NULL;
|
||
}
|
||
|
||
//
|
||
// Adjust the sub-authority count and
|
||
// add the relative Id unique to the newly allocated SID
|
||
//
|
||
|
||
(*(RtlSubAuthorityCountSid( Sid ))) ++;
|
||
*RtlSubAuthoritySid( Sid, DomainIdSubAuthorityCount ) = RelativeId;
|
||
|
||
|
||
return Sid;
|
||
}
|
||
|
||
|
||
|
||
PSID
|
||
NlpCopySid(
|
||
IN PSID * Sid
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Given a SID allocatees space for a new SID from the LSA heap and copies
|
||
the original SID.
|
||
|
||
Arguments:
|
||
|
||
Sid - The original SID.
|
||
|
||
Return Value:
|
||
|
||
Sid - Returns a pointer to a buffer allocated from the LsaHeap
|
||
containing the resultant Sid.
|
||
|
||
--*/
|
||
{
|
||
PSID NewSid;
|
||
ULONG Size;
|
||
|
||
Size = RtlLengthSid( Sid );
|
||
|
||
|
||
|
||
if ((NewSid = (*Lsa.AllocateLsaHeap)( Size )) == NULL ) {
|
||
return NULL;
|
||
}
|
||
|
||
|
||
if ( !NT_SUCCESS( RtlCopySid( Size, NewSid, Sid ) ) ) {
|
||
(*Lsa.FreeLsaHeap)( NewSid );
|
||
return NULL;
|
||
}
|
||
|
||
|
||
return NewSid;
|
||
}
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Function: NlpMakeTokenInformationV2
|
||
//
|
||
// Synopsis: This routine makes copies of all the pertinent
|
||
// information from the UserInfo and generates a
|
||
// LSA_TOKEN_INFORMATION_V2 data structure.
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments:
|
||
//
|
||
// UserInfo - Contains the validation information which is
|
||
// to be copied into the TokenInformation.
|
||
//
|
||
// TokenInformation - Returns a pointer to a properly Version 1 token
|
||
// information structures. The structure and individual fields are
|
||
// allocated properly as described in ntlsa.h.
|
||
//
|
||
// Requires:
|
||
//
|
||
// Returns: STATUS_SUCCESS - Indicates the service completed successfully.
|
||
//
|
||
// STATUS_INSUFFICIENT_RESOURCES - This error indicates that
|
||
// the logon could not be completed because the client
|
||
// does not have sufficient quota to allocate the return
|
||
// buffer.
|
||
//
|
||
// Notes: stolen back from from kerberos\client2\krbtoken.cxx.c:KerbMakeTokenInformationV1
|
||
//
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
|
||
NTSTATUS
|
||
NlpMakeTokenInformationV2(
|
||
IN PNETLOGON_VALIDATION_SAM_INFO4 ValidationInfo,
|
||
OUT PLSA_TOKEN_INFORMATION_V2 *TokenInformation
|
||
)
|
||
{
|
||
PNETLOGON_VALIDATION_SAM_INFO3 UserInfo = (PNETLOGON_VALIDATION_SAM_INFO3) ValidationInfo;
|
||
NTSTATUS Status;
|
||
PLSA_TOKEN_INFORMATION_V2 V2 = NULL;
|
||
ULONG Size, i;
|
||
DWORD NumGroups = 0;
|
||
PBYTE CurrentSid = NULL;
|
||
ULONG SidLength = 0;
|
||
|
||
//
|
||
// Allocate the structure itself
|
||
//
|
||
|
||
Size = (ULONG)sizeof(LSA_TOKEN_INFORMATION_V2);
|
||
|
||
//
|
||
// Allocate an array to hold the groups
|
||
//
|
||
|
||
Size += sizeof(TOKEN_GROUPS);
|
||
|
||
|
||
// Add room for groups passed as RIDS
|
||
NumGroups = UserInfo->GroupCount;
|
||
if(UserInfo->GroupCount)
|
||
{
|
||
Size += UserInfo->GroupCount * (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
|
||
}
|
||
|
||
//
|
||
// If there are extra SIDs, add space for them
|
||
//
|
||
|
||
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
|
||
ULONG i = 0;
|
||
NumGroups += UserInfo->SidCount;
|
||
|
||
// Add room for the sid's themselves
|
||
for(i=0; i < UserInfo->SidCount; i++)
|
||
{
|
||
Size += RtlLengthSid(UserInfo->ExtraSids[i].Sid);
|
||
}
|
||
}
|
||
|
||
//
|
||
// If there are resource groups, add space for them
|
||
//
|
||
if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
|
||
|
||
NumGroups += UserInfo->ResourceGroupCount;
|
||
|
||
if ((UserInfo->ResourceGroupCount != 0) &&
|
||
((UserInfo->ResourceGroupIds == NULL) ||
|
||
(UserInfo->ResourceGroupDomainSid == NULL)))
|
||
{
|
||
Status = STATUS_INVALID_PARAMETER;
|
||
goto Cleanup;
|
||
}
|
||
// Allocate space for the sids
|
||
if(UserInfo->ResourceGroupCount)
|
||
{
|
||
Size += UserInfo->ResourceGroupCount * (RtlLengthSid(UserInfo->ResourceGroupDomainSid) + sizeof(ULONG));
|
||
}
|
||
|
||
}
|
||
|
||
|
||
if( UserInfo->UserId )
|
||
{
|
||
// Size of the user sid and the primary group sid.
|
||
Size += 2*(RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
|
||
}
|
||
else
|
||
{
|
||
if ( UserInfo->SidCount <= 0 ) {
|
||
|
||
Status = STATUS_INSUFFICIENT_LOGON_INFO;
|
||
goto Cleanup;
|
||
}
|
||
|
||
// Size of the primary group sid.
|
||
Size += (RtlLengthSid(UserInfo->LogonDomainId) + sizeof(ULONG));
|
||
}
|
||
|
||
|
||
Size += (NumGroups - ANYSIZE_ARRAY)*sizeof(SID_AND_ATTRIBUTES);
|
||
|
||
|
||
V2 = (PLSA_TOKEN_INFORMATION_V2) (*Lsa.AllocateLsaHeap)( Size );
|
||
if ( V2 == NULL ) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
V2,
|
||
Size
|
||
);
|
||
|
||
V2->Groups = (PTOKEN_GROUPS)(V2+1);
|
||
V2->Groups->GroupCount = 0;
|
||
CurrentSid = (PBYTE)&V2->Groups->Groups[NumGroups];
|
||
|
||
OLD_TO_NEW_LARGE_INTEGER( UserInfo->KickOffTime, V2->ExpirationTime );
|
||
|
||
|
||
|
||
//
|
||
// If the UserId is non-zero, then it contians the users RID.
|
||
//
|
||
|
||
if ( UserInfo->UserId ) {
|
||
V2->User.User.Sid = (PSID)CurrentSid;
|
||
CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->UserId);
|
||
}
|
||
|
||
//
|
||
// Make a copy of the primary group (a required field).
|
||
//
|
||
V2->PrimaryGroup.PrimaryGroup = (PSID)CurrentSid;
|
||
CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->PrimaryGroupId );
|
||
|
||
|
||
|
||
|
||
//
|
||
// Copy over all the groups passed as RIDs
|
||
//
|
||
|
||
for ( i=0; i < UserInfo->GroupCount; i++ ) {
|
||
|
||
V2->Groups->Groups[V2->Groups->GroupCount].Attributes = UserInfo->GroupIds[i].Attributes;
|
||
|
||
V2->Groups->Groups[V2->Groups->GroupCount].Sid = (PSID)CurrentSid;
|
||
CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->LogonDomainId, UserInfo->GroupIds[i].RelativeId);
|
||
|
||
V2->Groups->GroupCount++;
|
||
}
|
||
|
||
|
||
//
|
||
// Add in the extra SIDs
|
||
//
|
||
|
||
if (UserInfo->UserFlags & LOGON_EXTRA_SIDS) {
|
||
|
||
ULONG index = 0;
|
||
//
|
||
// If the user SID wasn't passed as a RID, it is the first
|
||
// SID.
|
||
//
|
||
|
||
if ( !V2->User.User.Sid ) {
|
||
V2->User.User.Sid = (PSID)CurrentSid;
|
||
SidLength = RtlLengthSid(UserInfo->ExtraSids[index].Sid);
|
||
RtlCopySid(SidLength, (PSID)CurrentSid, UserInfo->ExtraSids[index].Sid);
|
||
|
||
CurrentSid += SidLength;
|
||
index++;
|
||
}
|
||
|
||
//
|
||
// Copy over all additional SIDs as groups.
|
||
//
|
||
|
||
for ( ; index < UserInfo->SidCount; index++ ) {
|
||
|
||
V2->Groups->Groups[V2->Groups->GroupCount].Attributes =
|
||
UserInfo->ExtraSids[index].Attributes;
|
||
|
||
V2->Groups->Groups[V2->Groups->GroupCount].Sid= (PSID)CurrentSid;
|
||
SidLength = RtlLengthSid(UserInfo->ExtraSids[index].Sid);
|
||
RtlCopySid(SidLength, (PSID)CurrentSid, UserInfo->ExtraSids[index].Sid);
|
||
|
||
CurrentSid += SidLength;
|
||
|
||
V2->Groups->GroupCount++;
|
||
}
|
||
}
|
||
|
||
//
|
||
// Check to see if any resouce groups exist
|
||
//
|
||
|
||
if (UserInfo->UserFlags & LOGON_RESOURCE_GROUPS) {
|
||
|
||
|
||
for ( i=0; i < UserInfo->ResourceGroupCount; i++ ) {
|
||
|
||
V2->Groups->Groups[V2->Groups->GroupCount].Attributes = UserInfo->ResourceGroupIds[i].Attributes;
|
||
|
||
V2->Groups->Groups[V2->Groups->GroupCount].Sid= (PSID)CurrentSid;
|
||
CurrentSid += NlpCopyDomainRelativeSid((PSID)CurrentSid, UserInfo->ResourceGroupDomainSid, UserInfo->ResourceGroupIds[i].RelativeId);
|
||
|
||
V2->Groups->GroupCount++;
|
||
}
|
||
}
|
||
|
||
ASSERT( ((PBYTE)V2 + Size) == CurrentSid );
|
||
|
||
|
||
if (!V2->User.User.Sid) {
|
||
|
||
Status = STATUS_INSUFFICIENT_LOGON_INFO;
|
||
goto Cleanup;
|
||
}
|
||
|
||
//
|
||
// There are no default privileges supplied.
|
||
// We don't have an explicit owner SID.
|
||
// There is no default DACL.
|
||
//
|
||
|
||
V2->Privileges = NULL;
|
||
V2->Owner.Owner = NULL;
|
||
V2->DefaultDacl.DefaultDacl = NULL;
|
||
|
||
//
|
||
// Return the Validation Information to the caller.
|
||
//
|
||
|
||
*TokenInformation = V2;
|
||
return STATUS_SUCCESS;
|
||
|
||
//
|
||
// Deallocate any memory we've allocated
|
||
//
|
||
|
||
Cleanup:
|
||
|
||
(*Lsa.FreeLsaHeap)( V2 );
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
|
||
VOID
|
||
NlpPutOwfsInPrimaryCredential(
|
||
IN PUNICODE_STRING CleartextPassword,
|
||
OUT PMSV1_0_PRIMARY_CREDENTIAL Credential
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine puts the OWFs for the specified clear password into
|
||
the passed in Credential structure.
|
||
|
||
Arguments:
|
||
|
||
CleartextPassword - Is a string containing the user's cleartext password.
|
||
The password may be up to 255 characters long and contain any
|
||
UNICODE value.
|
||
|
||
Credential - A pointer to the credential to update.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
|
||
|
||
//
|
||
// Compute the Ansi version to the Cleartext password.
|
||
//
|
||
// The Ansi version of the Cleartext password is at most 14 bytes long,
|
||
// exists in a trailing zero filled 15 byte buffer,
|
||
// is uppercased.
|
||
//
|
||
|
||
Credential->LmPasswordPresent = FALSE;
|
||
|
||
if( CleartextPassword->Length <= (LM20_PWLEN*sizeof(WCHAR)) )
|
||
{
|
||
CHAR LmPassword[LM20_PWLEN+1];
|
||
STRING AnsiCleartextPassword;
|
||
|
||
AnsiCleartextPassword.Buffer = LmPassword;
|
||
AnsiCleartextPassword.Length = sizeof(LmPassword);
|
||
AnsiCleartextPassword.MaximumLength = AnsiCleartextPassword.Length;
|
||
|
||
Status = RtlUpcaseUnicodeStringToOemString(
|
||
&AnsiCleartextPassword,
|
||
CleartextPassword,
|
||
(BOOLEAN) FALSE );
|
||
|
||
if( NT_SUCCESS( Status ) )
|
||
{
|
||
//
|
||
// Save the OWF encrypted versions of the passwords.
|
||
//
|
||
|
||
Status = RtlCalculateLmOwfPassword( LmPassword,
|
||
&Credential->LmOwfPassword );
|
||
|
||
ASSERT( NT_SUCCESS(Status) );
|
||
|
||
Credential->LmPasswordPresent = TRUE;
|
||
}
|
||
|
||
//
|
||
// Don't leave passwords around in the pagefile
|
||
//
|
||
|
||
RtlZeroMemory( LmPassword, sizeof(LmPassword) );
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
Status = RtlCalculateNtOwfPassword( CleartextPassword,
|
||
&Credential->NtOwfPassword );
|
||
|
||
ASSERT( NT_SUCCESS(Status) );
|
||
|
||
Credential->NtPasswordPresent = TRUE;
|
||
|
||
|
||
Status = RtlCalculateShaOwfPassword( CleartextPassword,
|
||
&Credential->ShaOwfPassword );
|
||
|
||
ASSERT( NT_SUCCESS(Status) );
|
||
|
||
Credential->ShaPasswordPresent = TRUE;
|
||
|
||
|
||
return;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
NlpMakePrimaryCredential(
|
||
IN PUNICODE_STRING LogonDomainName,
|
||
IN PUNICODE_STRING UserName,
|
||
IN PUNICODE_STRING CleartextPassword,
|
||
OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
|
||
OUT PULONG CredentialSize
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine makes a primary credential for the given user nam and
|
||
password.
|
||
|
||
Arguments:
|
||
|
||
LogonDomainName - Is a string representing the domain in which the user's
|
||
account is defined.
|
||
|
||
UserName - Is a string representing the user's account name. The
|
||
name may be up to 255 characters long. The name is treated case
|
||
insensitive.
|
||
|
||
CleartextPassword - Is a string containing the user's cleartext password.
|
||
The password may be up to 255 characters long and contain any
|
||
UNICODE value.
|
||
|
||
CredentialBuffer - Returns a pointer to the specified credential allocated
|
||
on the LsaHeap. It is the callers responsibility to deallocate
|
||
this credential.
|
||
|
||
CredentialSize - the size of the allocated credential buffer (in bytes).
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PMSV1_0_PRIMARY_CREDENTIAL Credential;
|
||
NTSTATUS Status;
|
||
PUCHAR Where;
|
||
ULONG PaddingLength;
|
||
|
||
|
||
//
|
||
// Build the credential
|
||
//
|
||
|
||
*CredentialSize = sizeof(MSV1_0_PRIMARY_CREDENTIAL) +
|
||
LogonDomainName->Length + sizeof(WCHAR) +
|
||
UserName->Length + sizeof(WCHAR);
|
||
|
||
//
|
||
// add padding for memory encryption interface.
|
||
//
|
||
|
||
PaddingLength = DESX_BLOCKLEN - (*CredentialSize % DESX_BLOCKLEN);
|
||
if( PaddingLength == DESX_BLOCKLEN )
|
||
{
|
||
PaddingLength = 0;
|
||
}
|
||
|
||
*CredentialSize += PaddingLength;
|
||
|
||
|
||
Credential = (*Lsa.AllocateLsaHeap)( *CredentialSize );
|
||
|
||
if ( Credential == NULL ) {
|
||
KdPrint(("MSV1_0: NlpMakePrimaryCredential: No memory %ld\n",
|
||
*CredentialSize ));
|
||
return STATUS_QUOTA_EXCEEDED;
|
||
}
|
||
|
||
|
||
//
|
||
// Put the LogonDomainName into the Credential Buffer.
|
||
//
|
||
|
||
Where = (PUCHAR)(Credential + 1);
|
||
|
||
NlpPutString( &Credential->LogonDomainName, LogonDomainName, &Where );
|
||
|
||
|
||
//
|
||
// Put the UserName into the Credential Buffer.
|
||
//
|
||
|
||
NlpPutString( &Credential->UserName, UserName, &Where );
|
||
|
||
|
||
//
|
||
// Put the OWF passwords into the newly allocated credential.
|
||
//
|
||
|
||
NlpPutOwfsInPrimaryCredential( CleartextPassword, Credential );
|
||
|
||
|
||
//
|
||
// Return the credential to the caller.
|
||
//
|
||
*CredentialBuffer = Credential;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpMakePrimaryCredentialFromMsvCredential(
|
||
IN PUNICODE_STRING LogonDomainName,
|
||
IN PUNICODE_STRING UserName,
|
||
IN PMSV1_0_SUPPLEMENTAL_CREDENTIAL MsvCredential,
|
||
OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
|
||
OUT PULONG CredentialSize
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine makes a primary credential for the given user nam and
|
||
password.
|
||
|
||
Arguments:
|
||
|
||
LogonDomainName - Is a string representing the domain in which the user's
|
||
account is defined.
|
||
|
||
UserName - Is a string representing the user's account name. The
|
||
name may be up to 255 characters long. The name is treated case
|
||
insensitive.
|
||
|
||
SupplementalCred - The credentials retrieved from the user's account on
|
||
the domain controller.
|
||
|
||
CredentialBuffer - Returns a pointer to the specified credential allocated
|
||
on the LsaHeap. It is the callers responsibility to deallocate
|
||
this credential.
|
||
|
||
CredentialSize - the size of the allocated credential buffer (in bytes).
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
PMSV1_0_PRIMARY_CREDENTIAL Credential;
|
||
NTSTATUS Status;
|
||
PUCHAR Where;
|
||
ULONG PaddingLength;
|
||
|
||
|
||
//
|
||
// Build the credential
|
||
//
|
||
|
||
*CredentialSize = sizeof(MSV1_0_PRIMARY_CREDENTIAL) +
|
||
LogonDomainName->Length + sizeof(WCHAR) +
|
||
UserName->Length + sizeof(WCHAR);
|
||
|
||
//
|
||
// add padding for memory encryption interface.
|
||
//
|
||
|
||
PaddingLength = DESX_BLOCKLEN - (*CredentialSize % DESX_BLOCKLEN);
|
||
if( PaddingLength == DESX_BLOCKLEN )
|
||
{
|
||
PaddingLength = 0;
|
||
}
|
||
|
||
*CredentialSize += PaddingLength;
|
||
|
||
|
||
Credential = (*Lsa.AllocateLsaHeap)( *CredentialSize );
|
||
|
||
if ( Credential == NULL ) {
|
||
KdPrint(("MSV1_0: NlpMakePrimaryCredential: No memory %ld\n",
|
||
*CredentialSize ));
|
||
return STATUS_QUOTA_EXCEEDED;
|
||
}
|
||
|
||
RtlZeroMemory(
|
||
Credential,
|
||
*CredentialSize
|
||
);
|
||
|
||
//
|
||
// Put the LogonDomainName into the Credential Buffer.
|
||
//
|
||
|
||
Where = (PUCHAR)(Credential + 1);
|
||
|
||
NlpPutString( &Credential->LogonDomainName, LogonDomainName, &Where );
|
||
|
||
|
||
//
|
||
// Put the UserName into the Credential Buffer.
|
||
//
|
||
|
||
NlpPutString( &Credential->UserName, UserName, &Where );
|
||
|
||
|
||
|
||
//
|
||
// Save the OWF encrypted versions of the passwords.
|
||
//
|
||
|
||
if (MsvCredential->Flags & MSV1_0_CRED_NT_PRESENT) {
|
||
RtlCopyMemory(
|
||
&Credential->NtOwfPassword,
|
||
MsvCredential->NtPassword,
|
||
MSV1_0_OWF_PASSWORD_LENGTH
|
||
);
|
||
Credential->NtPasswordPresent = TRUE;
|
||
} else {
|
||
#if 0
|
||
RtlCopyMemory(
|
||
&Credential->NtOwfPassword,
|
||
&NlpNullNtOwfPassword,
|
||
MSV1_0_OWF_PASSWORD_LENGTH
|
||
);
|
||
Credential->NtPasswordPresent = TRUE;
|
||
#endif
|
||
Credential->NtPasswordPresent = FALSE;
|
||
}
|
||
|
||
|
||
if (MsvCredential->Flags & MSV1_0_CRED_LM_PRESENT) {
|
||
RtlCopyMemory(
|
||
&Credential->LmOwfPassword,
|
||
MsvCredential->LmPassword,
|
||
MSV1_0_OWF_PASSWORD_LENGTH
|
||
);
|
||
Credential->LmPasswordPresent = TRUE;
|
||
} else {
|
||
#if 0
|
||
RtlCopyMemory(
|
||
&Credential->LmOwfPassword,
|
||
&NlpNullLmOwfPassword,
|
||
MSV1_0_OWF_PASSWORD_LENGTH
|
||
);
|
||
Credential->LmPasswordPresent = TRUE;
|
||
#endif
|
||
Credential->LmPasswordPresent = FALSE;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Return the credential to the caller.
|
||
//
|
||
*CredentialBuffer = Credential;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpAddPrimaryCredential(
|
||
IN PLUID LogonId,
|
||
IN PMSV1_0_PRIMARY_CREDENTIAL Credential,
|
||
IN ULONG CredentialSize
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine sets a primary credential for the given LogonId.
|
||
|
||
Arguments:
|
||
|
||
LogonId - The LogonId of the LogonSession to set the Credentials
|
||
for.
|
||
|
||
Credential - Specifies a pointer to the credential.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
STRING CredentialString;
|
||
STRING PrimaryKeyValue;
|
||
|
||
//
|
||
// Make all pointers in the credential relative.
|
||
//
|
||
|
||
NlpMakeRelativeString( (PUCHAR)Credential, &Credential->UserName );
|
||
NlpMakeRelativeString( (PUCHAR)Credential, &Credential->LogonDomainName );
|
||
|
||
//
|
||
// Add the credential to the logon session.
|
||
//
|
||
|
||
RtlInitString( &PrimaryKeyValue, MSV1_0_PRIMARY_KEY );
|
||
CredentialString.Buffer = (PCHAR) Credential;
|
||
CredentialString.Length = (USHORT) CredentialSize;
|
||
CredentialString.MaximumLength = CredentialString.Length;
|
||
|
||
//
|
||
// encrypt input credential.
|
||
//
|
||
|
||
(*Lsa.LsaProtectMemory)( CredentialString.Buffer, (ULONG)CredentialString.Length );
|
||
|
||
Status = (*Lsa.AddCredential)(
|
||
LogonId,
|
||
MspAuthenticationPackageId,
|
||
&PrimaryKeyValue,
|
||
&CredentialString );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
KdPrint(( "NlpAddPrimaryCredential: error from AddCredential %lX\n",
|
||
Status));
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
NTSTATUS
|
||
NlpGetPrimaryCredentialByUserDomain(
|
||
IN PUNICODE_STRING LogonDomainName,
|
||
IN PUNICODE_STRING UserName,
|
||
OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
|
||
OUT PULONG CredentialSize OPTIONAL
|
||
)
|
||
{
|
||
PACTIVE_LOGON Logon;
|
||
LUID LogonId;
|
||
BOOLEAN Match = FALSE;
|
||
|
||
//
|
||
// Loop through the table looking for this particular LogonId.
|
||
//
|
||
|
||
NlpLockActiveLogonsRead();
|
||
|
||
for( Logon = NlpActiveLogons; Logon != NULL; Logon = Logon->Next ) {
|
||
|
||
if(RtlEqualUnicodeString( UserName, &Logon->UserName, (BOOLEAN) TRUE) &&
|
||
RtlEqualDomainName(LogonDomainName,&Logon->LogonDomainName ))
|
||
{
|
||
Match = TRUE;
|
||
CopyMemory( &LogonId, &Logon->LogonId, sizeof(LogonId) );
|
||
break;
|
||
}
|
||
|
||
}
|
||
|
||
NlpUnlockActiveLogons();
|
||
|
||
if( !Match )
|
||
return STATUS_NO_SUCH_LOGON_SESSION;
|
||
|
||
|
||
return NlpGetPrimaryCredential( &LogonId, CredentialBuffer, CredentialSize );
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpGetPrimaryCredential(
|
||
IN PLUID LogonId,
|
||
OUT PMSV1_0_PRIMARY_CREDENTIAL *CredentialBuffer,
|
||
OUT PULONG CredentialSize OPTIONAL
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine gets a primary credential for the given LogonId.
|
||
|
||
Arguments:
|
||
|
||
LogonId - The LogonId of the LogonSession to retrieve the Credentials
|
||
for.
|
||
|
||
CredentialBuffer - Returns a pointer to the specified credential allocated
|
||
on the LsaHeap. It is the callers responsibility to deallocate
|
||
this credential.
|
||
|
||
CredentialSize - Optionally returns the size of the credential buffer.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
ULONG QueryContext = 0;
|
||
ULONG PrimaryKeyLength;
|
||
STRING PrimaryKeyValue;
|
||
STRING CredentialString;
|
||
PMSV1_0_PRIMARY_CREDENTIAL Credential = NULL;
|
||
|
||
RtlInitString( &PrimaryKeyValue, MSV1_0_PRIMARY_KEY );
|
||
|
||
Status = (*Lsa.GetCredentials)( LogonId,
|
||
MspAuthenticationPackageId,
|
||
&QueryContext,
|
||
(BOOLEAN) FALSE, // Just retrieve primary
|
||
&PrimaryKeyValue,
|
||
&PrimaryKeyLength,
|
||
&CredentialString );
|
||
|
||
if ( !NT_SUCCESS( Status ) ) {
|
||
return Status;
|
||
}
|
||
|
||
//
|
||
// Make all pointers in the credential absolute.
|
||
//
|
||
|
||
Credential = (PMSV1_0_PRIMARY_CREDENTIAL) CredentialString.Buffer;
|
||
|
||
//
|
||
// decrypt credential.
|
||
//
|
||
|
||
(*Lsa.LsaUnprotectMemory)( CredentialString.Buffer, (ULONG)CredentialString.Length );
|
||
|
||
|
||
NlpRelativeToAbsolute( Credential,
|
||
(PULONG_PTR)&Credential->UserName.Buffer );
|
||
NlpRelativeToAbsolute( Credential,
|
||
(PULONG_PTR)&Credential->LogonDomainName.Buffer );
|
||
|
||
|
||
*CredentialBuffer = Credential;
|
||
if ( CredentialSize != NULL ) {
|
||
*CredentialSize = CredentialString.Length;
|
||
}
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpDeletePrimaryCredential(
|
||
IN PLUID LogonId
|
||
)
|
||
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine deletes the credential for the given LogonId.
|
||
|
||
Arguments:
|
||
|
||
LogonId - The LogonId of the LogonSession to delete the Credentials for.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - Indicates the service completed successfully.
|
||
|
||
STATUS_QUOTA_EXCEEDED - This error indicates that the logon
|
||
could not be completed because the client does not have
|
||
sufficient quota to allocate the return buffer.
|
||
|
||
|
||
--*/
|
||
|
||
{
|
||
NTSTATUS Status;
|
||
STRING PrimaryKeyValue;
|
||
|
||
RtlInitString( &PrimaryKeyValue, MSV1_0_PRIMARY_KEY );
|
||
|
||
Status = (*Lsa.DeleteCredential)( LogonId,
|
||
MspAuthenticationPackageId,
|
||
&PrimaryKeyValue );
|
||
|
||
return Status;
|
||
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpChangePassword(
|
||
IN PUNICODE_STRING DomainName,
|
||
IN PUNICODE_STRING UserName,
|
||
IN PUNICODE_STRING Password
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Change the password for the specified user in all currently stored
|
||
credentials.
|
||
|
||
Arguments:
|
||
|
||
DomainName - The Netbios name of the domain in which the account exists.
|
||
|
||
UserName - The name of the account whose password is to be changed.
|
||
|
||
Password - The new password.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - If the operation was successful.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_NOT_FOUND;
|
||
PACTIVE_LOGON Logon;
|
||
|
||
MSV1_0_PRIMARY_CREDENTIAL TempCredential;
|
||
|
||
LUID FastLogonIds[ 32 ];
|
||
PLUID SlowLogonIds = NULL;
|
||
ULONG AllocatedLogonIds;
|
||
|
||
PLUID LogonIds;
|
||
ULONG cLogonIds;
|
||
UNICODE_STRING NetBiosLogonDomainName = {0};
|
||
UNICODE_STRING DnsDomainName = {0};
|
||
UNICODE_STRING* pNetBiosLogonDomainName = NULL;
|
||
cLogonIds = 0;
|
||
LogonIds = FastLogonIds;
|
||
AllocatedLogonIds = sizeof(FastLogonIds) / sizeof(LUID);
|
||
|
||
//
|
||
// Compute the OWFs of the password.
|
||
//
|
||
|
||
NlpPutOwfsInPrimaryCredential( Password, &TempCredential );
|
||
|
||
Status = LsaIGetNbAndDnsDomainNames(DomainName, &DnsDomainName, &NetBiosLogonDomainName);
|
||
|
||
if (NT_SUCCESS(Status) && NetBiosLogonDomainName.Length != 0)
|
||
{
|
||
pNetBiosLogonDomainName = &NetBiosLogonDomainName;
|
||
}
|
||
else
|
||
{
|
||
pNetBiosLogonDomainName = DomainName;
|
||
}
|
||
|
||
//
|
||
// Loop through the table looking for this particular UserName/DomainName.
|
||
//
|
||
|
||
NlpLockActiveLogonsRead();
|
||
|
||
for (Logon = NlpActiveLogons; Logon != NULL; Logon = Logon->Next ) {
|
||
|
||
if (!RtlEqualUnicodeString( UserName, &Logon->UserName, (BOOLEAN) TRUE ))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
if (!RtlEqualDomainName( pNetBiosLogonDomainName, &Logon->LogonDomainName ))
|
||
{
|
||
continue;
|
||
}
|
||
|
||
SspPrint((SSP_UPDATES, "NlpChangePassword matched LogonId=%lx.%lx\n",
|
||
Logon->LogonId.LowPart, Logon->LogonId.HighPart ));
|
||
|
||
//
|
||
// if we don't have space to store the new entry, allocate a new
|
||
// buffer, copy the existing buffer, and keep going.
|
||
//
|
||
|
||
if( AllocatedLogonIds < (cLogonIds+1))
|
||
{
|
||
PLUID OldLogonIds = SlowLogonIds;
|
||
|
||
AllocatedLogonIds *= 2;
|
||
|
||
SlowLogonIds = I_NtLmAllocate( AllocatedLogonIds * sizeof(LUID) );
|
||
if( SlowLogonIds == NULL )
|
||
{
|
||
break;
|
||
}
|
||
|
||
CopyMemory( SlowLogonIds, LogonIds, cLogonIds*sizeof(LUID) );
|
||
|
||
LogonIds = SlowLogonIds;
|
||
|
||
if( OldLogonIds != NULL )
|
||
{
|
||
I_NtLmFree( OldLogonIds );
|
||
}
|
||
}
|
||
|
||
LogonIds[ cLogonIds ] = Logon->LogonId;
|
||
|
||
cLogonIds++;
|
||
}
|
||
|
||
NlpUnlockActiveLogons();
|
||
|
||
//
|
||
// Pass the change back to the LSA. Note - this only changes it for the
|
||
// last element in the list.
|
||
//
|
||
|
||
if (cLogonIds != 0)
|
||
{
|
||
SECPKG_PRIMARY_CRED PrimaryCredentials;
|
||
ULONG Index;
|
||
|
||
RtlZeroMemory(
|
||
&PrimaryCredentials,
|
||
sizeof(SECPKG_PRIMARY_CRED)
|
||
);
|
||
|
||
PrimaryCredentials.Password = *Password;
|
||
PrimaryCredentials.Flags = PRIMARY_CRED_UPDATE | PRIMARY_CRED_CLEAR_PASSWORD;
|
||
|
||
//
|
||
// update each instance of the credential that matches.
|
||
// Multiple logon session can legally reference the same creds,
|
||
// eg: Terminal Services, RunAs, etc.
|
||
//
|
||
|
||
for ( Index = 0 ; Index < cLogonIds ; Index++ )
|
||
{
|
||
PrimaryCredentials.LogonId = LogonIds[ Index ];
|
||
|
||
(VOID) LsaFunctions->UpdateCredentials(
|
||
&PrimaryCredentials,
|
||
NULL // no supplemental credentials
|
||
);
|
||
}
|
||
|
||
Status = STATUS_SUCCESS;
|
||
}
|
||
else
|
||
{
|
||
Status = STATUS_NOT_FOUND;
|
||
}
|
||
|
||
//
|
||
// Pass the new password on to the logon cache
|
||
//
|
||
|
||
NlpChangeCachePassword(
|
||
DomainName,
|
||
UserName,
|
||
&TempCredential.LmOwfPassword,
|
||
&TempCredential.NtOwfPassword
|
||
);
|
||
|
||
ZeroMemory( &TempCredential, sizeof(TempCredential) );
|
||
|
||
if ( SlowLogonIds )
|
||
{
|
||
I_NtLmFree( SlowLogonIds );
|
||
}
|
||
|
||
if (NetBiosLogonDomainName.MaximumLength && NetBiosLogonDomainName.Buffer)
|
||
{
|
||
LsaIFreeHeap(NetBiosLogonDomainName.Buffer);
|
||
}
|
||
|
||
if (DnsDomainName.MaximumLength && DnsDomainName.Buffer)
|
||
{
|
||
LsaIFreeHeap(DnsDomainName.Buffer);
|
||
}
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
NTSTATUS
|
||
NlpChangePasswordByLogonId(
|
||
IN PLUID LogonId,
|
||
IN PUNICODE_STRING Password
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Change the password for the specified user in all currently stored
|
||
credentials.
|
||
|
||
Arguments:
|
||
|
||
LogonId - Logon ID of user whose password changed.
|
||
|
||
Password - New password.
|
||
|
||
Return Value:
|
||
|
||
STATUS_SUCCESS - If the operation was successful.
|
||
|
||
--*/
|
||
{
|
||
NTSTATUS Status = STATUS_SUCCESS;
|
||
PACTIVE_LOGON Logon;
|
||
ULONG LogonCount = 0;
|
||
PMSV1_0_PRIMARY_CREDENTIAL Credential = NULL;
|
||
ULONG CredentialSize;
|
||
|
||
MSV1_0_PRIMARY_CREDENTIAL TempCredential;
|
||
|
||
//
|
||
// Compute the OWFs of the password.
|
||
//
|
||
|
||
NlpPutOwfsInPrimaryCredential( Password, &TempCredential );
|
||
|
||
//
|
||
// Loop through the table looking for this particular UserName/DomainName.
|
||
//
|
||
|
||
// conservative: take the full write lock up front.
|
||
NlpLockActiveLogonsWrite();
|
||
|
||
for( Logon = NlpActiveLogons; Logon != NULL; Logon = Logon->Next )
|
||
{
|
||
|
||
if(!RtlEqualLuid( LogonId, &Logon->LogonId) )
|
||
{
|
||
continue;
|
||
}
|
||
|
||
SspPrint((SSP_UPDATES, "NlpChangePasswordByLogonId LogonId=%lx.%lx\n",
|
||
LogonId->LowPart, LogonId->HighPart ));
|
||
|
||
|
||
//
|
||
// Get the current credential for this logonid.
|
||
//
|
||
|
||
Status = NlpGetPrimaryCredential( &Logon->LogonId,
|
||
&Credential,
|
||
&CredentialSize );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Delete it from the LSA.
|
||
//
|
||
|
||
Status = NlpDeletePrimaryCredential( &Logon->LogonId );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
(*Lsa.FreeLsaHeap)( Credential );
|
||
break;
|
||
}
|
||
|
||
|
||
//
|
||
// Change the passwords in it
|
||
//
|
||
|
||
Credential->LmOwfPassword = TempCredential.LmOwfPassword;
|
||
Credential->NtOwfPassword = TempCredential.NtOwfPassword;
|
||
Credential->ShaOwfPassword = TempCredential.ShaOwfPassword;
|
||
Credential->LmPasswordPresent = TempCredential.LmPasswordPresent;
|
||
Credential->NtPasswordPresent = TempCredential.NtPasswordPresent;
|
||
Credential->ShaPasswordPresent = TempCredential.ShaPasswordPresent;
|
||
|
||
//
|
||
// Add it back to the LSA.
|
||
//
|
||
|
||
Status = NlpAddPrimaryCredential( &Logon->LogonId,
|
||
Credential,
|
||
CredentialSize );
|
||
|
||
(*Lsa.FreeLsaHeap)( Credential );
|
||
|
||
if ( !NT_SUCCESS(Status) ) {
|
||
break;
|
||
}
|
||
|
||
//
|
||
// Pass the new password on to the logon cache
|
||
//
|
||
|
||
NlpChangeCachePassword(
|
||
&Logon->LogonDomainName,
|
||
&Logon->UserName,
|
||
&TempCredential.LmOwfPassword,
|
||
&TempCredential.NtOwfPassword );
|
||
|
||
break;
|
||
}
|
||
|
||
NlpUnlockActiveLogons();
|
||
|
||
ZeroMemory( &TempCredential, sizeof(TempCredential) );
|
||
|
||
return Status;
|
||
}
|
||
|
||
|
||
VOID
|
||
NlpGetAccountNames(
|
||
IN PNETLOGON_LOGON_IDENTITY_INFO LogonInfo,
|
||
IN PNETLOGON_VALIDATION_SAM_INFO4 NlpUser,
|
||
OUT PUNICODE_STRING SamAccountName,
|
||
OUT PUNICODE_STRING NetbiosDomainName,
|
||
OUT PUNICODE_STRING DnsDomainName,
|
||
OUT PUNICODE_STRING Upn
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Get the sundry account names from the LogonInfo and NlpUser
|
||
|
||
Arguments:
|
||
|
||
LogonInfo - pointer to NETLOGON_INTERACTIVE_INFO structure which contains
|
||
the domain name, user name and password for this user. These
|
||
are what the user typed to WinLogon
|
||
|
||
NlpUser - pointer to NETLOGON_VALIDATION_SAM_INFO4 structure which
|
||
contains this user's specific interactive logon information
|
||
|
||
SamAccountName - Returns the SamAccountName of the logged on user.
|
||
The returned buffer is within the LogonInfo or NlpUser.
|
||
|
||
NetbiosDomainName - Returns the NetbiosDomainName of the logged on user.
|
||
The returned buffer is within the LogonInfo or NlpUser.
|
||
|
||
DnsDomainName - Returns the DnsDomainName of the logged on user.
|
||
The returned buffer is within the LogonInfo or NlpUser.
|
||
The returned length will be zero if DnsDomainName is not known.
|
||
|
||
UPN - Returns the UPN of the logged on user.
|
||
The returned buffer is within the LogonInfo or NlpUser.
|
||
The returned length will be zero if UPN is not known.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
{
|
||
|
||
//
|
||
// Return the SamAccountName and Netbios Domain Name
|
||
//
|
||
*SamAccountName = NlpUser->EffectiveName;
|
||
*NetbiosDomainName = NlpUser->LogonDomainName;
|
||
|
||
//
|
||
// Return the DNS domain name.
|
||
//
|
||
|
||
*DnsDomainName = NlpUser->DnsLogonDomainName;
|
||
|
||
//
|
||
// Determine the UPN of the account
|
||
//
|
||
// If the UPN was returned from the DC,
|
||
// use it.
|
||
// else
|
||
// use the UPN the caller passed in
|
||
//
|
||
// The caller passed in a UPN if all of the following are true:
|
||
// There is no domain name.
|
||
// The passed in user name isn't the one returned from the DC.
|
||
// The passed in user name has an @ in it.
|
||
//
|
||
//
|
||
|
||
*Upn = NlpUser->Upn;
|
||
|
||
if ( Upn->Length == 0 ) {
|
||
|
||
if ( LogonInfo->LogonDomainName.Length == 0 &&
|
||
!RtlEqualUnicodeString( &LogonInfo->UserName, &NlpUser->EffectiveName, (BOOLEAN) TRUE ) ) {
|
||
|
||
ULONG i;
|
||
|
||
for ( i=0; i<LogonInfo->UserName.Length/sizeof(WCHAR); i++) {
|
||
|
||
if ( LogonInfo->UserName.Buffer[i] == L'@') {
|
||
*Upn = LogonInfo->UserName;
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//+-------------------------------------------------------------------------
|
||
//
|
||
// Function: NlpCopyDomainRelativeSid
|
||
//
|
||
// Synopsis: Given a domain Id and a relative ID create the corresponding
|
||
// SID at the location indicated by TargetSid
|
||
//
|
||
// Effects:
|
||
//
|
||
// Arguments: TargetSid - target memory location
|
||
// DomainId - The template SID to use.
|
||
//
|
||
// RelativeId - The relative Id to append to the DomainId.
|
||
//
|
||
// Requires:
|
||
//
|
||
// Returns: Size - Size of the sid copied
|
||
//
|
||
// Notes:
|
||
//
|
||
//
|
||
//--------------------------------------------------------------------------
|
||
|
||
DWORD
|
||
NlpCopyDomainRelativeSid(
|
||
OUT PSID TargetSid,
|
||
IN PSID DomainId,
|
||
IN ULONG RelativeId
|
||
)
|
||
{
|
||
UCHAR DomainIdSubAuthorityCount;
|
||
ULONG Size;
|
||
|
||
//
|
||
// Allocate a Sid which has one more sub-authority than the domain ID.
|
||
//
|
||
|
||
DomainIdSubAuthorityCount = *(RtlSubAuthorityCountSid( DomainId ));
|
||
Size = RtlLengthRequiredSid(DomainIdSubAuthorityCount+1);
|
||
|
||
//
|
||
// Initialize the new SID to have the same inital value as the
|
||
// domain ID.
|
||
//
|
||
|
||
if ( !NT_SUCCESS( RtlCopySid( Size, TargetSid, DomainId ) ) ) {
|
||
return 0;
|
||
}
|
||
|
||
//
|
||
// Adjust the sub-authority count and
|
||
// add the relative Id unique to the newly allocated SID
|
||
//
|
||
|
||
(*(RtlSubAuthorityCountSid( TargetSid ))) ++;
|
||
*RtlSubAuthoritySid( TargetSid, DomainIdSubAuthorityCount ) = RelativeId;
|
||
|
||
|
||
return Size;
|
||
}
|
||
|
||
|
||
//
|
||
// temporary home for this function.
|
||
//
|
||
|
||
|
||
NTSTATUS
|
||
RtlCalculateShaOwfPassword(
|
||
IN PSHA_PASSWORD ShaPassword,
|
||
OUT PSHA_OWF_PASSWORD ShaOwfPassword
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
Takes the passed ShaPassword and performs a one-way-function on it.
|
||
Uses the FIPS approved SHA-1 function
|
||
|
||
Arguments:
|
||
|
||
ShaPassword - The password to perform the one-way-function on.
|
||
|
||
ShaOwfPassword - The hashed password is returned here
|
||
|
||
Return Values:
|
||
|
||
STATUS_SUCCESS - The function was completed successfully. The hashed
|
||
password is in ShaOwfPassword.
|
||
--*/
|
||
|
||
{
|
||
A_SHA_CTX SHA_Context;
|
||
|
||
A_SHAInit(&SHA_Context);
|
||
A_SHAUpdate(&SHA_Context, (PCHAR)ShaPassword->Buffer, ShaPassword->Length);
|
||
A_SHAFinal(&SHA_Context, (PCHAR)ShaOwfPassword);
|
||
|
||
|
||
return(STATUS_SUCCESS);
|
||
}
|
||
|