|
|
/*++
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
Module Name:
security.c
Abstract:
This file handles the management of the NLS per-thread and process cache. The cache is only established when hitting an API that needs it. The process NLS cache is used when accessing NLS info for a process NOT running in the context of the interactive logged on user. The per-thread NLS cache is used when accssing NLS info and the thread is doing a user impersonation.
External Routines found in this file: NlsFlushProcessCache NlsGetCurrentUserNlsInfo NlsIsInteractiveUserProcess NlsCheckForInteractiveUser NlsGetUserLocale
Revision History:
03-29-1999 SamerA Created.
--*/
//
// Include Files.
//
#include "nls.h"
#include "nlssafe.h"
//
// Global Variables.
//
//
// Process Nls Cache.
//
PNLS_LOCAL_CACHE gpNlsProcessCache;
//
// Whether the current running process is the same as the
// interactive logged on user.
//
BOOL gInteractiveLogonUserProcess = (BOOL)-1;
//
// Forward Declarations.
//
NTSTATUS FASTCALL NlsGetCacheBuffer( PNLS_USER_INFO pNlsUserInfo, LCTYPE LCType, PWSTR *ppCache);
void FASTCALL NlsInvalidateCache( PNLS_USER_INFO pNlsUserInfo);
//-------------------------------------------------------------------------//
// EXTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// NlsFlushProcessCache
//
// Invalidates an entry in the NLS process cache.
//
// 05-22-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS NlsFlushProcessCache( LCTYPE LCType) { PWSTR pOutputCache; NTSTATUS NtStatus = STATUS_SUCCESS;
//
// If there is no thread impersonation, then flush the
// process entry cache.
//
if (NtCurrentTeb()->IsImpersonating != 0) { return (NtStatus); }
if (gpNlsProcessCache) { NtStatus = NlsGetCacheBuffer( &gpNlsProcessCache->NlsInfo, LCType, &pOutputCache ); if (NT_SUCCESS(NtStatus)) { RtlEnterCriticalSection(&gcsNlsProcessCache);
pOutputCache[0] = NLS_INVALID_INFO_CHAR;
RtlLeaveCriticalSection(&gcsNlsProcessCache); } }
return (NtStatus); }
////////////////////////////////////////////////////////////////////////////
//
// NlsGetCurrentUserNlsInfo
//
// Retreive the NLS info correponding to the current security context.
//
// 03-29-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS NlsGetCurrentUserNlsInfo( LCID Locale, LCTYPE LCType, PWSTR RegistryValue, PWSTR pOutputBuffer, size_t cchOutputBuffer, BOOL IgnoreLocaleValue) { NTSTATUS NtStatus = STATUS_UNSUCCESSFUL; PNLS_LOCAL_CACHE pNlsThreadCache; PWSTR pOutputCache;
//
// Possible NtCurrentTeb()->IsImpersonating values :
//
// 0 : Thread isn't impersonating any user.
//
// 1 : Thread has just started to do impersonation.
// Per thread cache needs to be allocated now.
//
// 2 : Thread is calling the NLS apis while its
// a context other than the interactive logged on user.
//
switch (NtCurrentTeb()->IsImpersonating) { case ( 0 ) : { //
// Thread is NOT impersonating any user. We check if the process
// belongs to the interactive user, then we retreive the info from
// the NLS cache in CSR. Otherwise if the process is running in
// the context of a different user, then we retreive the NLS info
// from the process cache.
//
if (gInteractiveLogonUserProcess == (BOOL)-1) { NlsIsInteractiveUserProcess(); }
if (gInteractiveLogonUserProcess == FALSE) { if ((IgnoreLocaleValue) || (GetUserDefaultLCID() == Locale)) { if (!gpNlsProcessCache) { //
// Allocate and invalidate the NLS process cache.
//
RtlEnterCriticalSection(&gcsNlsProcessCache);
if (!gpNlsProcessCache) { gpNlsProcessCache = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof(NLS_LOCAL_CACHE) ); if (gpNlsProcessCache) { NlsInvalidateCache(&gpNlsProcessCache->NlsInfo); gpNlsProcessCache->CurrentUserKeyHandle = NULL; } }
RtlLeaveCriticalSection(&gcsNlsProcessCache); }
if (gpNlsProcessCache) { NtStatus = NlsGetCacheBuffer( &gpNlsProcessCache->NlsInfo, LCType, &pOutputCache); if (NT_SUCCESS(NtStatus)) { //
// See if it is a valid cache.
//
if (pOutputCache[0] == NLS_INVALID_INFO_CHAR) { RtlEnterCriticalSection(&gcsNlsProcessCache);
if (GetUserInfoFromRegistry( RegistryValue, pOutputCache, MAX_REG_VAL_SIZE, 0 ) == FALSE) { NtStatus = STATUS_UNSUCCESSFUL; pOutputCache[0] = NLS_INVALID_INFO_CHAR; }
RtlLeaveCriticalSection(&gcsNlsProcessCache); }
if (NT_SUCCESS(NtStatus)) { if(FAILED((StringCchCopyW(pOutputBuffer, cchOutputBuffer, pOutputCache)))) { NtStatus = STATUS_UNSUCCESSFUL; } } } } } } break; } case ( 1 ) : { //
// Thread started to do impersonation.
//
pNlsThreadCache = NtCurrentTeb()->NlsCache;
if (!pNlsThreadCache) { pNlsThreadCache = RtlAllocateHeap( RtlProcessHeap(), 0, sizeof(NLS_LOCAL_CACHE) ); if (pNlsThreadCache) { pNlsThreadCache->CurrentUserKeyHandle = NULL; }
NtCurrentTeb()->NlsCache = (PVOID) pNlsThreadCache; }
if (pNlsThreadCache) { NlsInvalidateCache(&pNlsThreadCache->NlsInfo); }
NtCurrentTeb()->IsImpersonating = 2;
//
// Fall Thru...
//
} case ( 2 ) : { //
// Thread is impersonating a particular user.
//
pNlsThreadCache = NtCurrentTeb()->NlsCache;
if (pNlsThreadCache) {
if ((IgnoreLocaleValue) || (GetUserDefaultLCID() == Locale)) { NtStatus = NlsGetCacheBuffer( &pNlsThreadCache->NlsInfo, LCType, &pOutputCache ); if (NT_SUCCESS(NtStatus)) { if (pOutputCache[0] == NLS_INVALID_INFO_CHAR) { //
// Don't cache key handles - this will break
// profile unload.
//
OPEN_CPANEL_INTL_KEY( pNlsThreadCache->CurrentUserKeyHandle, STATUS_UNSUCCESSFUL, KEY_READ );
NtStatus = NlsQueryCurrentUserInfo( pNlsThreadCache, RegistryValue, pOutputCache, MAX_REG_VAL_SIZE );
CLOSE_REG_KEY(pNlsThreadCache->CurrentUserKeyHandle);
if (!NT_SUCCESS(NtStatus)) { pOutputCache[0] = NLS_INVALID_INFO_CHAR; } }
if (NT_SUCCESS(NtStatus)) { if(FAILED((StringCchCopyW(pOutputBuffer, cchOutputBuffer, pOutputCache)))) { NtStatus = STATUS_UNSUCCESSFUL; } } } } } break; } }
return (NtStatus); }
////////////////////////////////////////////////////////////////////////////
//
// NlsIsInteractiveUserProcess
//
// Read the process's authetication id out of its access token object and
// cache it since it never changes.
//
// 12-27-98 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS NlsIsInteractiveUserProcess() { NTSTATUS NtStatus; TOKEN_STATISTICS TokenInformation; HANDLE TokenHandle; ULONG BytesRequired; BOOL IsInteractiveProcess = TRUE;
//
// Get the process access token.
//
NtStatus = NtOpenProcessToken( NtCurrentProcess(), TOKEN_QUERY, &TokenHandle ); if (NT_SUCCESS(NtStatus)) { //
// Get the LUID.
//
NtStatus = NtQueryInformationToken( TokenHandle, TokenStatistics, &TokenInformation, sizeof(TokenInformation), &BytesRequired ); if (NT_SUCCESS(NtStatus)) { if (RtlEqualLuid( &pNlsUserInfo->InteractiveUserLuid, &TokenInformation.AuthenticationId ) == FALSE) { IsInteractiveProcess = FALSE; } }
NtClose(TokenHandle); }
gInteractiveLogonUserProcess = IsInteractiveProcess;
return (NtStatus); }
////////////////////////////////////////////////////////////////////////////
//
// NlsCheckForInteractiveUser
//
// This function makes sure that the current thread isn't impersonating
// anybody, but the interactive. It compares the authentication-id of the
// interactive user -cached in CSRSS at logon time- with the
// authentication-id of the current thread or process. It returns failure
// ONLY if the current security context -session- isn't the same as the
// interactive logged-on user.
//
// 12-16-98 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS NlsCheckForInteractiveUser() { NTSTATUS NtStatus, ReturnStatus = STATUS_SUCCESS; TOKEN_STATISTICS TokenInformation; HANDLE TokenHandle; ULONG BytesRequired; PLUID InteractiveUserLuid = &pNlsUserInfo->InteractiveUserLuid;
//
// Get the Token Handle.
// Fast optimization to detect if a thread hasn't started to do any
// impersonation, which is the case for most GUI user apps.
//
if (NtCurrentTeb()->IsImpersonating == 0) { NtStatus = STATUS_NO_TOKEN; } else { NtStatus = NtOpenThreadToken( NtCurrentThread(), TOKEN_QUERY, FALSE, &TokenHandle ); }
if (!NT_SUCCESS(NtStatus)) { if (NtStatus != STATUS_NO_TOKEN) { KdPrint(("NLSAPI: Couldn't retreive thread token - %lx.\n", NtStatus)); return (STATUS_SUCCESS); }
//
// Get the process access token.
//
if (gInteractiveLogonUserProcess == (BOOL)-1) { NtStatus = NlsIsInteractiveUserProcess();
if (!NT_SUCCESS(NtStatus)) { KdPrint(("NLSAPI: Couldn't retreive process token - %lx\n", NtStatus)); return (STATUS_SUCCESS); } }
if (gInteractiveLogonUserProcess == FALSE) { ReturnStatus = STATUS_UNSUCCESSFUL; } } else { //
// Get the AuthenticationId of the current thread's security context.
//
NtStatus = NtQueryInformationToken( TokenHandle, TokenStatistics, &TokenInformation, sizeof(TokenInformation), &BytesRequired );
//
// Close the thread token here.
//
NtClose(TokenHandle);
if (NT_SUCCESS(NtStatus)) { if (RtlEqualLuid( InteractiveUserLuid, &TokenInformation.AuthenticationId ) == FALSE) { ReturnStatus = STATUS_UNSUCCESSFUL; } } }
return (ReturnStatus); }
////////////////////////////////////////////////////////////////////////////
//
// NlsGetUserLocale
//
// Retreives the user locale from the registry of the current security
// context. It is called ONLY when the running security context is
// different from the interactive logged-on security context-(user).
//
// 12-16-98 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS NlsGetUserLocale( LCID *Lcid) { NTSTATUS NtStatus; WCHAR wszLocale[MAX_REG_VAL_SIZE]; UNICODE_STRING ObLocaleString; PNLS_LOCAL_CACHE pNlsCache = NtCurrentTeb()->NlsCache;
//
// Get the current user locale.
//
NtStatus = NlsGetCurrentUserNlsInfo( LOCALE_USER_DEFAULT, (LCTYPE)LOCALE_SLOCALE, L"Locale", wszLocale, ARRAYSIZE(wszLocale), TRUE ); if ((NT_SUCCESS(NtStatus)) || (GetUserInfoFromRegistry(L"Locale", wszLocale, ARRAYSIZE(wszLocale), 0))) { RtlInitUnicodeString(&ObLocaleString, wszLocale); NtStatus = RtlUnicodeStringToInteger( &ObLocaleString, 16, (PULONG)Lcid); }
return (NtStatus); }
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// NlsGetCacheBuffer
//
// Get a buffer pointer inside the cache for this LCTYPE.
//
// 03-29-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS FASTCALL NlsGetCacheBuffer( PNLS_USER_INFO pNlsUserInfo, LCTYPE LCType, PWSTR *ppCache) { NTSTATUS NtStatus = STATUS_SUCCESS;
switch (LCType) { case ( LOCALE_SLANGUAGE ) : { *ppCache = pNlsUserInfo->sAbbrevLangName; break; } case ( LOCALE_ICOUNTRY ) : { *ppCache = pNlsUserInfo->iCountry; break; } case ( LOCALE_SCOUNTRY ) : { *ppCache = pNlsUserInfo->sCountry; break; } case ( LOCALE_SLIST ) : { *ppCache = pNlsUserInfo->sList; break; } case ( LOCALE_IMEASURE ) : { *ppCache = pNlsUserInfo->iMeasure; break; } case ( LOCALE_IPAPERSIZE ) : { *ppCache = pNlsUserInfo->iPaperSize; break; } case ( LOCALE_SDECIMAL ) : { *ppCache = pNlsUserInfo->sDecimal; break; } case ( LOCALE_STHOUSAND ) : { *ppCache = pNlsUserInfo->sThousand; break; } case ( LOCALE_SGROUPING ) : { *ppCache = pNlsUserInfo->sGrouping; break; } case ( LOCALE_IDIGITS ) : { *ppCache = pNlsUserInfo->iDigits; break; } case ( LOCALE_ILZERO ) : { *ppCache = pNlsUserInfo->iLZero; break; } case ( LOCALE_INEGNUMBER ) : { *ppCache = pNlsUserInfo->iNegNumber; break; } case ( LOCALE_SNATIVEDIGITS ) : { *ppCache = pNlsUserInfo->sNativeDigits; break; } case ( LOCALE_IDIGITSUBSTITUTION ) : { *ppCache = pNlsUserInfo->iDigitSubstitution; break; } case ( LOCALE_SCURRENCY ) : { *ppCache = pNlsUserInfo->sCurrency; break; } case ( LOCALE_SMONDECIMALSEP ) : { *ppCache = pNlsUserInfo->sMonDecSep; break; } case ( LOCALE_SMONTHOUSANDSEP ) : { *ppCache = pNlsUserInfo->sMonThouSep; break; } case ( LOCALE_SMONGROUPING ) : { *ppCache = pNlsUserInfo->sMonGrouping; break; } case ( LOCALE_ICURRDIGITS ) : { *ppCache = pNlsUserInfo->iCurrDigits; break; } case ( LOCALE_ICURRENCY ) : { *ppCache = pNlsUserInfo->iCurrency; break; } case ( LOCALE_INEGCURR ) : { *ppCache = pNlsUserInfo->iNegCurr; break; } case ( LOCALE_SPOSITIVESIGN ) : { *ppCache = pNlsUserInfo->sPosSign; break; } case ( LOCALE_SNEGATIVESIGN ) : { *ppCache = pNlsUserInfo->sNegSign; break; } case ( LOCALE_STIMEFORMAT ) : { *ppCache = pNlsUserInfo->sTimeFormat; break; } case ( LOCALE_STIME ) : { *ppCache = pNlsUserInfo->sTime; break; } case ( LOCALE_ITIME ) : { *ppCache = pNlsUserInfo->iTime; break; } case ( LOCALE_ITLZERO ) : { *ppCache = pNlsUserInfo->iTLZero; break; } case ( LOCALE_ITIMEMARKPOSN ) : { *ppCache = pNlsUserInfo->iTimeMarkPosn; break; } case ( LOCALE_S1159 ) : { *ppCache = pNlsUserInfo->s1159; break; } case ( LOCALE_S2359 ) : { *ppCache = pNlsUserInfo->s2359; break; } case ( LOCALE_SSHORTDATE ) : { *ppCache = pNlsUserInfo->sShortDate; break; } case ( LOCALE_SDATE ) : { *ppCache = pNlsUserInfo->sDate; break; } case ( LOCALE_IDATE ) : { *ppCache = pNlsUserInfo->iDate; break; } case ( LOCALE_SYEARMONTH ) : { *ppCache = pNlsUserInfo->sYearMonth; break; } case ( LOCALE_SLONGDATE ) : { *ppCache = pNlsUserInfo->sLongDate; break; } case ( LOCALE_ICALENDARTYPE ) : { *ppCache = pNlsUserInfo->iCalType; break; } case ( LOCALE_IFIRSTDAYOFWEEK ) : { *ppCache = pNlsUserInfo->iFirstDay; break; } case ( LOCALE_IFIRSTWEEKOFYEAR ) : { *ppCache = pNlsUserInfo->iFirstWeek; break; } case ( LOCALE_SLOCALE ) : { *ppCache = pNlsUserInfo->sLocale; break; } default : { NtStatus = STATUS_UNSUCCESSFUL; break; } }
return (NtStatus); }
////////////////////////////////////////////////////////////////////////////
//
// NlsQueryCurrentUserInfo
//
// Retreive the NLS info from the registry using a cached key.
//
// 04-07-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
NTSTATUS NlsQueryCurrentUserInfo( PNLS_LOCAL_CACHE pNlsCache, LPWSTR pValue, LPWSTR pOutput, size_t cchOutput) { PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
ULONG rc;
//
// Initialize the output string.
//
*pOutput = 0;
//
// Query the registry value.
//
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic; rc = QueryRegValue( pNlsCache->CurrentUserKeyHandle, pValue, &pKeyValueFull, MAX_KEY_VALUE_FULLINFO, NULL );
//
// If the query failed or if the output buffer is not large enough,
// then return failure.
//
if ((rc != NO_ERROR) || (pKeyValueFull->DataLength > (MAX_REG_VAL_SIZE * sizeof(WCHAR)))) { return (STATUS_UNSUCCESSFUL); }
//
// Save the string in pOutput.
//
if(FAILED(StringCchCopyW(pOutput, MAX_REG_VAL_SIZE, GET_VALUE_DATA_PTR(pKeyValueFull)))) { return (STATUS_UNSUCCESSFUL); }
//
// Return success.
//
return (STATUS_SUCCESS); }
////////////////////////////////////////////////////////////////////////////
//
// NlsInvalidateCache
//
// Invalidate an NLS Cache.
//
// 03-29-99 SamerA Created.
////////////////////////////////////////////////////////////////////////////
void FASTCALL NlsInvalidateCache( PNLS_USER_INFO pNlsUserInfo) { pNlsUserInfo->sAbbrevLangName[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iCountry[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sCountry[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sList[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iMeasure[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iPaperSize[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sDecimal[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sThousand[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sGrouping[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iDigits[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iLZero[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iNegNumber[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sNativeDigits[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iDigitSubstitution[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sCurrency[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sMonDecSep[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sMonThouSep[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sMonGrouping[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iCurrDigits[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iCurrency[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iNegCurr[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sPosSign[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sNegSign[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sTimeFormat[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sTime[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iTime[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iTLZero[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iTimeMarkPosn[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->s1159[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->s2359[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sShortDate[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sDate[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iDate[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sYearMonth[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sLongDate[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iCalType[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iFirstDay[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->iFirstWeek[0] = NLS_INVALID_INFO_CHAR; pNlsUserInfo->sLocale[0] = NLS_INVALID_INFO_CHAR;
return; }
|