/*++ Copyright (c) 1987-1993 Microsoft Corporation Module Name: utility.cxx 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: ChandanS 06-Aug-1996 Stolen from net\svcdlls\ntlmssp\common\utility.c --*/ // // Common include files. // #include // // Include files specific to this .c file // #include // NetpMemoryFree() #include // ACE_DATA ... #include // vsprintf(). #include // 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) #if DBG SECURITY_STATUS SspNtStatusToSecStatus( IN NTSTATUS NtStatus, IN SECURITY_STATUS DefaultStatus ) /*++ Routine Description: Convert an NtStatus code to the corresponding Security status code. For particular errors that are required to be returned as is (for setup code) don't map the errors. Arguments: NtStatus - NT status to convert Return Value: Returns security status code. --*/ { // // this routine is left here for DBG builds to enable the developer // to ASSERT on status codes, etc. // return(NtStatus); } #endif 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 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 NtLmFree. --*/ { DWORD Size; LPWSTR ptr; Size = WCSSIZE(Unicode); ptr = (LPWSTR)NtLmAllocate(Size); if ( ptr != NULL) { RtlCopyMemory(ptr, Unicode, Size); } return ptr; } 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: --*/ { SspPrint((SSP_API_MORE, "Entering SspHidePassword\n")); if( (Password->Length != 0) && (Password->MaximumLength != 0) ) { LsaFunctions->LsaProtectMemory( Password->Buffer, (ULONG)Password->MaximumLength ); } SspPrint((SSP_API_MORE, "Leaving SspHidePassword\n")); } 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 --*/ { SspPrint((SSP_API_MORE, "Entering SspRevealPassword\n")); if( (HiddenPassword->Length != 0) && (HiddenPassword->MaximumLength != 0) ) { LsaFunctions->LsaUnprotectMemory( HiddenPassword->Buffer, (ULONG)HiddenPassword->MaximumLength ); } SspPrint((SSP_API_MORE, "Leaving SspRevealPassword\n")); } BOOLEAN SspGetTokenBuffer( IN PSecBufferDesc TokenDescriptor OPTIONAL, IN ULONG BufferIndex, OUT PSecBuffer * Token, IN BOOLEAN ReadonlyOK ) /*++ Routine Description: This routine parses a Token Descriptor and pulls out the useful information. Arguments: TokenDescriptor - Descriptor of the buffer containing (or to contain) the token. If not specified, TokenBuffer and TokenSize will be returned as NULL. TokenBuffer - Returns a pointer to the buffer for the token. TokenSize - Returns a pointer to the location of the size of the buffer. ReadonlyOK - TRUE if the token buffer may be readonly. Return Value: TRUE - If token buffer was properly found. --*/ { ULONG i, Index = 0; // // If there is no TokenDescriptor passed in, // just pass out NULL to our caller. // ASSERT(*Token != NULL); if ( !ARGUMENT_PRESENT( TokenDescriptor) ) { return TRUE; } if (TokenDescriptor->ulVersion != SECBUFFER_VERSION) { return FALSE; } // // Loop through each described buffer. // for ( i=0; icBuffers ; i++ ) { PSecBuffer Buffer = &TokenDescriptor->pBuffers[i]; if ( (Buffer->BufferType & (~SECBUFFER_ATTRMASK)) == SECBUFFER_TOKEN ) { // // If the buffer is readonly and readonly isn't OK, // reject the buffer. // if (!ReadonlyOK && (Buffer->BufferType & SECBUFFER_READONLY)) { return FALSE; } // // It is possible that there are > 1 buffers of type SECBUFFER_TOKEN // eg, the rdr // if (Index != BufferIndex) { Index++; continue; } // // Return the requested information // if (!NT_SUCCESS(LsaFunctions->MapBuffer(Buffer, Buffer))) { return FALSE; } *Token = Buffer; return TRUE; } } // // If we didn't have a buffer, fine. // SspPrint((SSP_API_MORE, "SspGetTokenBuffer: No token passed in\n")); return TRUE; }