Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

633 lines
13 KiB

/*++
Copyright (c) 1987-1993 Microsoft Corporation
Module Name:
utility.c
Abstract:
Private NtLmSsp service utility routines.
Author:
Cliff Van Dyke (cliffv) 9-Jun-1993
Environment:
User mode only.
Contains NT-specific code.
Requires ANSI C extensions: slash-slash comments, long external names.
Revision History:
--*/
//
// Common include files.
//
#include <ntlmcomn.h> // Common definitions for DLL and SERVICE
#include <ntlmsspi.h> // Data private to the common routines
//
// Include files specific to this .c file
//
#include <netlib.h> // NetpMemoryFree()
#include <secobj.h> // ACE_DATA ...
#include <stdio.h> // vsprintf().
#include <tstr.h> // TCHAR_ equates.
#define SSP_TOKEN_ACCESS (READ_CONTROL |\
WRITE_DAC |\
TOKEN_DUPLICATE |\
TOKEN_IMPERSONATE |\
TOKEN_QUERY |\
TOKEN_QUERY_SOURCE |\
TOKEN_ADJUST_PRIVILEGES |\
TOKEN_ADJUST_GROUPS |\
TOKEN_ADJUST_DEFAULT)
SECURITY_STATUS
SspNtStatusToSecStatus(
IN NTSTATUS NtStatus,
IN SECURITY_STATUS DefaultStatus
)
/*++
Routine Description:
Convert an NtStatus code to the corresponding Security status code
Arguments:
NtStatus - NT status to convert
Return Value:
Returns security status code.
--*/
{
switch(NtStatus){
case STATUS_NO_MEMORY:
return SEC_E_INSUFFICIENT_MEMORY;
case STATUS_SUCCESS:
return STATUS_SUCCESS;
default:
if ( DefaultStatus != 0 ) {
return DefaultStatus;
} else {
return NtStatus;
}
}
ASSERT(FALSE);
}
BOOLEAN
SspTimeHasElapsed(
IN LARGE_INTEGER StartTime,
IN DWORD Timeout
)
/*++
Routine Description:
Determine if "Timeout" milliseconds have elapsed since StartTime.
Arguments:
StartTime - Specifies an absolute time when the event started (100ns units).
Timeout - Specifies a relative time in milliseconds. 0xFFFFFFFF indicates
that the time will never expire.
Return Value:
TRUE -- iff Timeout milliseconds have elapsed since StartTime.
--*/
{
LARGE_INTEGER TimeNow;
LARGE_INTEGER ElapsedTime;
LARGE_INTEGER Period;
//
// If the period to too large to handle (i.e., 0xffffffff is forever),
// just indicate that the timer has not expired.
//
// (0x7fffffff is a little over 24 days).
//
if ( Timeout> 0x7fffffff ) {
return FALSE;
}
//
// Compute the elapsed time
//
NtQuerySystemTime( &TimeNow );
ElapsedTime.QuadPart = TimeNow.QuadPart - StartTime.QuadPart;
//
// Convert Timeout from milliseconds into 100ns units.
//
Period.QuadPart = Int32x32To64( (LONG)Timeout, 10000 );
//
// If the elapsed time is negative (totally bogus),
// or greater than the maximum allowed,
// indicate the period has elapsed.
//
if ( ElapsedTime.QuadPart < 0 || ElapsedTime.QuadPart > Period.QuadPart ) {
return TRUE;
}
return FALSE;
}
SECURITY_STATUS
SspGetLogonId (
OUT PLUID LogonId,
OUT PHANDLE ReturnedTokenHandle OPTIONAL
)
/*++
Routine Description:
This routine gets the Logon Id of token of the calling thread.
Arguments:
LogonId - Returns the Logon Id of the calling thread.
ReturnedTokenHandle - Optionally returns a token handle to an
impersonation token for the calling thread.
Return Status:
STATUS_SUCCESS - Indicates the routine completed successfully.
--*/
{
NTSTATUS Status;
HANDLE NullImpersonationToken = NULL;
HANDLE TokenHandle = NULL;
PTOKEN_STATISTICS TokenStatisticsInfo = NULL;
ULONG TokenStatisticsInfoSize;
//
// Open the token,
//
Status = NtOpenThreadToken(
NtCurrentThread(),
TOKEN_DUPLICATE | TOKEN_QUERY | (ReturnedTokenHandle == NULL ? 0 : WRITE_DAC),
(BOOLEAN) TRUE, // Use the logon service's security context
// to open the token
&TokenHandle );
if ( Status == STATUS_NO_TOKEN ) {
Status = NtOpenProcessToken(
NtCurrentProcess(),
TOKEN_QUERY | TOKEN_DUPLICATE,
&TokenHandle );
}
if ( !NT_SUCCESS( Status )) {
goto Cleanup;
}
//
// Get the LogonId from the token.
//
Status = NtQueryInformationToken(
TokenHandle,
TokenStatistics,
&TokenStatisticsInfo,
0,
&TokenStatisticsInfoSize );
if ( Status != STATUS_BUFFER_TOO_SMALL ) {
goto Cleanup;
}
TokenStatisticsInfo = LocalAlloc( 0, TokenStatisticsInfoSize );
if ( TokenStatisticsInfo == NULL ) {
Status = STATUS_NO_MEMORY;
goto Cleanup;
}
Status = NtQueryInformationToken(
TokenHandle,
TokenStatistics,
TokenStatisticsInfo,
TokenStatisticsInfoSize,
&TokenStatisticsInfoSize );
if ( !NT_SUCCESS(Status) ) {
goto Cleanup;
}
*LogonId = TokenStatisticsInfo->AuthenticationId;
Status = STATUS_SUCCESS;
//
// Clean up locally used resources.
//
Cleanup:
//
// Return the token handle to the caller (if requested)
//
if ( ReturnedTokenHandle != NULL ) {
if ( !NT_SUCCESS(Status) ) {
*ReturnedTokenHandle = NULL;
} else {
*ReturnedTokenHandle = TokenHandle;
TokenHandle = NULL;
}
}
if ( TokenHandle != NULL ) {
(VOID) NtClose( TokenHandle );
}
if ( TokenStatisticsInfo != NULL ) {
(VOID) LocalFree( TokenStatisticsInfo );
}
return SspNtStatusToSecStatus( Status, SEC_E_NO_CREDENTIALS );
}
VOID
SspGetPrimaryDomainNameAndTargetName(
VOID
)
/*++
Routine Description:
Ensure SspGlobalTargetName is up to date.
Arguments:
None.
Return Value:
None.
--*/
{
NTSTATUS Status;
PPOLICY_PRIMARY_DOMAIN_INFO PrimaryDomain = NULL;
//
// If this is an Advanced Server and we've already read the domain name,
// just return now.
//
if ( SspGlobalNtProductType == NtProductLanManNt &&
SspGlobalTargetName.Length != 0 ) {
return;
}
//
// Open the Lsa Policy database if it isn't yet open.
//
if ( SspGlobalLsaPolicyHandle == NULL ) {
OBJECT_ATTRIBUTES ObjectAttributes;
InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL );
Status = LsaOpenPolicy( NULL,
&ObjectAttributes,
POLICY_VIEW_LOCAL_INFORMATION,
&SspGlobalLsaPolicyHandle );
if ( !NT_SUCCESS(Status) ) {
SspGlobalLsaPolicyHandle = NULL;
return;
}
}
//
// Get the PrimaryDomain information
//
Status = LsaQueryInformationPolicy(
SspGlobalLsaPolicyHandle,
PolicyPrimaryDomainInformation,
&PrimaryDomain );
if ( NT_SUCCESS(Status) ) {
//
// Save the primary domain name.
//
wcsncpy( SspGlobalUnicodePrimaryDomainName,
PrimaryDomain->Name.Buffer,
DNLEN+1 );
SspGlobalUnicodePrimaryDomainName[DNLEN] = L'\0';
RtlInitUnicodeString( &SspGlobalUnicodePrimaryDomainNameString,
SspGlobalUnicodePrimaryDomainName );
Status = RtlUpcaseUnicodeStringToOemString(
&SspGlobalOemPrimaryDomainNameString,
&SspGlobalUnicodePrimaryDomainNameString,
TRUE );
if ( !NT_SUCCESS(Status) ) {
RtlInitString( &SspGlobalOemPrimaryDomainNameString, NULL );
}
//
// If this is a standalone windows NT workstation,
// use the computer name as the Target name.
//
if ( PrimaryDomain->Sid == NULL ) {
SspGlobalTargetName = SspGlobalUnicodeComputerNameString;
SspGlobalOemTargetName = SspGlobalOemComputerNameString;
SspGlobalTargetFlags = NTLMSSP_TARGET_TYPE_SERVER;
} else {
SspGlobalTargetName = SspGlobalUnicodePrimaryDomainNameString;
SspGlobalOemTargetName = SspGlobalOemPrimaryDomainNameString;
SspGlobalTargetFlags = NTLMSSP_TARGET_TYPE_DOMAIN;
}
}
//
// Close the Lsa Policy Database if we'll never use it again.
//
if ( SspGlobalNtProductType == NtProductLanManNt ) {
(VOID) LsaClose( SspGlobalLsaPolicyHandle );
SspGlobalLsaPolicyHandle = NULL;
}
}
SECURITY_STATUS
SspDuplicateToken(
IN HANDLE OriginalToken,
IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
OUT PHANDLE DuplicatedToken
)
/*++
Routine Description:
Duplicates a token
Arguments:
OriginalToken - Token to duplicate
DuplicatedToken - Receives handle to duplicated token
Return Value:
Any error from NtDuplicateToken
--*/
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
SECURITY_QUALITY_OF_SERVICE QualityOfService;
InitializeObjectAttributes(
&ObjectAttributes,
NULL,
0,
NULL,
NULL
);
QualityOfService.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
QualityOfService.EffectiveOnly = FALSE;
QualityOfService.ContextTrackingMode = SECURITY_STATIC_TRACKING;
QualityOfService.ImpersonationLevel = ImpersonationLevel;
ObjectAttributes.SecurityQualityOfService = &QualityOfService;
Status = NtDuplicateToken(
OriginalToken,
SSP_TOKEN_ACCESS,
&ObjectAttributes,
FALSE,
TokenImpersonation,
DuplicatedToken
);
return(SspNtStatusToSecStatus(Status, SEC_E_NO_IMPERSONATION));
}
LPWSTR
SspAllocWStrFromWStr(
IN LPWSTR Unicode
)
/*++
Routine Description:
Allocate and copy unicode string (wide character strdup)
Arguments:
Unicode - pointer to wide character string to make copy of
Return Value:
NULL - There was some error in the conversion.
Otherwise, it returns a pointer to the zero terminated UNICODE string in
an allocated buffer. The buffer must be freed using LocalFree.
--*/
{
DWORD Size;
LPWSTR ptr;
Size = WCSSIZE(Unicode);
ptr = LocalAlloc(0, Size);
if ( ptr != NULL) {
RtlCopyMemory(ptr, Unicode, Size);
}
return ptr;
}
SECURITY_STATUS
SspDuplicateUnicodeString(
OUT PUNICODE_STRING Destination,
IN PUNICODE_STRING Source
)
/*++
Routine Description:
Allocate and copy unicode string
Arguments:
Destination - Receives duplicate string, allocated with LocalAlloc.
Source - Contains source unicode string.
Return Value:
SEC_E_INSUFFICIENT_MEMORY - The routine was unable to allocate the
output string.
--*/
{
if (Source == NULL) {
Destination->Buffer = NULL;
Destination->Length = Destination->MaximumLength = 0;
return(SEC_E_OK);
}
Destination->Buffer = (LPWSTR) LocalAlloc(0, Source->Length + sizeof(WCHAR));
if (Destination->Buffer == NULL) {
return(SEC_E_INSUFFICIENT_MEMORY);
}
Destination->Length = Source->Length;
Destination->MaximumLength = Source->Length + sizeof(WCHAR);
RtlCopyMemory(
Destination->Buffer,
Source->Buffer,
Source->Length
);
Destination->Buffer[Source->Length/sizeof(WCHAR)] = L'\0';
return(SEC_E_OK);
}
VOID
SspHidePassword(
IN OUT PUNICODE_STRING Password
)
/*++
Routine Description:
Run-encodes the password so that it is not very visually
distinguishable. This is so that if it makes it to a
paging file, it wont be obvious.
WARNING - This routine will use the upper portion of the
password's length field to store the seed used in encoding
password. Be careful you don't pass such a string to
a routine that looks at the length (like and RPC routine).
Arguments:
Seed - The seed to use to hide the password.
PasswordSource - Contains password to hide.
Return Value:
--*/
{
PSECURITY_SEED_AND_LENGTH SeedAndLength;
UCHAR LocalSeed;
LocalSeed = 0;
SeedAndLength = (PSECURITY_SEED_AND_LENGTH)&Password->Length;
//ASSERT(*((LPWCH)SeedAndLength+Password->Length) == 0);
ASSERT((SeedAndLength->Seed) == 0);
RtlRunEncodeUnicodeString(
&LocalSeed,
Password
);
SeedAndLength->Seed = LocalSeed;
}
VOID
SspRevealPassword(
IN OUT PUNICODE_STRING HiddenPassword
)
/*++
Routine Description
Reveals a previously hidden password so that it
is plain text once again.
Arguments:
HiddenPassword - Contains the password to reveal
Return Value
--*/
{
PSECURITY_SEED_AND_LENGTH SeedAndLength;
UCHAR Seed;
SeedAndLength = (PSECURITY_SEED_AND_LENGTH)&HiddenPassword->Length;
Seed = SeedAndLength->Seed;
SeedAndLength->Seed = 0;
RtlRunDecodeUnicodeString(
Seed,
HiddenPassword
);
}