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.
1364 lines
40 KiB
1364 lines
40 KiB
/*++
|
|
|
|
Copyright (c) 1991-2000, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
srvnls.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the NLS Server-Side routines.
|
|
|
|
Author:
|
|
|
|
Julie Bennett (JulieB) 02-Dec-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files.
|
|
//
|
|
|
|
#include "basesrv.h"
|
|
|
|
|
|
|
|
|
|
//
|
|
// Constant Declarations.
|
|
//
|
|
|
|
#define MAX_PATH_LEN 512 // max length of path name
|
|
#define MAX_SMALL_BUF_LEN 32 // C_nlsXXXXX.nls\0 is longest file name (15),
|
|
// \NLS\NlsSectionSortkey0000XXXX\0 (31) is longest section name
|
|
|
|
// Security descriptor buffer is size of SD + size of ACL + size of ACE +
|
|
// sizeof SID + sizeof 1 SUB_AUTHORITY.
|
|
//
|
|
// THIS IS ONLY VALID FOR 1 ACE with 1 SID (SUB_AUTHORITY). If you have more it won't work for you.
|
|
//
|
|
// ACE is size of ACE_HEADER + size of ACCESS_MASK
|
|
// SID includes the first ULONG (pointer) of the PSID_IDENTIFIER_AUTHORITY array, so this
|
|
// declaration should be 4 bytes too much for a 1 ACL 1 SID 1 SubAuthority SD.
|
|
// This is 52 bytes at the moment, only needs to be 48.
|
|
// (I tested this by using -4, which works and -5 which STOPS during the boot.
|
|
#define MAX_SMALL_SECURITY_DESCRIPTOR \
|
|
(sizeof(SECURITY_DESCRIPTOR) + sizeof(ACL) + \
|
|
sizeof(ACE_HEADER) + sizeof(ACCESS_MASK) + \
|
|
sizeof(SID) + sizeof(PSID_IDENTIFIER_AUTHORITY ))
|
|
|
|
#define MAX_KEY_VALUE_PARTINFO \
|
|
(FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + MAX_REG_VAL_SIZE * sizeof(WCHAR))
|
|
|
|
//
|
|
// Get the data pointer for the KEY_VALUE_FULL_INFORMATION structure.
|
|
//
|
|
#define GET_VALUE_DATA_PTR(p) ((LPWSTR)((PBYTE)(p) + (p)->DataOffset))
|
|
|
|
|
|
//
|
|
// Size of stack buffer for PKEY_VALUE_FULL_INFORMATION pointer.
|
|
//
|
|
#define MAX_KEY_VALUE_FULLINFO \
|
|
( FIELD_OFFSET( KEY_VALUE_FULL_INFORMATION, Name ) + MAX_PATH_LEN )
|
|
|
|
|
|
|
|
|
|
//
|
|
// Typedef Declarations.
|
|
//
|
|
|
|
//
|
|
// These MUST remain in the same order as the NLS_USER_INFO structure.
|
|
//
|
|
LPWSTR pCPanelRegValues[] =
|
|
{
|
|
L"sLanguage",
|
|
L"iCountry",
|
|
L"sCountry",
|
|
L"sList",
|
|
L"iMeasure",
|
|
L"iPaperSize",
|
|
L"sDecimal",
|
|
L"sThousand",
|
|
L"sGrouping",
|
|
L"iDigits",
|
|
L"iLZero",
|
|
L"iNegNumber",
|
|
L"sNativeDigits",
|
|
L"NumShape",
|
|
L"sCurrency",
|
|
L"sMonDecimalSep",
|
|
L"sMonThousandSep",
|
|
L"sMonGrouping",
|
|
L"iCurrDigits",
|
|
L"iCurrency",
|
|
L"iNegCurr",
|
|
L"sPositiveSign",
|
|
L"sNegativeSign",
|
|
L"sTimeFormat",
|
|
L"sTime",
|
|
L"iTime",
|
|
L"iTLZero",
|
|
L"iTimePrefix",
|
|
L"s1159",
|
|
L"s2359",
|
|
L"sShortDate",
|
|
L"sDate",
|
|
L"iDate",
|
|
L"sYearMonth",
|
|
L"sLongDate",
|
|
L"iCalendarType",
|
|
L"iFirstDayOfWeek",
|
|
L"iFirstWeekOfYear",
|
|
L"Locale"
|
|
};
|
|
|
|
int NumCPanelRegValues = (sizeof(pCPanelRegValues) / sizeof(LPWSTR));
|
|
|
|
|
|
|
|
|
|
//
|
|
// Global Variables.
|
|
//
|
|
|
|
// Critical Section to protect the NLS cache, which caches the current user settings from registry.
|
|
RTL_CRITICAL_SECTION NlsCacheCriticalSection;
|
|
HANDLE hCPanelIntlKeyRead = INVALID_HANDLE_VALUE;
|
|
HANDLE hCPanelIntlKeyWrite = INVALID_HANDLE_VALUE;
|
|
PNLS_USER_INFO pNlsRegUserInfo;
|
|
ULONG NlsChangeBuffer;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
|
|
|
|
|
|
//
|
|
// Forward Declarations.
|
|
//
|
|
|
|
ULONG
|
|
NlsSetRegAndCache(
|
|
LPWSTR pValue,
|
|
LPWSTR pCacheString,
|
|
LPWSTR pData,
|
|
ULONG DataLength);
|
|
|
|
VOID
|
|
NlsUpdateCacheInfo(VOID);
|
|
|
|
NTSTATUS GetThreadAuthenticationId(
|
|
PLUID Luid);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNLSInit
|
|
//
|
|
// This routine creates the shared heap for the nls information.
|
|
// This is called when csrss.exe is initialized.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
BaseSrvNLSInit(
|
|
PBASE_STATIC_SERVER_DATA pStaticServerData)
|
|
{
|
|
NTSTATUS rc; // return code
|
|
|
|
//
|
|
// Create a critical section to protect the cache.
|
|
//
|
|
|
|
rc = RtlInitializeCriticalSection (&NlsCacheCriticalSection);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Create Cache critical section - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
|
|
//
|
|
// Initialize the cache to zero.
|
|
//
|
|
pNlsRegUserInfo = &(pStaticServerData->NlsUserInfo);
|
|
RtlFillMemory(pNlsRegUserInfo, sizeof(NLS_USER_INFO), (CHAR)NLS_INVALID_INFO_CHAR);
|
|
pNlsRegUserInfo->UserLocaleId = 0;
|
|
|
|
RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
pNlsRegUserInfo->ulCacheUpdateCount = 0;
|
|
RtlLeaveCriticalSection(&NlsCacheCriticalSection);
|
|
//
|
|
// Make the system locale the user locale.
|
|
//
|
|
NtQueryDefaultLocale(FALSE, &(pNlsRegUserInfo->UserLocaleId));
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNLSConnect
|
|
//
|
|
// This routine duplicates the mutant handle for the client.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
BaseSrvNlsConnect(
|
|
PCSR_PROCESS Process,
|
|
PVOID pConnectionInfo,
|
|
PULONG pConnectionInfoLength)
|
|
{
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsLogon
|
|
//
|
|
// This routine initializes the heap for the nls information. If fLogon
|
|
// is TRUE, then it opens the registry key, initializes the heap
|
|
// information, and registers the key for notification. If fLogon is
|
|
// FALSE, then it unregisters the key for notification, zeros out the
|
|
// heap information, and closes the registry key.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
BaseSrvNlsLogon(
|
|
BOOL fLogon)
|
|
{
|
|
HANDLE hKeyRead; // temp handle for read access
|
|
HANDLE hKeyWrite; // temp handle for write access
|
|
HANDLE hUserHandle; // HKEY_CURRENT_USER equivalent
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
UNICODE_STRING ObKeyName; // key name
|
|
NTSTATUS rc = STATUS_SUCCESS; // return code
|
|
|
|
RTL_SOFT_VERIFY(NT_SUCCESS(rc = BaseSrvSxsInvalidateSystemDefaultActivationContextCache()));
|
|
|
|
if (fLogon)
|
|
{
|
|
//
|
|
// Retreive the currently logged on interactive user's Luid
|
|
// authentication id. The currently executing thread is
|
|
// impersonating the logged on user.
|
|
//
|
|
if (pNlsRegUserInfo != NULL)
|
|
{
|
|
GetThreadAuthenticationId(&pNlsRegUserInfo->InteractiveUserLuid);
|
|
|
|
//
|
|
// Logging ON.
|
|
// - open keys
|
|
//
|
|
// NOTE: Registry Notification is done by the RIT in user server.
|
|
//
|
|
rc = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &hUserHandle);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Open HKEY_CURRENT_USER - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
RtlInitUnicodeString(&ObKeyName, L"Control Panel\\International");
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
hUserHandle,
|
|
NULL );
|
|
|
|
//
|
|
// Open key for READ and NOTIFY access.
|
|
//
|
|
rc = NtOpenKey( &hKeyRead,
|
|
KEY_READ | KEY_NOTIFY,
|
|
&ObjA );
|
|
|
|
//
|
|
// Open key for WRITE access.
|
|
//
|
|
if (!NT_SUCCESS(NtOpenKey( &hKeyWrite,
|
|
KEY_WRITE,
|
|
&ObjA )))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Open Registry Key %wZ for Write - %lx.\n",
|
|
&ObKeyName, rc));
|
|
hKeyWrite = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Close the handle to the current user (HKEY_CURRENT_USER).
|
|
//
|
|
NtClose(hUserHandle);
|
|
|
|
//
|
|
// Check for error from first NtOpenKey.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Open Registry Key %wZ for Read - %lx.\n",
|
|
&ObKeyName, rc));
|
|
|
|
if (hKeyWrite != INVALID_HANDLE_VALUE)
|
|
{
|
|
NtClose(hKeyWrite);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Enter the critical section so that we don't mess up the public handle.
|
|
//
|
|
rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
if (!NT_SUCCESS( rc ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
|
|
//
|
|
// Make sure any old handles are closed.
|
|
//
|
|
if (hCPanelIntlKeyRead != INVALID_HANDLE_VALUE)
|
|
{
|
|
NtClose(hCPanelIntlKeyRead);
|
|
}
|
|
|
|
if (hCPanelIntlKeyWrite != INVALID_HANDLE_VALUE)
|
|
{
|
|
NtClose(hCPanelIntlKeyWrite);
|
|
}
|
|
|
|
//
|
|
// Save the new handles.
|
|
//
|
|
hCPanelIntlKeyRead = hKeyRead;
|
|
hCPanelIntlKeyWrite = hKeyWrite;
|
|
|
|
//
|
|
// Fill up the cache so that we have the latest intl settings in the registry.
|
|
//
|
|
NlsUpdateCacheInfo();
|
|
RtlLeaveCriticalSection(&NlsCacheCriticalSection);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Logging OFF.
|
|
// - close keys
|
|
// - zero out info
|
|
//
|
|
|
|
//
|
|
// This may come as NULL, during stress memory cond for terminal
|
|
// server (when NLS cache mutant couldn't be created).
|
|
//
|
|
if (pNlsRegUserInfo != NULL)
|
|
{
|
|
rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
if (!NT_SUCCESS( rc ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
if (hCPanelIntlKeyRead != INVALID_HANDLE_VALUE)
|
|
{
|
|
NtClose(hCPanelIntlKeyRead);
|
|
hCPanelIntlKeyRead = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
if (hCPanelIntlKeyWrite != INVALID_HANDLE_VALUE)
|
|
{
|
|
NtClose(hCPanelIntlKeyWrite);
|
|
hCPanelIntlKeyWrite = INVALID_HANDLE_VALUE;
|
|
}
|
|
|
|
//
|
|
// Fill the cache with NLS_INVALID_INFO_CHAR.
|
|
//
|
|
RtlFillMemory(pNlsRegUserInfo, sizeof(NLS_USER_INFO), (CHAR)NLS_INVALID_INFO_CHAR);
|
|
pNlsRegUserInfo->UserLocaleId = 0;
|
|
// Reset the cache update count. There is no need to use InterlockedExchange() since
|
|
// all updates to ulCacheUpdateCount are protected in the critical section NlsCacheCriticalSection.
|
|
pNlsRegUserInfo->ulCacheUpdateCount = 0;
|
|
|
|
//
|
|
// Make the system locale the user locale.
|
|
//
|
|
NtQueryDefaultLocale(FALSE, &(pNlsRegUserInfo->UserLocaleId));
|
|
|
|
//
|
|
// No need to reset the User's Authentication Id, since it's
|
|
// being zero'ed out above.
|
|
//
|
|
|
|
RtlLeaveCriticalSection(&NlsCacheCriticalSection);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (STATUS_SUCCESS);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsUpdateRegistryCache
|
|
//
|
|
// This routine updates the NLS cache when a registry notification occurs.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
BaseSrvNlsUpdateRegistryCache(
|
|
PVOID ApcContext,
|
|
PIO_STATUS_BLOCK pIoStatusBlock)
|
|
{
|
|
ULONG rc = 0L; // return code
|
|
|
|
if (hCPanelIntlKeyRead == INVALID_HANDLE_VALUE)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!NT_SUCCESS(RtlEnterCriticalSection(&NlsCacheCriticalSection)))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (hCPanelIntlKeyRead == INVALID_HANDLE_VALUE)
|
|
{
|
|
RtlLeaveCriticalSection( &NlsCacheCriticalSection );
|
|
return;
|
|
}
|
|
|
|
//
|
|
// Update the cache information.
|
|
//
|
|
NlsUpdateCacheInfo();
|
|
|
|
RtlLeaveCriticalSection( &NlsCacheCriticalSection );
|
|
|
|
//
|
|
// Call NtNotifyChangeKey.
|
|
//
|
|
rc = NtNotifyChangeKey( hCPanelIntlKeyRead,
|
|
NULL,
|
|
(PIO_APC_ROUTINE)BaseSrvNlsUpdateRegistryCache,
|
|
NULL,
|
|
&IoStatusBlock,
|
|
REG_NOTIFY_CHANGE_LAST_SET | REG_NOTIFY_CHANGE_NAME,
|
|
FALSE,
|
|
&NlsChangeBuffer,
|
|
sizeof(NlsChangeBuffer),
|
|
TRUE );
|
|
|
|
#ifdef DBG
|
|
//
|
|
// Check for error from NtNotifyChangeKey.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Set Notification of Control Panel International Registry Key - %lx.\n",
|
|
rc));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NlsSetRegAndCache
|
|
//
|
|
// This routine sets the registry with the appropriate string and then
|
|
// updates the cache.
|
|
//
|
|
// NOTE: Must already own the mutant for the cache before calling this
|
|
// routine.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
NlsSetRegAndCache(
|
|
LPWSTR pValue,
|
|
LPWSTR pCacheString,
|
|
LPWSTR pData,
|
|
ULONG DataLength)
|
|
{
|
|
UNICODE_STRING ObValueName; // value name
|
|
ULONG rc; // return code
|
|
|
|
if (hCPanelIntlKeyWrite != INVALID_HANDLE_VALUE)
|
|
{
|
|
//
|
|
// Validate data length to be set in the registry
|
|
//
|
|
if (DataLength >= MAX_REG_VAL_SIZE)
|
|
{
|
|
return ((ULONG)STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
RTL_SOFT_VERIFY(NT_SUCCESS(rc = BaseSrvSxsInvalidateSystemDefaultActivationContextCache()));
|
|
|
|
//
|
|
// Set the value in the registry.
|
|
//
|
|
RtlInitUnicodeString(&ObValueName, pValue);
|
|
|
|
rc = NtSetValueKey( hCPanelIntlKeyWrite,
|
|
&ObValueName,
|
|
0,
|
|
REG_SZ,
|
|
(PVOID)pData,
|
|
DataLength );
|
|
|
|
//
|
|
// Copy the new string to the cache.
|
|
//
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
wcsncpy(pCacheString, pData, DataLength);
|
|
pCacheString[DataLength / sizeof(WCHAR)] = 0;
|
|
}
|
|
|
|
//
|
|
// Return the result.
|
|
//
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return access denied, since the key is not open for write access.
|
|
//
|
|
return ((ULONG)STATUS_ACCESS_DENIED);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsGetUserInfo
|
|
//
|
|
// This routine gets all of the values (including ulCacheUpdateCount) in the NLS cache, and copy it
|
|
// to the buffer in the capture buffer.
|
|
//
|
|
// Parameters:
|
|
// pData in BASE_NLS_GET_USER_INFO_MSG contains the target buffer to write.
|
|
// DataLength in BASE_NLS_GET_USER_INFO_MSG is the size of target buffer. It should be the value of sizeof(NLS_USER_INFO).
|
|
//
|
|
// When this function returns, the capture buffer will contain the data
|
|
// of the specified field.
|
|
//
|
|
//
|
|
// 06-06-2002 YSLin Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS
|
|
BaseSrvNlsGetUserInfo(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_GET_USER_INFO_MSG a =
|
|
(PBASE_NLS_GET_USER_INFO_MSG)&m->u.ApiMessageData;
|
|
|
|
NTSTATUS rc; // return code
|
|
LPWSTR pValue; // Points to the cached value.
|
|
|
|
if (!CsrValidateMessageBuffer(m, &a->pData, a->DataLength, sizeof(BYTE)))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
|
|
if (a->DataLength != sizeof(NLS_USER_INFO))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
if (!NT_SUCCESS( rc ))
|
|
{
|
|
return (rc);
|
|
}
|
|
RtlCopyMemory((LPVOID)a->pData, pNlsRegUserInfo, a->DataLength);
|
|
RtlLeaveCriticalSection( &NlsCacheCriticalSection );
|
|
|
|
|
|
//
|
|
// Return the result of NtSetValueKey.
|
|
//
|
|
return (rc);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsSetUserInfo
|
|
//
|
|
// This routine sets a particular value in the NLS cache and updates the
|
|
// registry entry.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
BaseSrvNlsSetUserInfo(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_SET_USER_INFO_MSG a =
|
|
(PBASE_NLS_SET_USER_INFO_MSG)&m->u.ApiMessageData;
|
|
|
|
ULONG rc; // return code
|
|
LPWSTR pValue;
|
|
LPWSTR pCache;
|
|
|
|
if (!CsrValidateMessageBuffer(m, &a->pData, a->DataLength, sizeof(BYTE)))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
RTL_VERIFY(NT_SUCCESS(rc = BaseSrvDelayLoadKernel32()));
|
|
ASSERT(pValidateLCType != NULL);
|
|
|
|
if (0 == (*pValidateLCType)(pNlsRegUserInfo, a->LCType, &pValue, &pCache))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
if (!NT_SUCCESS( rc ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
|
|
//
|
|
// Set the value in the registry and update the cache.
|
|
//
|
|
rc = NlsSetRegAndCache( pValue,
|
|
pCache,
|
|
a->pData,
|
|
a->DataLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
// Increment the cache update count. There is no need to use InterlockedExchange() since
|
|
// all updates to ulCacheUpdateCount are protected in the same critical section.
|
|
|
|
pNlsRegUserInfo->ulCacheUpdateCount++;
|
|
}
|
|
|
|
RtlLeaveCriticalSection( &NlsCacheCriticalSection );
|
|
|
|
//
|
|
// Return the result of NtSetValueKey.
|
|
//
|
|
return (rc);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsSetMultipleUserInfo
|
|
//
|
|
// This routine sets the date/time strings in the NLS cache and updates the
|
|
// registry entries.
|
|
//
|
|
// This call is done so that only one client/server transition is needed
|
|
// when setting multiple entries.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
BaseSrvNlsSetMultipleUserInfo(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_SET_MULTIPLE_USER_INFO_MSG a =
|
|
(PBASE_NLS_SET_MULTIPLE_USER_INFO_MSG)&m->u.ApiMessageData;
|
|
|
|
BOOL DoNotUpdateCacheCount = FALSE;
|
|
ULONG rc = 0L; // return code
|
|
|
|
if (!CsrValidateMessageBuffer(m, &a->pPicture, a->DataLength, sizeof(BYTE)))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (!CsrValidateMessageString(m, &a->pSeparator))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (!CsrValidateMessageString(m, &a->pOrder))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (!CsrValidateMessageString(m, &a->pTLZero))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (!CsrValidateMessageString(m, &a->pTimeMarkPosn))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
rc = RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
if (!NT_SUCCESS( rc ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
|
|
switch (a->Flags)
|
|
{
|
|
case ( LOCALE_STIMEFORMAT ) :
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_STIMEFORMAT,
|
|
pNlsRegUserInfo->sTimeFormat,
|
|
a->pPicture,
|
|
a->DataLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_STIME,
|
|
pNlsRegUserInfo->sTime,
|
|
a->pSeparator,
|
|
(wcslen(a->pSeparator) + 1) * sizeof(WCHAR) );
|
|
}
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_ITIME,
|
|
pNlsRegUserInfo->iTime,
|
|
a->pOrder,
|
|
(wcslen(a->pOrder) + 1) * sizeof(WCHAR) );
|
|
}
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_ITLZERO,
|
|
pNlsRegUserInfo->iTLZero,
|
|
a->pTLZero,
|
|
(wcslen(a->pTLZero) + 1) * sizeof(WCHAR) );
|
|
}
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_ITIMEMARKPOSN,
|
|
pNlsRegUserInfo->iTimeMarkPosn,
|
|
a->pTimeMarkPosn,
|
|
(wcslen(a->pTimeMarkPosn) + 1) * sizeof(WCHAR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ( LOCALE_STIME ) :
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_STIME,
|
|
pNlsRegUserInfo->sTime,
|
|
a->pSeparator,
|
|
a->DataLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_STIMEFORMAT,
|
|
pNlsRegUserInfo->sTimeFormat,
|
|
a->pPicture,
|
|
(wcslen(a->pPicture) + 1) * sizeof(WCHAR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ( LOCALE_ITIME ) :
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_ITIME,
|
|
pNlsRegUserInfo->iTime,
|
|
a->pOrder,
|
|
a->DataLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_STIMEFORMAT,
|
|
pNlsRegUserInfo->sTimeFormat,
|
|
a->pPicture,
|
|
(wcslen(a->pPicture) + 1) * sizeof(WCHAR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ( LOCALE_SSHORTDATE ) :
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_SSHORTDATE,
|
|
pNlsRegUserInfo->sShortDate,
|
|
a->pPicture,
|
|
a->DataLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_SDATE,
|
|
pNlsRegUserInfo->sDate,
|
|
a->pSeparator,
|
|
(wcslen(a->pSeparator) + 1) * sizeof(WCHAR) );
|
|
}
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_IDATE,
|
|
pNlsRegUserInfo->iDate,
|
|
a->pOrder,
|
|
(wcslen(a->pOrder) + 1) * sizeof(WCHAR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
case ( LOCALE_SDATE ) :
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_SDATE,
|
|
pNlsRegUserInfo->sDate,
|
|
a->pSeparator,
|
|
a->DataLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
rc = NlsSetRegAndCache( NLS_VALUE_SSHORTDATE,
|
|
pNlsRegUserInfo->sShortDate,
|
|
a->pPicture,
|
|
(wcslen(a->pPicture) + 1) * sizeof(WCHAR) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
DoNotUpdateCacheCount = TRUE;
|
|
break;
|
|
}
|
|
|
|
|
|
}
|
|
|
|
if (NT_SUCCESS(rc) && (DoNotUpdateCacheCount == FALSE))
|
|
{
|
|
// Increment the cache update count. There is no need to use InterlockedExchange() since
|
|
// all updates to ulCacheUpdateCount are protected in the same critical section.
|
|
|
|
pNlsRegUserInfo->ulCacheUpdateCount++;
|
|
}
|
|
|
|
RtlLeaveCriticalSection(&NlsCacheCriticalSection);
|
|
//
|
|
// Return the result.
|
|
//
|
|
return (rc);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsUpdateCacheCount
|
|
//
|
|
// This routine forces an increment on pNlsUserInfo->ulNlsCacheUpdateCount
|
|
//
|
|
// 11-29-99 SamerA Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
BaseSrvNlsUpdateCacheCount(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_UPDATE_CACHE_COUNT_MSG a =
|
|
(PBASE_NLS_UPDATE_CACHE_COUNT_MSG)&m->u.ApiMessageData;
|
|
|
|
//
|
|
// Increment the cache count.
|
|
// Use Interlocked operation since we do not use a critical section here.
|
|
//
|
|
if (pNlsRegUserInfo)
|
|
{
|
|
RtlEnterCriticalSection(&NlsCacheCriticalSection);
|
|
pNlsRegUserInfo->ulCacheUpdateCount++;
|
|
RtlLeaveCriticalSection(&NlsCacheCriticalSection);
|
|
}
|
|
|
|
return (0L);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NlsUpdateCacheInfo
|
|
//
|
|
// This routine updates the NLS cache when a registry notification occurs.
|
|
/// It will update every field in the NLS cache which stores value in the
|
|
// the registry.
|
|
//
|
|
// NOTENOTE:
|
|
// THE CALLER OF THIS FUNCITON SHOULD BE IN A CRITICAL SECTION
|
|
// PROTECTED BY NlsCacheCriticalSection, SINCE THE ulCacheUpdateCount
|
|
// AND pNlsRegUserInfo ARE UPDATED IN THIS FUNCTION.
|
|
//
|
|
// 08-19-94 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
VOID
|
|
NlsUpdateCacheInfo()
|
|
{
|
|
LCID Locale; // locale id
|
|
UNICODE_STRING ObKeyName; // key name
|
|
LPWSTR pTmp; // tmp string pointer
|
|
int ctr; // loop counter
|
|
ULONG ResultLength; // result length
|
|
ULONG rc = 0L; // return code
|
|
|
|
BYTE KeyValuePart[MAX_KEY_VALUE_PARTINFO];
|
|
PKEY_VALUE_PARTIAL_INFORMATION pValuePart;
|
|
|
|
//
|
|
// NOTE: The caller of this function should already have the
|
|
// cache mutant before calling this routine.
|
|
//
|
|
|
|
//
|
|
// Update the cache information.
|
|
//
|
|
pTmp = (LPWSTR)pNlsRegUserInfo;
|
|
pValuePart = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValuePart;
|
|
for (ctr = 0; ctr < NumCPanelRegValues; ctr++)
|
|
{
|
|
RtlInitUnicodeString(&ObKeyName, pCPanelRegValues[ctr]);
|
|
rc = NtQueryValueKey( hCPanelIntlKeyRead,
|
|
&ObKeyName,
|
|
KeyValuePartialInformation,
|
|
pValuePart,
|
|
MAX_KEY_VALUE_PARTINFO,
|
|
&ResultLength );
|
|
if (NT_SUCCESS(rc))
|
|
{
|
|
wcsncpy(pTmp, (LPWSTR)(pValuePart->Data), MAX_REG_VAL_SIZE);
|
|
// When the length of the string in the registry is greater than or equal to
|
|
// MAX_REG_VAL_SIZE, wcsncpy won't put NULL terminiator for us. So we make sure that
|
|
// it is NULL terminated at the end of the buffer in the statement below.
|
|
pTmp[MAX_REG_VAL_SIZE - 1] = UNICODE_NULL;
|
|
}
|
|
else
|
|
{
|
|
*pTmp = NLS_INVALID_INFO_CHAR;
|
|
*(pTmp + 1) = UNICODE_NULL;
|
|
}
|
|
|
|
//
|
|
// Increment pointer to cache structure.
|
|
//
|
|
pTmp += MAX_REG_VAL_SIZE;
|
|
}
|
|
|
|
//
|
|
// Once we finished reading the reg-data, let's increment
|
|
// our global update cache count
|
|
//
|
|
pNlsRegUserInfo->ulCacheUpdateCount++;
|
|
|
|
//
|
|
// Convert the user locale id string to a dword value and store
|
|
// it in the cache.
|
|
//
|
|
pNlsRegUserInfo->UserLocaleId = (LCID)0;
|
|
if ((pNlsRegUserInfo->sLocale)[0] != NLS_INVALID_INFO_CHAR)
|
|
{
|
|
RtlInitUnicodeString(&ObKeyName, pNlsRegUserInfo->sLocale);
|
|
if (NT_SUCCESS(RtlUnicodeStringToInteger(&ObKeyName, 16, &Locale)))
|
|
{
|
|
pNlsRegUserInfo->UserLocaleId = Locale;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Make sure the user locale id was found. Otherwise, set it to
|
|
// the system locale.
|
|
//
|
|
if (pNlsRegUserInfo->UserLocaleId == 0)
|
|
{
|
|
NtQueryDefaultLocale(FALSE, &(pNlsRegUserInfo->UserLocaleId));
|
|
}
|
|
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// BaseSrvNlsCreateSection
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG
|
|
BaseSrvNlsCreateSection(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_CREATE_SECTION_MSG a =
|
|
(PBASE_NLS_CREATE_SECTION_MSG)&m->u.ApiMessageData;
|
|
|
|
UNICODE_STRING ObSecName; // section name
|
|
LARGE_INTEGER Size;
|
|
WCHAR wszFileName[MAX_SMALL_BUF_LEN]; // file name (Actually l2 chars is max: c_nlsXXXXX.nls\0
|
|
WCHAR wszSecName[MAX_SMALL_BUF_LEN]; // section name string
|
|
HANDLE hNewSec = (HANDLE)0; // new section handle
|
|
HANDLE hProcess = (HANDLE)0; // process handle
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
NTSTATUS rc = 0L; // return code
|
|
LPWSTR pFile = NULL;
|
|
HANDLE hFile = (HANDLE)0; // file handle
|
|
ANSI_STRING proc;
|
|
PVOID pTemp; // temp pointer
|
|
BYTE pSecurityDescriptor[MAX_SMALL_SECURITY_DESCRIPTOR]; // Buffer for our security descriptor
|
|
|
|
RTL_VERIFY(NT_SUCCESS(rc = BaseSrvDelayLoadKernel32()));
|
|
|
|
//
|
|
// Set the handles to null.
|
|
//
|
|
a->hNewSection = NULL;
|
|
|
|
if (a->Locale)
|
|
{
|
|
if (!(*pValidateLocale)(a->Locale))
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
}
|
|
|
|
switch (a->uiType)
|
|
{
|
|
case (NLS_CREATE_SECTION_UNICODE) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_UNICODE);
|
|
pFile = NLS_FILE_UNICODE;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_GEO) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_GEO);
|
|
pFile = NLS_FILE_GEO;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_LOCALE) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_LOCALE);
|
|
pFile = NLS_FILE_LOCALE;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_CTYPE) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_CTYPE);
|
|
pFile = NLS_FILE_CTYPE;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_SORTKEY) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_SORTKEY);
|
|
pFile = NLS_FILE_SORTKEY;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_SORTTBLS) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_SORTTBLS);
|
|
pFile = NLS_FILE_SORTTBLS;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_DEFAULT_OEMCP) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_DEFAULT_SECTION_OEMCP);
|
|
pFile = NLS_DEFAULT_FILE_OEMCP;
|
|
break;
|
|
}
|
|
|
|
|
|
case (NLS_CREATE_SECTION_DEFAULT_ACP) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_DEFAULT_SECTION_ACP);
|
|
pFile = NLS_DEFAULT_FILE_ACP;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_SECTION_LANG_EXCEPT) :
|
|
{
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_EXCEPT);
|
|
pFile = NLS_FILE_LANG_EXCEPT;
|
|
break;
|
|
}
|
|
|
|
case (NLS_CREATE_CODEPAGE_SECTION) :
|
|
{
|
|
// Get the Code Page file name from registry
|
|
ASSERT(pGetCPFileNameFromRegistry);
|
|
if ( FALSE == (*pGetCPFileNameFromRegistry)( a->Locale,
|
|
wszFileName,
|
|
MAX_SMALL_BUF_LEN ) )
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
// Remember we're using this file name
|
|
pFile = wszFileName;
|
|
|
|
// Hmm, we'll need the section name for this section.
|
|
// Note that this had better be in sync with what we see
|
|
// in winnls\tables.c or else the server will be called needlessly.
|
|
ASSERT(pGetNlsSectionName != NULL);
|
|
if (!NT_SUCCESS((*pGetNlsSectionName)( a->Locale,
|
|
10,
|
|
0,
|
|
NLS_SECTION_CPPREFIX,
|
|
wszSecName,
|
|
MAX_SMALL_BUF_LEN)))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
// Make it a string we can remember/use later
|
|
RtlInitUnicodeString(&ObSecName, wszSecName);
|
|
|
|
break;
|
|
}
|
|
case ( NLS_CREATE_SORT_SECTION ) :
|
|
{
|
|
if (a->Locale == 0)
|
|
{
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
ASSERT(pGetNlsSectionName != NULL);
|
|
if (rc = (*pGetNlsSectionName)( a->Locale,
|
|
16,
|
|
8,
|
|
NLS_SECTION_SORTKEY,
|
|
wszSecName,
|
|
MAX_SMALL_BUF_LEN))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
ASSERT(pGetDefaultSortkeySize != NULL);
|
|
(*pGetDefaultSortkeySize)(&Size);
|
|
RtlInitUnicodeString(&ObSecName, wszSecName);
|
|
|
|
break;
|
|
}
|
|
case ( NLS_CREATE_LANG_EXCEPTION_SECTION ) :
|
|
{
|
|
if (a->Locale == 0)
|
|
{
|
|
//
|
|
// Creating the default section.
|
|
//
|
|
RtlInitUnicodeString(&ObSecName, NLS_SECTION_LANG_INTL);
|
|
}
|
|
else
|
|
{
|
|
ASSERT(pGetNlsSectionName != NULL);
|
|
if (rc = (*pGetNlsSectionName)( a->Locale,
|
|
16,
|
|
8,
|
|
NLS_SECTION_LANGPREFIX,
|
|
wszSecName,
|
|
MAX_SMALL_BUF_LEN))
|
|
{
|
|
return (rc);
|
|
}
|
|
RtlInitUnicodeString(&ObSecName, wszSecName);
|
|
}
|
|
|
|
(*pGetLinguistLangSize)(&Size);
|
|
break;
|
|
}
|
|
default:
|
|
return (STATUS_INVALID_PARAMETER);
|
|
}
|
|
|
|
if (pFile)
|
|
{
|
|
//
|
|
// Open the data file.
|
|
//
|
|
ASSERT(pOpenDataFile != NULL);
|
|
if (rc = (*pOpenDataFile)( &hFile,
|
|
pFile ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Create the NEW Section for Read and Write access.
|
|
// Add a ReadOnly security descriptor so that only the
|
|
// initial creating process may write to the section.
|
|
//
|
|
ASSERT(pCreateNlsSecurityDescriptor);
|
|
rc = (*pCreateNlsSecurityDescriptor)( (PSECURITY_DESCRIPTOR)pSecurityDescriptor,
|
|
MAX_SMALL_SECURITY_DESCRIPTOR,
|
|
GENERIC_READ);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
if (hFile)
|
|
NtClose(hFile);
|
|
return (rc);
|
|
}
|
|
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObSecName,
|
|
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
|
|
NULL,
|
|
pSecurityDescriptor );
|
|
|
|
rc = NtCreateSection( &hNewSec,
|
|
hFile ? SECTION_MAP_READ : SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
&ObjA,
|
|
hFile? NULL:&Size,
|
|
hFile ? PAGE_READONLY:PAGE_READWRITE,
|
|
SEC_COMMIT,
|
|
hFile );
|
|
|
|
NtClose(hFile);
|
|
|
|
//
|
|
// Check for error from NtCreateSection.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
// KdPrint(("NLSAPI (BaseSrv): Could NOT Create Section %wZ - %lx.\n", &ObSecName, rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Duplicate the new section handle for the client.
|
|
// The client will map a view of the section and fill in the data.
|
|
//
|
|
InitializeObjectAttributes( &ObjA,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
|
|
rc = NtOpenProcess( &hProcess,
|
|
PROCESS_DUP_HANDLE,
|
|
&ObjA,
|
|
&m->h.ClientId );
|
|
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Open Process - %lx.\n", rc));
|
|
NtClose(hNewSec);
|
|
return (rc);
|
|
}
|
|
|
|
rc = NtDuplicateObject( NtCurrentProcess(),
|
|
hNewSec,
|
|
hProcess,
|
|
&(a->hNewSection),
|
|
0L,
|
|
0L,
|
|
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE );
|
|
|
|
//
|
|
// Close the process handle we opened.
|
|
//
|
|
NtClose(hProcess);
|
|
return (rc);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetThreadAuthenticationId
|
|
//
|
|
// Retreives the authentication id of the security context of the
|
|
// currently executing thread.
|
|
//
|
|
// 12-22-98 SamerA Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
NTSTATUS GetThreadAuthenticationId(
|
|
PLUID Luid)
|
|
{
|
|
HANDLE TokenHandle;
|
|
TOKEN_STATISTICS TokenInformation;
|
|
ULONG BytesRequired;
|
|
NTSTATUS NtStatus;
|
|
|
|
|
|
NtStatus = NtOpenThreadToken( NtCurrentThread(),
|
|
TOKEN_QUERY,
|
|
FALSE,
|
|
&TokenHandle );
|
|
|
|
if (!NT_SUCCESS(NtStatus))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv) : No thread token in BaseSrvNlsLogon - %lx\n", NtStatus));
|
|
return (NtStatus);
|
|
}
|
|
|
|
//
|
|
// Get the LUID.
|
|
//
|
|
NtStatus = NtQueryInformationToken(
|
|
TokenHandle,
|
|
TokenStatistics,
|
|
&TokenInformation,
|
|
sizeof(TokenInformation),
|
|
&BytesRequired );
|
|
|
|
if (NT_SUCCESS( NtStatus ))
|
|
{
|
|
RtlCopyLuid(Luid, &TokenInformation.AuthenticationId);
|
|
}
|
|
else
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv) : Couldn't Query Information for Token %lx. NtStatus = %lx\n", TokenHandle, NtStatus));
|
|
}
|
|
|
|
NtClose(TokenHandle);
|
|
|
|
return (NtStatus);
|
|
}
|