mirror of https://github.com/tongzx/nt5src
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.
2594 lines
63 KiB
2594 lines
63 KiB
/*++
|
|
|
|
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);
|
|
}
|
|
|