1034 lines
29 KiB
C
1034 lines
29 KiB
C
/*++
|
|
|
|
Copyright (c) 1990 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
srvnls.c
|
|
|
|
Abstract:
|
|
|
|
This file contains the NLS Server-Side routines.
|
|
|
|
Author:
|
|
|
|
Julie Bennett (JulieB) 02-Dec-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
|
|
|
|
#include "basesrv.h"
|
|
|
|
|
|
|
|
|
|
/*
|
|
* Constant Declarations.
|
|
*/
|
|
#define MAX_PATH_LEN 512 /* max length of path name */
|
|
|
|
#define MAX_KEY_VALUE_PARTINFO \
|
|
( FIELD_OFFSET( KEY_VALUE_PARTIAL_INFORMATION, Data ) + MAX_REG_VAL_SIZE )
|
|
|
|
|
|
#define NLS_VALUE_STIMEFORMAT L"sTimeFormat"
|
|
#define NLS_VALUE_STIME L"sTime"
|
|
#define NLS_VALUE_ITIME L"iTime"
|
|
#define NLS_VALUE_ITLZERO L"iTLZero"
|
|
#define NLS_VALUE_ITIMEMARKPOSN L"iTimePrefix"
|
|
#define NLS_VALUE_SSHORTDATE L"sShortDate"
|
|
#define NLS_VALUE_SDATE L"sDate"
|
|
#define NLS_VALUE_IDATE L"iDate"
|
|
|
|
|
|
|
|
/*
|
|
* 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"sDecimal",
|
|
L"sThousand",
|
|
L"sGrouping",
|
|
L"iDigits",
|
|
L"iLZero",
|
|
L"iNegNumber",
|
|
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"sLongDate",
|
|
L"iCalendarType",
|
|
L"iFirstDayOfWeek",
|
|
L"iFirstWeekOfYear",
|
|
L"Locale"
|
|
};
|
|
|
|
int NumCPanelRegValues = ( sizeof(pCPanelRegValues) / sizeof(LPWSTR) );
|
|
|
|
|
|
|
|
/*
|
|
* Global Variables.
|
|
*/
|
|
HANDLE hNlsCacheMutant;
|
|
HANDLE hCPanelIntlKeyRead = NULL;
|
|
HANDLE hCPanelIntlKeyWrite = NULL;
|
|
PNLS_USER_INFO pNlsRegUserInfo = NULL;
|
|
ULONG NlsChangeBuffer;
|
|
IO_STATUS_BLOCK IoStatusBlock;
|
|
|
|
|
|
|
|
/*
|
|
* Forward Declarations.
|
|
*/
|
|
ULONG
|
|
NlsSetRegAndCache(
|
|
LPWSTR pValue,
|
|
LPWSTR pCacheString,
|
|
LPWSTR pData,
|
|
ULONG DataLength);
|
|
|
|
VOID
|
|
NlsUpdateCacheInfo(VOID);
|
|
|
|
ULONG
|
|
CreateSecurityDescriptor(
|
|
ULONG *pSecurityDescriptor,
|
|
PSID *ppWorldSid,
|
|
ACCESS_MASK AccessMask);
|
|
|
|
|
|
|
|
|
|
/***************************************************************************\
|
|
* BaseSrvNLSInit
|
|
*
|
|
* This routine creates the shared heap for the nls information.
|
|
*
|
|
* 08-19-94 JulieB Created.
|
|
\***************************************************************************/
|
|
|
|
NTSTATUS
|
|
BaseSrvNLSInit(
|
|
PBASE_STATIC_SERVER_DATA pStaticServerData)
|
|
{
|
|
ULONG rc; /* return code */
|
|
|
|
|
|
/*
|
|
* Create a mutant to protect the cache.
|
|
*/
|
|
rc = NtCreateMutant( &hNlsCacheMutant,
|
|
MUTANT_ALL_ACCESS,
|
|
NULL,
|
|
FALSE );
|
|
if (!NT_SUCCESS( rc ))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Create Cache Mutex - %lx.\n", rc));
|
|
return ( rc );
|
|
}
|
|
|
|
/*
|
|
* Initialize the cache to zero.
|
|
*/
|
|
pNlsRegUserInfo = &(pStaticServerData->NlsUserInfo);
|
|
RtlZeroMemory( pNlsRegUserInfo, sizeof(NLS_USER_INFO) );
|
|
|
|
/*
|
|
* 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)
|
|
{
|
|
/*
|
|
* Duplicate the mutant handle.
|
|
*/
|
|
return ( NtDuplicateObject(NtCurrentProcess(),
|
|
hNlsCacheMutant,
|
|
Process->ProcessHandle,
|
|
(PHANDLE)pConnectionInfo,
|
|
SYNCHRONIZE,
|
|
0L,
|
|
0L ) );
|
|
}
|
|
|
|
/***************************************************************************\
|
|
* BaseSrvNlsLogon
|
|
*
|
|
* This routine initializes the heap for the nls information. If fLogon is
|
|
* TRUE, then it opens 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 hUserHandle; /* HKEY_CURRENT_USER equivalent */
|
|
HANDLE hKeyHandle;
|
|
OBJECT_ATTRIBUTES ObjA; /* object attributes structure */
|
|
UNICODE_STRING ObKeyName; /* key name */
|
|
ULONG rc = 0L; /* return code */
|
|
|
|
|
|
if (fLogon)
|
|
{
|
|
/*
|
|
* 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( &hCPanelIntlKeyRead,
|
|
KEY_READ | KEY_NOTIFY,
|
|
&ObjA );
|
|
|
|
/*
|
|
* Open key for WRITE access.
|
|
*/
|
|
if (!NT_SUCCESS( NtOpenKey( &hCPanelIntlKeyWrite,
|
|
KEY_WRITE,
|
|
&ObjA ) ))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Open Registry Key %wZ for Write - %lx.\n",
|
|
&ObKeyName, rc));
|
|
hCPanelIntlKeyWrite = NULL;
|
|
}
|
|
|
|
/*
|
|
* 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));
|
|
hCPanelIntlKeyRead = NULL;
|
|
|
|
if (hCPanelIntlKeyWrite != NULL)
|
|
{
|
|
NtClose( hCPanelIntlKeyWrite );
|
|
hCPanelIntlKeyWrite = NULL;
|
|
}
|
|
return ( rc );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
* Logging OFF.
|
|
* - close keys
|
|
* - zero out info
|
|
*/
|
|
if (hCPanelIntlKeyRead != NULL)
|
|
{
|
|
NtClose( hCPanelIntlKeyRead );
|
|
hCPanelIntlKeyRead = NULL;
|
|
}
|
|
|
|
if (hCPanelIntlKeyWrite != NULL)
|
|
{
|
|
NtClose( hCPanelIntlKeyWrite );
|
|
hCPanelIntlKeyWrite = NULL;
|
|
}
|
|
|
|
/*
|
|
* Get the cache mutant.
|
|
*/
|
|
NtWaitForSingleObject( hNlsCacheMutant, FALSE, NULL );
|
|
|
|
/*
|
|
* Set the cache to be invalid.
|
|
*/
|
|
pNlsRegUserInfo->fCacheValid = FALSE;
|
|
|
|
/*
|
|
* Zero out info.
|
|
*/
|
|
RtlZeroMemory(pNlsRegUserInfo, sizeof(NLS_USER_INFO));
|
|
|
|
/*
|
|
* Make the system locale the user locale.
|
|
*/
|
|
NtQueryDefaultLocale( FALSE, &(pNlsRegUserInfo->UserLocaleId) );
|
|
|
|
/*
|
|
* Release the cache mutant.
|
|
*/
|
|
NtReleaseMutant( hNlsCacheMutant, NULL );
|
|
}
|
|
|
|
/*
|
|
* 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 != NULL)
|
|
{
|
|
/*
|
|
* Update the cache information.
|
|
*/
|
|
NlsUpdateCacheInfo();
|
|
|
|
/*
|
|
* 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 != NULL)
|
|
{
|
|
/*
|
|
* 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 );
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* 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 */
|
|
|
|
|
|
/*
|
|
* Get the cache mutant.
|
|
*/
|
|
NtWaitForSingleObject( hNlsCacheMutant, FALSE, NULL );
|
|
|
|
/*
|
|
* Set the value in the registry and update the cache.
|
|
*/
|
|
rc = NlsSetRegAndCache( a->pValue,
|
|
a->pCacheString,
|
|
a->pData,
|
|
a->DataLength );
|
|
|
|
/*
|
|
* Release the cache mutant.
|
|
*/
|
|
NtReleaseMutant( hNlsCacheMutant, NULL );
|
|
|
|
/*
|
|
* 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;
|
|
|
|
ULONG rc = 0L; /* return code */
|
|
|
|
|
|
/*
|
|
* Get the cache mutant.
|
|
*/
|
|
NtWaitForSingleObject( hNlsCacheMutant, FALSE, NULL );
|
|
|
|
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;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Release the cache mutant.
|
|
*/
|
|
NtReleaseMutant( hNlsCacheMutant, NULL );
|
|
|
|
/*
|
|
* Return the result.
|
|
*/
|
|
return (rc);
|
|
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* NlsUpdateCacheInfo
|
|
*
|
|
* This routine updates the NLS cache when a registry notification occurs.
|
|
*
|
|
* 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;
|
|
|
|
|
|
/*
|
|
* Get the cache mutant.
|
|
*/
|
|
NtWaitForSingleObject( hNlsCacheMutant, FALSE, NULL );
|
|
|
|
/*
|
|
* 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 ))
|
|
{
|
|
((LPBYTE)pValuePart)[ResultLength] = UNICODE_NULL;
|
|
wcscpy(pTmp, (LPWSTR)(pValuePart->Data));
|
|
}
|
|
else
|
|
{
|
|
*pTmp = NLS_INVALID_INFO_CHAR;
|
|
*(pTmp + 1) = UNICODE_NULL;
|
|
}
|
|
|
|
/*
|
|
* Increment pointer to cache structure.
|
|
*/
|
|
pTmp += MAX_REG_VAL_SIZE;
|
|
}
|
|
|
|
/*
|
|
* 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) );
|
|
}
|
|
|
|
/*
|
|
* Set the cache to be valid.
|
|
*/
|
|
pNlsRegUserInfo->fCacheValid = TRUE;
|
|
|
|
/*
|
|
* Release the cache mutant.
|
|
*/
|
|
NtReleaseMutant( hNlsCacheMutant, NULL );
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* BaseSrvNlsCreateSortSection
|
|
*
|
|
* This routine creates a named memory mapped section with the given
|
|
* section name, and has both READ and WRITE access. The size of the
|
|
* section should be the same as the default section - NLSSECTION_SORTKEY.
|
|
*
|
|
* 12-02-92 JulieB Created.
|
|
\***************************************************************************/
|
|
|
|
ULONG
|
|
BaseSrvNlsCreateSortSection(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_CREATE_SORT_SECTION_MSG a =
|
|
(PBASE_NLS_CREATE_SORT_SECTION_MSG)&m->u.ApiMessageData;
|
|
|
|
HANDLE hNewSec = (HANDLE)0; /* new section handle */
|
|
HANDLE hProcess = (HANDLE)0; /* process handle */
|
|
OBJECT_ATTRIBUTES ObjA; /* object attributes structure */
|
|
NTSTATUS rc = 0L; /* return code */
|
|
ULONG pSecurityDescriptor[MAX_PATH_LEN]; /* security descriptor buffer */
|
|
PSID pWorldSid; /* ptr to world SID */
|
|
|
|
|
|
/*
|
|
* Set the handles to null.
|
|
*/
|
|
a->hNewSection = NULL;
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
if (rc = CreateSecurityDescriptor(pSecurityDescriptor,
|
|
&pWorldSid,
|
|
GENERIC_READ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
InitializeObjectAttributes(&ObjA,
|
|
&(a->SectionName),
|
|
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
pSecurityDescriptor);
|
|
|
|
rc = NtCreateSection(&hNewSec,
|
|
SECTION_MAP_READ | SECTION_MAP_WRITE,
|
|
&ObjA,
|
|
&(a->SectionSize),
|
|
PAGE_READWRITE,
|
|
SEC_COMMIT,
|
|
NULL);
|
|
|
|
/*
|
|
* Check for error from NtCreateSection.
|
|
*/
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
/*
|
|
* If the name has already been created, ignore the error.
|
|
*/
|
|
if (rc != STATUS_OBJECT_NAME_COLLISION)
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Create Section %wZ - %lx.\n",
|
|
&(a->SectionName), 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));
|
|
return (rc);
|
|
}
|
|
|
|
rc = NtDuplicateObject(NtCurrentProcess(),
|
|
hNewSec,
|
|
hProcess,
|
|
&(a->hNewSection),
|
|
0L,
|
|
0L,
|
|
DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
|
|
|
|
/*
|
|
* Return the return value from NtDuplicateObject.
|
|
*/
|
|
return (rc);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* BaseSrvNlsPreserveSection
|
|
*
|
|
* This routine preserves a created section by duplicating the handle
|
|
* into CSR and never closing it.
|
|
*
|
|
* 03-12-93 JulieB Created.
|
|
\***************************************************************************/
|
|
|
|
ULONG
|
|
BaseSrvNlsPreserveSection(
|
|
IN OUT PCSR_API_MSG m,
|
|
IN OUT PCSR_REPLY_STATUS ReplyStatus)
|
|
{
|
|
PBASE_NLS_PRESERVE_SECTION_MSG a =
|
|
(PBASE_NLS_PRESERVE_SECTION_MSG)&m->u.ApiMessageData;
|
|
|
|
HANDLE hSection = (HANDLE)0; /* section handle */
|
|
HANDLE hProcess = (HANDLE)0; /* process handle */
|
|
OBJECT_ATTRIBUTES ObjA; /* object attributes structure */
|
|
NTSTATUS rc = 0L; /* return code */
|
|
|
|
|
|
/*
|
|
* Duplicate the section handle for the server.
|
|
*/
|
|
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));
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* The hSection value will not be used for anything. However,
|
|
* it must remain open so that the object remains permanent.
|
|
*/
|
|
rc = NtDuplicateObject(hProcess,
|
|
a->hSection,
|
|
NtCurrentProcess(),
|
|
&hSection,
|
|
0L,
|
|
0L,
|
|
DUPLICATE_SAME_ACCESS);
|
|
|
|
/*
|
|
* Return the return value from NtDuplicateObject.
|
|
*/
|
|
return (rc);
|
|
|
|
ReplyStatus; // get rid of unreferenced parameter warning message
|
|
}
|
|
|
|
|
|
/***************************************************************************\
|
|
* CreateSecurityDescriptor
|
|
*
|
|
* This routine creates the security descriptor needed to create the
|
|
* memory mapped section for a data file and returns the world SID.
|
|
*
|
|
* 12-02-92 JulieB Created.
|
|
\***************************************************************************/
|
|
|
|
ULONG CreateSecurityDescriptor(
|
|
ULONG *pSecurityDescriptor,
|
|
PSID *ppWorldSid,
|
|
ACCESS_MASK AccessMask)
|
|
{
|
|
ULONG rc = 0L; /* return code */
|
|
PACL pAclBuffer; /* ptr to ACL buffer */
|
|
ULONG SidLength; /* length of SID - 1 sub authority */
|
|
PSID pWSid; /* ptr to world SID */
|
|
SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_WORLD_SID_AUTHORITY;
|
|
|
|
|
|
/*
|
|
* Create World SID.
|
|
*/
|
|
SidLength = RtlLengthRequiredSid(1);
|
|
|
|
if ((pWSid = (PSID)RtlAllocateHeap(RtlProcessHeap(),
|
|
MAKE_TAG( TMP_TAG ) | HEAP_ZERO_MEMORY,
|
|
SidLength)) == NULL)
|
|
{
|
|
*ppWorldSid = NULL;
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Allocate SID Buffer.\n"));
|
|
return (ERROR_OUTOFMEMORY);
|
|
}
|
|
*ppWorldSid = pWSid;
|
|
|
|
RtlInitializeSid(pWSid, &SidAuth, 1);
|
|
|
|
*(RtlSubAuthoritySid(pWSid, 0)) = SECURITY_WORLD_RID;
|
|
|
|
/*
|
|
* Initialize Security Descriptor.
|
|
*/
|
|
rc = RtlCreateSecurityDescriptor(pSecurityDescriptor,
|
|
SECURITY_DESCRIPTOR_REVISION);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Create Security Descriptor - %lx.\n",
|
|
rc));
|
|
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pWSid);
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* Initialize ACL.
|
|
*/
|
|
pAclBuffer = (PACL)((PBYTE)pSecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH);
|
|
rc = RtlCreateAcl((PACL)pAclBuffer,
|
|
MAX_PATH_LEN * sizeof(ULONG),
|
|
ACL_REVISION2);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Create ACL - %lx.\n", rc));
|
|
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pWSid);
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* Add an ACE to the ACL that allows World GENERIC_READ to the
|
|
* section object.
|
|
*/
|
|
rc = RtlAddAccessAllowedAce((PACL)pAclBuffer,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
pWSid);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Add Access Allowed ACE - %lx.\n",
|
|
rc));
|
|
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pWSid);
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* Assign the DACL to the security descriptor.
|
|
*/
|
|
rc = RtlSetDaclSecurityDescriptor((PSECURITY_DESCRIPTOR)pSecurityDescriptor,
|
|
(BOOLEAN)TRUE,
|
|
(PACL)pAclBuffer,
|
|
(BOOLEAN)FALSE);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI (BaseSrv): Could NOT Set DACL Security Descriptor - %lx.\n",
|
|
rc));
|
|
RtlFreeHeap(RtlProcessHeap(), 0, (PVOID)pWSid);
|
|
return (rc);
|
|
}
|
|
|
|
/*
|
|
* Return success.
|
|
*/
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
|