1670 lines
48 KiB
C
1670 lines
48 KiB
C
/*++
|
|
|
|
Copyright (c) 1991-1996, Microsoft Corporation All rights reserved.
|
|
|
|
Module Name:
|
|
|
|
section.c
|
|
|
|
Abstract:
|
|
|
|
This file contains functions that deal with creating, opening, or
|
|
mapping a section for data table files for the NLS API.
|
|
|
|
External Routines found in this file:
|
|
CreateNlsObjectDirectory
|
|
OpenRegKey
|
|
QueryRegValue
|
|
CreateSectionFromReg
|
|
CreateSectionOneValue
|
|
CreateSection
|
|
CreateSectionTemp
|
|
OpenSection
|
|
MapSection
|
|
UnMapSection
|
|
GetNlsSectionName
|
|
GetScriptMemberWeights
|
|
|
|
Revision History:
|
|
|
|
05-31-91 JulieB Created.
|
|
|
|
--*/
|
|
|
|
|
|
|
|
//
|
|
// Include Files.
|
|
//
|
|
|
|
#include "nls.h"
|
|
|
|
|
|
|
|
|
|
//
|
|
// Forward Declarations.
|
|
//
|
|
|
|
ULONG
|
|
OpenDataFile(
|
|
HANDLE *phFile,
|
|
LPWSTR pFile);
|
|
|
|
ULONG
|
|
GetNTFileName(
|
|
LPWSTR pFile,
|
|
PUNICODE_STRING pFileName);
|
|
|
|
ULONG
|
|
CreateSecurityDescriptor(
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
PSID *ppWorldSid,
|
|
ACCESS_MASK AccessMask);
|
|
|
|
ULONG
|
|
AppendAccessAllowedACE(
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
ACCESS_MASK AccessMask);
|
|
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// INTERNAL MACROS //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_REG_BUFFER_ALLOC
|
|
//
|
|
// Allocates the buffer used by the registry enumeration and query calls
|
|
// and sets the pKeyValueFull variable to point at the newly created buffer.
|
|
//
|
|
// NOTE: This macro may return if an error is encountered.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_REG_BUFFER_ALLOC( pKeyValueFull, \
|
|
BufSize, \
|
|
pBuffer, \
|
|
CritSect ) \
|
|
{ \
|
|
if ((pBuffer = (PVOID)NLS_ALLOC_MEM(BufSize)) == NULL) \
|
|
{ \
|
|
KdPrint(("NLSAPI: Could NOT Allocate Memory.\n")); \
|
|
if (CritSect) \
|
|
{ \
|
|
RtlLeaveCriticalSection(&gcsTblPtrs); \
|
|
} \
|
|
return ((ULONG)STATUS_NO_MEMORY); \
|
|
} \
|
|
\
|
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pBuffer; \
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_REG_BUFFER_FREE
|
|
//
|
|
// Frees the buffer used by the registry enumeration and query calls.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_REG_BUFFER_FREE(pBuffer) (NLS_FREE_MEM(pBuffer))
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// NLS_INTEGER_TO_UNICODE_STR
|
|
//
|
|
// Converts an integer value to a unicode string and stores it in the
|
|
// buffer provided.
|
|
//
|
|
// NOTE: This macro may return if an error is encountered.
|
|
//
|
|
// DEFINED AS A MACRO.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define NLS_INTEGER_TO_UNICODE_STR( Value, \
|
|
Base, \
|
|
Padding, \
|
|
pResultBuf, \
|
|
Size ) \
|
|
{ \
|
|
UNICODE_STRING ObString; /* value string */ \
|
|
WCHAR pBuffer[Size]; /* ptr to buffer */ \
|
|
UINT LpCtr; /* loop counter */ \
|
|
ULONG rc = 0L; /* return code */ \
|
|
LPWSTR pBufPtr; /* ptr to result buffer */ \
|
|
\
|
|
\
|
|
/* \
|
|
* Set up unicode string structure. \
|
|
*/ \
|
|
ObString.Length = Size * 2; \
|
|
ObString.MaximumLength = Size * 2; \
|
|
ObString.Buffer = pBuffer; \
|
|
\
|
|
/* \
|
|
* Get the value as a string. \
|
|
*/ \
|
|
if (rc = RtlIntegerToUnicodeString(Value, Base, &ObString)) \
|
|
{ \
|
|
return (rc); \
|
|
} \
|
|
\
|
|
/* \
|
|
* Pad the string with the appropriate number of zeros. \
|
|
*/ \
|
|
pBufPtr = pResultBuf; \
|
|
for (LpCtr = GET_WC_COUNT(ObString.Length); \
|
|
LpCtr < Padding; \
|
|
LpCtr++, pBufPtr++) \
|
|
{ \
|
|
*pBufPtr = (WCHAR)'0'; \
|
|
} \
|
|
NlsStrCpyW(pBufPtr, ObString.Buffer); \
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// EXTERNAL ROUTINES //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateNlsObjectDirectory
|
|
//
|
|
// This routine creates the object directory for the NLS memory mapped
|
|
// sections.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CreateNlsObjectDirectory()
|
|
{
|
|
ULONG pSecurityDescriptor[MAX_PATH_LEN]; // security descriptor buffer
|
|
PSID pWorldSid; // ptr to world SID
|
|
UNICODE_STRING ObDirName; // directory name
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
HANDLE hDirHandle; // directory handle
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Create the security descriptor.
|
|
//
|
|
if (rc = CreateSecurityDescriptor( pSecurityDescriptor,
|
|
&pWorldSid,
|
|
DIRECTORY_TRAVERSE |
|
|
DIRECTORY_CREATE_OBJECT ))
|
|
{
|
|
NLS_FREE_MEM(pWorldSid);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Add Admin Access for Query.
|
|
//
|
|
if (rc = AppendAccessAllowedACE( pSecurityDescriptor,
|
|
DIRECTORY_QUERY |
|
|
DIRECTORY_TRAVERSE |
|
|
DIRECTORY_CREATE_OBJECT ))
|
|
{
|
|
NLS_FREE_MEM(pWorldSid);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Create the object directory.
|
|
//
|
|
RtlInitUnicodeString(&ObDirName, NLS_OBJECT_DIRECTORY_NAME);
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObDirName,
|
|
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
pSecurityDescriptor );
|
|
|
|
rc = NtCreateDirectoryObject( &hDirHandle,
|
|
DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT,
|
|
&ObjA );
|
|
|
|
//
|
|
// Free the memory used for the SID and close the directory handle.
|
|
//
|
|
NLS_FREE_MEM(pWorldSid);
|
|
NtClose(hDirHandle);
|
|
|
|
//
|
|
// Check for error from NtCreateDirectoryObject.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Create Object Directory %wZ - %lx.\n",
|
|
&ObDirName, rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OpenRegKey
|
|
//
|
|
// This routine opens a key in the registry.
|
|
//
|
|
// 08-02-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG OpenRegKey(
|
|
PHANDLE phKeyHandle,
|
|
LPWSTR pBaseName,
|
|
LPWSTR pKey,
|
|
ULONG fAccess)
|
|
{
|
|
WCHAR pwszKeyName[MAX_PATH_LEN]; // ptr to the full key name
|
|
HANDLE UserKeyHandle; // HKEY_CURRENT_USER equivalent
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
UNICODE_STRING ObKeyName; // key name
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Get the full key name.
|
|
//
|
|
if (pBaseName == NULL)
|
|
{
|
|
//
|
|
// Get current user's key handle.
|
|
//
|
|
rc = RtlOpenCurrentUser(MAXIMUM_ALLOWED, &UserKeyHandle);
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Open HKEY_CURRENT_USER - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
pwszKeyName[ 0 ] = UNICODE_NULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Base name exists, so not current user.
|
|
//
|
|
UserKeyHandle = NULL;
|
|
NlsStrCpyW(pwszKeyName, pBaseName);
|
|
}
|
|
NlsStrCatW(pwszKeyName, pKey);
|
|
|
|
//
|
|
// Open the registry key.
|
|
//
|
|
RtlInitUnicodeString(&ObKeyName, pwszKeyName);
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
UserKeyHandle,
|
|
NULL );
|
|
rc = NtOpenKey( phKeyHandle,
|
|
fAccess,
|
|
&ObjA );
|
|
|
|
//
|
|
// Close the current user handle, if necessary.
|
|
//
|
|
if (UserKeyHandle != NULL)
|
|
{
|
|
NtClose(UserKeyHandle);
|
|
}
|
|
|
|
//
|
|
// Check for error from NtOpenKey.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Open Registry Key %wZ - %lx.\n",
|
|
&ObKeyName, rc));
|
|
*phKeyHandle = NULL;
|
|
}
|
|
|
|
//
|
|
// Return the status from NtOpenKey.
|
|
//
|
|
return (rc);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// QueryRegValue
|
|
//
|
|
// This routine queries the given value from the registry.
|
|
//
|
|
// NOTE: If pIfAlloc is NULL, then no buffer will be allocated.
|
|
// If this routine is successful, the CALLER must free the
|
|
// ppKeyValueFull information buffer if *pIfAlloc is TRUE.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG QueryRegValue(
|
|
HANDLE hKeyHandle,
|
|
LPWSTR pValue,
|
|
PKEY_VALUE_FULL_INFORMATION *ppKeyValueFull,
|
|
ULONG Length,
|
|
LPBOOL pIfAlloc)
|
|
{
|
|
UNICODE_STRING ObValueName; // value name
|
|
PVOID pBuffer; // ptr to buffer for enum
|
|
ULONG ResultLength; // # bytes written
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Set contents of pIfAlloc to FALSE to show that we did NOT do a
|
|
// memory allocation (yet).
|
|
//
|
|
if (pIfAlloc)
|
|
{
|
|
*pIfAlloc = FALSE;
|
|
}
|
|
|
|
//
|
|
// Query the value from the registry.
|
|
//
|
|
RtlInitUnicodeString(&ObValueName, pValue);
|
|
|
|
RtlZeroMemory(*ppKeyValueFull, Length);
|
|
rc = NtQueryValueKey( hKeyHandle,
|
|
&ObValueName,
|
|
KeyValueFullInformation,
|
|
*ppKeyValueFull,
|
|
Length,
|
|
&ResultLength );
|
|
|
|
//
|
|
// Check the error code. If the buffer is too small, allocate
|
|
// a new one and try the query again.
|
|
//
|
|
if ((rc == STATUS_BUFFER_OVERFLOW) && (pIfAlloc))
|
|
{
|
|
//
|
|
// Buffer is too small, so allocate a new one.
|
|
//
|
|
NLS_REG_BUFFER_ALLOC(*ppKeyValueFull, ResultLength, pBuffer, FALSE);
|
|
RtlZeroMemory(*ppKeyValueFull, ResultLength);
|
|
rc = NtQueryValueKey( hKeyHandle,
|
|
&ObValueName,
|
|
KeyValueFullInformation,
|
|
*ppKeyValueFull,
|
|
ResultLength,
|
|
&ResultLength );
|
|
|
|
//
|
|
// Set contents of pIfAlloc to TRUE to show that we DID do
|
|
// a memory allocation.
|
|
//
|
|
*pIfAlloc = TRUE;
|
|
}
|
|
|
|
//
|
|
// If there is an error at this point, then the query failed.
|
|
//
|
|
if (rc != NO_ERROR)
|
|
{
|
|
if ((pIfAlloc) && (*pIfAlloc))
|
|
{
|
|
NLS_REG_BUFFER_FREE(pBuffer);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateSectionFromReg
|
|
//
|
|
// This routine creates a named memory mapped section for the given full
|
|
// information for the key value and returns the handle to the section.
|
|
// The section name and the data file name are retrieved and formed from
|
|
// information given in the key_value_full_information structure.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CreateSectionFromReg(
|
|
HANDLE *phSec,
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull,
|
|
LPWSTR pwszNlsPrefix)
|
|
{
|
|
HANDLE hFile = (HANDLE)0; // file handle
|
|
ULONG pSecurityDescriptor[MAX_PATH_LEN]; // security descriptor buffer
|
|
PSID pWorldSid; // ptr to world SID
|
|
UNICODE_STRING ObSecName; // section name
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
WCHAR pwszSecName[MAX_PATH_LEN]; // ptr to section name string
|
|
ULONG rc = 0L; // return code
|
|
|
|
BASE_API_MSG m;
|
|
PBASE_NLS_PRESERVE_SECTION_MSG a = &m.u.NlsPreserveSection;
|
|
|
|
|
|
//
|
|
// Make sure we're in the critical section when entering this call.
|
|
//
|
|
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
|
|
//
|
|
// Open the data file.
|
|
//
|
|
if (rc = OpenDataFile( &hFile,
|
|
GET_VALUE_DATA_PTR(pKeyValueFull) ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Create the security descriptor.
|
|
//
|
|
if (rc = CreateSecurityDescriptor( pSecurityDescriptor,
|
|
&pWorldSid,
|
|
GENERIC_READ ))
|
|
{
|
|
NLS_FREE_MEM(pWorldSid);
|
|
NtClose(hFile);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Create the section.
|
|
//
|
|
RtlZeroMemory(pwszSecName, MAX_PATH_LEN);
|
|
NlsStrCpyW(pwszSecName, pwszNlsPrefix);
|
|
NlsStrNCatW( pwszSecName,
|
|
(LPWSTR)pKeyValueFull->Name,
|
|
GET_WC_COUNT(pKeyValueFull->NameLength) );
|
|
|
|
RtlInitUnicodeString(&ObSecName, pwszSecName);
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObSecName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
pSecurityDescriptor );
|
|
|
|
rc = NtCreateSection( phSec,
|
|
SECTION_MAP_READ,
|
|
&ObjA,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
SEC_COMMIT,
|
|
hFile );
|
|
|
|
//
|
|
// Free the memory used for the SID and close the file.
|
|
//
|
|
NLS_FREE_MEM(pWorldSid);
|
|
NtClose(hFile);
|
|
|
|
//
|
|
// 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: Could NOT Create Section %wZ - %lx.\n",
|
|
&ObSecName, rc));
|
|
return (rc);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Call the server to preserve the section handle.
|
|
// Don't bother checking the error return, because the
|
|
// section was successfully created for this process.
|
|
//
|
|
a->hSection = *phSec;
|
|
|
|
CsrClientCallServer( (PCSR_API_MSG)&m,
|
|
NULL,
|
|
CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
|
|
BasepNlsPreserveSection),
|
|
sizeof(*a) );
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateSectionOneValue
|
|
//
|
|
// This routine creates a named memory mapped section for the given
|
|
// value under the given key in the registry.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define MAX_BUF 20
|
|
|
|
ULONG CreateSectionOneValue(
|
|
HANDLE hKeyHandle,
|
|
UINT Value,
|
|
UINT Base,
|
|
UINT Padding,
|
|
LPWSTR pNlsPrefix,
|
|
PVOID *ppBaseAddr)
|
|
{
|
|
WCHAR pTmpBuf[MAX_BUF]; // temp buffer
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info
|
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer
|
|
HANDLE hSec = (HANDLE)0; // section handle
|
|
ULONG rc = 0L; // return code
|
|
BOOL IfAlloc = FALSE; // if buffer was allocated
|
|
|
|
|
|
//
|
|
// Make sure we're in the critical section when entering this call.
|
|
//
|
|
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
|
|
//
|
|
// Convert value to unicode string.
|
|
//
|
|
NLS_INTEGER_TO_UNICODE_STR( Value,
|
|
Base,
|
|
Padding,
|
|
pTmpBuf,
|
|
MAX_BUF );
|
|
|
|
//
|
|
// Query the registry for the value.
|
|
//
|
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
|
if (rc = QueryRegValue( hKeyHandle,
|
|
pTmpBuf,
|
|
&pKeyValueFull,
|
|
MAX_KEY_VALUE_FULLINFO,
|
|
&IfAlloc ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Make sure there is data with this value.
|
|
//
|
|
if (pKeyValueFull->DataLength <= 2)
|
|
{
|
|
if (IfAlloc)
|
|
{
|
|
NLS_FREE_MEM(pKeyValueFull);
|
|
}
|
|
return (1);
|
|
}
|
|
|
|
//
|
|
// Create the section.
|
|
//
|
|
if (rc = CreateSectionFromReg( &hSec,
|
|
pKeyValueFull,
|
|
pNlsPrefix ))
|
|
{
|
|
if (IfAlloc)
|
|
{
|
|
NLS_FREE_MEM(pKeyValueFull);
|
|
}
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Free the buffer used for the query.
|
|
//
|
|
if (IfAlloc)
|
|
{
|
|
NLS_FREE_MEM(pKeyValueFull);
|
|
}
|
|
|
|
//
|
|
// Map a View of the Section.
|
|
//
|
|
if (rc = MapSection( hSec,
|
|
ppBaseAddr,
|
|
PAGE_READONLY,
|
|
TRUE ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateSection
|
|
//
|
|
// This routine creates a named memory mapped section for the given file
|
|
// name and section name and returns the handle to the section.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CreateSection(
|
|
HANDLE *phSec,
|
|
LPWSTR pwszFileName,
|
|
LPWSTR pwszSecName)
|
|
{
|
|
HANDLE hFile = (HANDLE)0; // file handle
|
|
ULONG pSecurityDescriptor[MAX_PATH_LEN]; // security descriptor buffer
|
|
PSID pWorldSid; // ptr to world SID
|
|
UNICODE_STRING ObSecName; // section name
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
ULONG rc = 0L; // return code
|
|
|
|
BASE_API_MSG m;
|
|
PBASE_NLS_PRESERVE_SECTION_MSG a = &m.u.NlsPreserveSection;
|
|
|
|
|
|
//
|
|
// Don't need to be in the critical section here, since the
|
|
// server init routine calls this. All other calls made to
|
|
// this function should ensure that they are in a critical
|
|
// section.
|
|
//
|
|
// ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
//
|
|
|
|
//
|
|
// Open the data file.
|
|
//
|
|
if (rc = OpenDataFile( &hFile,
|
|
pwszFileName ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Create the security descriptor.
|
|
//
|
|
if (rc = CreateSecurityDescriptor( pSecurityDescriptor,
|
|
&pWorldSid,
|
|
GENERIC_READ ))
|
|
{
|
|
NLS_FREE_MEM(pWorldSid);
|
|
NtClose(hFile);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Create the section.
|
|
//
|
|
RtlInitUnicodeString(&ObSecName, pwszSecName);
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObSecName,
|
|
OBJ_OPENIF | OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
pSecurityDescriptor );
|
|
|
|
rc = NtCreateSection( phSec,
|
|
SECTION_MAP_READ,
|
|
&ObjA,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
SEC_COMMIT,
|
|
hFile );
|
|
|
|
//
|
|
// Free the memory used for the SID and close the file.
|
|
//
|
|
NLS_FREE_MEM(pWorldSid);
|
|
NtClose(hFile);
|
|
|
|
//
|
|
// Check for error from NtCreateSection.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Create Section %wZ - %lx.\n",
|
|
&ObSecName, rc));
|
|
return (rc);
|
|
}
|
|
else if (rc != STATUS_OBJECT_NAME_EXISTS)
|
|
{
|
|
//
|
|
// Call the server to preserve the section handle.
|
|
// Don't bother checking the error return, because the
|
|
// section was successfully created for this process.
|
|
//
|
|
a->hSection = *phSec;
|
|
|
|
CsrClientCallServer( (PCSR_API_MSG)&m,
|
|
NULL,
|
|
CSR_MAKE_API_NUMBER(BASESRV_SERVERDLL_INDEX,
|
|
BasepNlsPreserveSection),
|
|
sizeof(*a) );
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateSectionTemp
|
|
//
|
|
// This routine creates a temporary memory mapped section for the given file
|
|
// name and returns the handle to the section.
|
|
//
|
|
// 09-01-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CreateSectionTemp(
|
|
HANDLE *phSec,
|
|
LPWSTR pwszFileName)
|
|
{
|
|
HANDLE hFile = (HANDLE)0; // file handle
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Make sure we're in the critical section when entering this call.
|
|
//
|
|
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
|
|
//
|
|
// Open the data file.
|
|
//
|
|
if (rc = OpenDataFile( &hFile,
|
|
pwszFileName ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Create the section.
|
|
//
|
|
InitializeObjectAttributes( &ObjA,
|
|
NULL,
|
|
0,
|
|
NULL,
|
|
NULL );
|
|
|
|
rc = NtCreateSection( phSec,
|
|
SECTION_MAP_READ,
|
|
&ObjA,
|
|
NULL,
|
|
PAGE_READONLY,
|
|
SEC_COMMIT,
|
|
hFile );
|
|
|
|
//
|
|
// Close the file.
|
|
//
|
|
NtClose(hFile);
|
|
|
|
//
|
|
// Check for error from NtCreateSection.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Create Temp Section for %ws - %lx.\n",
|
|
pwszFileName, rc));
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (rc);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OpenSection
|
|
//
|
|
// This routine opens the named memory mapped section for the given section
|
|
// name and returns the handle to the section.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG OpenSection(
|
|
HANDLE *phSec,
|
|
PUNICODE_STRING pObSectionName,
|
|
PVOID *ppBaseAddr,
|
|
ULONG AccessMask,
|
|
BOOL bCloseHandle)
|
|
{
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Make sure we're in the critical section when entering this call.
|
|
//
|
|
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
|
|
//
|
|
// Open the Section.
|
|
//
|
|
InitializeObjectAttributes( &ObjA,
|
|
pObSectionName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
rc = NtOpenSection( phSec,
|
|
AccessMask,
|
|
&ObjA );
|
|
|
|
//
|
|
// Check for error from NtOpenSection.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Map a View of the Section.
|
|
//
|
|
if (rc = MapSection( *phSec,
|
|
ppBaseAddr,
|
|
PAGE_READONLY,
|
|
FALSE ))
|
|
{
|
|
NtClose(*phSec);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Close the handle to the section. Once the section has been mapped,
|
|
// the pointer to the base address will remain valid until the section
|
|
// is unmapped. It is not necessary to leave the handle to the section
|
|
// around.
|
|
//
|
|
if (bCloseHandle)
|
|
{
|
|
NtClose(*phSec);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// MapSection
|
|
//
|
|
// This routine maps a view of the section to the current process and adds
|
|
// the appropriate information to the hash table.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG MapSection(
|
|
HANDLE hSec,
|
|
PVOID *ppBaseAddr,
|
|
ULONG PageProtection,
|
|
BOOL bCloseHandle)
|
|
{
|
|
ULONG ViewSize; // view size of mapped section
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Make sure we're in the critical section when entering this call.
|
|
//
|
|
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
|
|
//
|
|
// Map a View of the Section.
|
|
//
|
|
*ppBaseAddr = (PVOID)NULL;
|
|
ViewSize = 0L;
|
|
|
|
rc = NtMapViewOfSection( hSec,
|
|
NtCurrentProcess(),
|
|
ppBaseAddr,
|
|
0L,
|
|
0L,
|
|
NULL,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0L,
|
|
PageProtection );
|
|
|
|
//
|
|
// Close the handle to the section. Once the section has been mapped,
|
|
// the pointer to the base address will remain valid until the section
|
|
// is unmapped. It is not necessary to leave the handle to the section
|
|
// around.
|
|
//
|
|
if (bCloseHandle)
|
|
{
|
|
NtClose(hSec);
|
|
}
|
|
|
|
//
|
|
// Check for error from NtMapViewOfSection.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Map View of Section - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UnMapSection
|
|
//
|
|
// This routine unmaps a view of the given section to the current process.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG UnMapSection(
|
|
PVOID pBaseAddr)
|
|
{
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Make sure we're in the critical section when entering this call.
|
|
//
|
|
ASSERT(NtCurrentTeb()->ClientId.UniqueThread == gcsTblPtrs.OwningThread);
|
|
|
|
//
|
|
// UnMap a View of the Section.
|
|
//
|
|
rc = NtUnmapViewOfSection( NtCurrentProcess(),
|
|
pBaseAddr );
|
|
|
|
//
|
|
// Check for error from NtUnmapViewOfSection.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Unmap View of Section - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetNlsSectionName
|
|
//
|
|
// This routine returns a section name by concatenating the given
|
|
// section prefix and the given integer value converted to a string.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG GetNlsSectionName(
|
|
UINT Value,
|
|
UINT Base,
|
|
UINT Padding,
|
|
LPWSTR pwszPrefix,
|
|
LPWSTR pwszSecName)
|
|
{
|
|
//
|
|
// Create section name string.
|
|
//
|
|
NlsStrCpyW(pwszSecName, pwszPrefix);
|
|
NLS_INTEGER_TO_UNICODE_STR( Value,
|
|
Base,
|
|
Padding,
|
|
pwszSecName + NlsStrLenW(pwszSecName),
|
|
MAX_PATH_LEN );
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetScriptMemberWeights
|
|
//
|
|
// Gets the script member sorting order from the registry. If the order
|
|
// is different from the default order, it then sets the SMWeight array
|
|
// in the table pointers structure to the correct values and sets the
|
|
// IfModify_SMWeight flag to TRUE.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG GetScriptMemberWeights()
|
|
{
|
|
DWORD ctr, ctr2; // loop counters
|
|
ULONG Index = 0; // index for enumeration
|
|
PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to full info for enum
|
|
BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer for enum
|
|
PVOID pBuffer = NULL; // ptr to alloc buffer for enum
|
|
ULONG BufSize; // size of buffer
|
|
ULONG ResultLength; // # bytes written
|
|
UNICODE_STRING ObUnicodeStr; // unicode string
|
|
ULONG SortOrder; // sort order from registry
|
|
ULONG Script; // script from registry
|
|
ULONG rc = 0L; // return code
|
|
BYTE RegVal[NUM_SM]; // registry value for script
|
|
BYTE NewScript; // new script to store
|
|
BYTE SM; // script member value
|
|
LPBYTE pSMWeight = pTblPtrs->SMWeight; // ptr to script member weights
|
|
PMULTI_WT pMulti; // ptr to multi weight
|
|
HANDLE hKey = NULL; // handle to registry key
|
|
|
|
|
|
//
|
|
// Enter table pointers critical section.
|
|
//
|
|
RtlEnterCriticalSection(&gcsTblPtrs);
|
|
|
|
//
|
|
// Make sure the SMWeight structure still hasn't been initialized.
|
|
//
|
|
// NOTE: Must leave the first value set to INVALID_SM_VALUE until
|
|
// this function is complete.
|
|
//
|
|
if (pSMWeight[0] != INVALID_SM_VALUE)
|
|
{
|
|
RtlLeaveCriticalSection(&gcsTblPtrs);
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
//
|
|
// Set the 0 to FIRST_SCRIPT of script structure to its default
|
|
// value and the RegVal structure to zero.
|
|
//
|
|
// NOTE: The intermediate RegVal array is necessary because:
|
|
// (1) Enumeration may produce values out of order
|
|
// (2) There may be multiple weight entries in the list
|
|
// As a result, it is not correct to simply increment
|
|
// the sorting order by the value given in the registry.
|
|
//
|
|
RtlZeroMemory(RegVal, NUM_SM);
|
|
RtlZeroMemory(pSMWeight + 1, NUM_SM - 1);
|
|
|
|
for (ctr = 1; ctr < FIRST_SCRIPT; ctr++)
|
|
{
|
|
pSMWeight[ctr] = (BYTE)ctr;
|
|
}
|
|
|
|
//
|
|
// Enumerate through all values in the registry. Store the
|
|
// data in the RegVal structure if it exists.
|
|
//
|
|
// NOTE: Values range from (1) to (NUM_SM - FIRST_SCRIPT).
|
|
//
|
|
OPEN_CPANEL_SORTING_KEY(hKey, (ULONG)STATUS_REGISTRY_CORRUPT);
|
|
|
|
pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic;
|
|
BufSize = MAX_KEY_VALUE_FULLINFO;
|
|
RtlZeroMemory(pKeyValueFull, BufSize);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
BufSize,
|
|
&ResultLength );
|
|
|
|
while (rc != STATUS_NO_MORE_ENTRIES)
|
|
{
|
|
if (rc == STATUS_BUFFER_OVERFLOW)
|
|
{
|
|
//
|
|
// Free old buffer if it was allocated before allocating
|
|
// a new buffer.
|
|
//
|
|
NLS_REG_BUFFER_FREE(pBuffer);
|
|
|
|
//
|
|
// Buffer is too small, so allocate a new one.
|
|
//
|
|
NLS_REG_BUFFER_ALLOC(pKeyValueFull, ResultLength, pBuffer, TRUE);
|
|
BufSize = ResultLength;
|
|
RtlZeroMemory(pKeyValueFull, BufSize);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
BufSize,
|
|
&ResultLength );
|
|
}
|
|
|
|
if (rc != NO_ERROR)
|
|
{
|
|
NLS_REG_BUFFER_FREE(pBuffer);
|
|
CLOSE_REG_KEY(hKey);
|
|
KdPrint(("NLSAPI: Error in getting Script Member Weights - %lx.\n",
|
|
rc));
|
|
RtlLeaveCriticalSection(&gcsTblPtrs);
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Convert the string value to an integer if data exists for
|
|
// the value.
|
|
//
|
|
if (pKeyValueFull->DataLength > 2)
|
|
{
|
|
//
|
|
// Convert the value to an integer.
|
|
//
|
|
RtlInitUnicodeString(&ObUnicodeStr, pKeyValueFull->Name);
|
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &SortOrder)) ||
|
|
(SortOrder > (NUM_SM - FIRST_SCRIPT)))
|
|
{
|
|
//
|
|
// Report that there was an error in the registry.
|
|
//
|
|
KdPrint(("NLSAPI: Sorting Order Registry Value Corrupt.\n"));
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Convert the data to an integer and save it in the
|
|
// RegVal structure.
|
|
//
|
|
RtlInitUnicodeString( &ObUnicodeStr,
|
|
GET_VALUE_DATA_PTR(pKeyValueFull) );
|
|
if ((RtlUnicodeStringToInteger(&ObUnicodeStr, 10, &Script)) ||
|
|
(Script >= NUM_SM) || (Script < FIRST_SCRIPT))
|
|
{
|
|
//
|
|
// Report that there was an error in the registry.
|
|
//
|
|
KdPrint(("NLSAPI: Sorting Order Registry Data Corrupt.\n"));
|
|
}
|
|
else
|
|
{
|
|
RegVal[SortOrder] = (BYTE)Script;
|
|
if (SortOrder != (ULONG)(Script - FIRST_SCRIPT + 1))
|
|
{
|
|
//
|
|
// No longer default order. Set the boolean to TRUE.
|
|
//
|
|
pTblPtrs->IfModify_SMWeight = TRUE;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Increment enumeration index value and get the next enumeration.
|
|
//
|
|
Index++;
|
|
RtlZeroMemory(pKeyValueFull, BufSize);
|
|
rc = NtEnumerateValueKey( hKey,
|
|
Index,
|
|
KeyValueFullInformation,
|
|
pKeyValueFull,
|
|
BufSize,
|
|
&ResultLength );
|
|
}
|
|
|
|
//
|
|
// Free the buffer used for the enumeration.
|
|
//
|
|
NLS_REG_BUFFER_FREE(pBuffer);
|
|
|
|
//
|
|
// Store the values in the SMWeight array in the table
|
|
// pointers structure only if the IfModify_SMWeight boolean is set
|
|
// to TRUE.
|
|
//
|
|
if (pTblPtrs->IfModify_SMWeight)
|
|
{
|
|
//
|
|
// Not using default table, so set the SMWeight array to the
|
|
// correct order.
|
|
//
|
|
NewScript = FIRST_SCRIPT;
|
|
for (ctr = 1; ctr < NUM_SM; ctr++)
|
|
{
|
|
//
|
|
// For each registry value, store the appropriate order in
|
|
// each of the script member fields.
|
|
//
|
|
if ((SM = RegVal[ctr]) != 0)
|
|
{
|
|
//
|
|
// Save the order in the SMWeight array.
|
|
//
|
|
pSMWeight[SM] = NewScript;
|
|
NewScript++;
|
|
|
|
//
|
|
// Make sure the script is not part of a multiple weights
|
|
// script.
|
|
//
|
|
pMulti = pTblPtrs->pMultiWeight;
|
|
for (ctr2 = pTblPtrs->NumMultiWeight; ctr2 > 0; ctr2--, pMulti++)
|
|
{
|
|
if (pMulti->FirstSM == SM)
|
|
{
|
|
//
|
|
// Part of multiple weight, so must move entire range
|
|
// by setting each value in range to NewScript and
|
|
// then incrementing NewScript.
|
|
//
|
|
// NOTE: May use 'ctr2' here since it ALWAYS breaks
|
|
// out of outer for loop.
|
|
//
|
|
for (ctr2 = 1; ctr2 < pMulti->NumSM; ctr2++)
|
|
{
|
|
pSMWeight[SM + ctr2] = NewScript;
|
|
NewScript++;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Must set each script member that has not yet been reset to its
|
|
// new order.
|
|
//
|
|
// The default ordering is to assign:
|
|
// Order = Script Member Value
|
|
//
|
|
// Therefore, can simply set each zero entry in order to the end
|
|
// of the array to the next 'NewScript' value.
|
|
//
|
|
for (ctr = FIRST_SCRIPT; ctr < NUM_SM; ctr++)
|
|
{
|
|
//
|
|
// If it's a zero value, set it to the next sorting order value.
|
|
//
|
|
if (pSMWeight[ctr] == 0)
|
|
{
|
|
pSMWeight[ctr] = NewScript;
|
|
NewScript++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Close the sorting key handle.
|
|
//
|
|
CLOSE_REG_KEY(hKey);
|
|
|
|
//
|
|
// Set the first value to be valid.
|
|
//
|
|
pSMWeight[0] = 0;
|
|
RtlLeaveCriticalSection(&gcsTblPtrs);
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------------//
|
|
// INTERNAL ROUTINES //
|
|
//-------------------------------------------------------------------------//
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// OpenDataFile
|
|
//
|
|
// This routine opens the data file for the specified file name and
|
|
// returns the handle to the file.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG OpenDataFile(
|
|
HANDLE *phFile,
|
|
LPWSTR pFile)
|
|
{
|
|
UNICODE_STRING ObFileName; // file name
|
|
OBJECT_ATTRIBUTES ObjA; // object attributes structure
|
|
IO_STATUS_BLOCK iosb; // IO status block
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Get the NT file name.
|
|
//
|
|
if (rc = GetNTFileName( pFile,
|
|
&ObFileName ))
|
|
{
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Open the file.
|
|
//
|
|
InitializeObjectAttributes( &ObjA,
|
|
&ObFileName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL );
|
|
|
|
rc = NtOpenFile( phFile,
|
|
FILE_READ_DATA | SYNCHRONIZE,
|
|
&ObjA,
|
|
&iosb,
|
|
FILE_SHARE_READ,
|
|
FILE_SYNCHRONOUS_IO_NONALERT );
|
|
|
|
//
|
|
// Free the buffer used for the file name.
|
|
//
|
|
RtlFreeHeap( RtlProcessHeap(),
|
|
0,
|
|
ObFileName.Buffer );
|
|
|
|
//
|
|
// Check for error from NtOpenFile.
|
|
//
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Open File %wZ - %lx.\n", &ObFileName, rc));
|
|
return (rc);
|
|
}
|
|
if (!NT_SUCCESS(iosb.Status))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Open File %wZ - Status = %lx.\n",
|
|
&ObFileName, iosb.Status));
|
|
return ((ULONG)iosb.Status);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// GetNTFileName
|
|
//
|
|
// This routine returns the full path name for the data file found in
|
|
// the given registry information buffer.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG GetNTFileName(
|
|
LPWSTR pFile,
|
|
PUNICODE_STRING pFileName)
|
|
{
|
|
WCHAR pwszFilePath[MAX_PATH_LEN]; // ptr to file path string
|
|
UNICODE_STRING ObFileName; // file name
|
|
ULONG rc = 0L; // return code
|
|
|
|
|
|
//
|
|
// Get the full path name for the file.
|
|
//
|
|
GetSystemDirectoryW(pwszFilePath, MAX_PATH_LEN);
|
|
NlsStrCatW(pwszFilePath, L"\\");
|
|
NlsStrCatW(pwszFilePath, pFile);
|
|
|
|
//
|
|
// Make the file name an NT path name.
|
|
//
|
|
RtlInitUnicodeString(&ObFileName, pwszFilePath);
|
|
if (!RtlDosPathNameToNtPathName_U( ObFileName.Buffer,
|
|
pFileName,
|
|
NULL,
|
|
NULL ))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT convert %wZ to NT path name - %lx.\n",
|
|
&ObFileName, rc));
|
|
return (ERROR_FILE_NOT_FOUND);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// CreateSecurityDescriptor
|
|
//
|
|
// This routine creates the security descriptor needed to create the
|
|
// memory mapped section for a data file and returns the world SID.
|
|
//
|
|
// 05-31-91 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG CreateSecurityDescriptor(
|
|
PSECURITY_DESCRIPTOR 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)NLS_ALLOC_MEM(SidLength)) == NULL)
|
|
{
|
|
*ppWorldSid = NULL;
|
|
KdPrint(("NLSAPI: 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: Could NOT Create Security Descriptor - %lx.\n", rc));
|
|
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: Could NOT Create ACL - %lx.\n", rc));
|
|
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: Could NOT Add Access Allowed ACE - %lx.\n", rc));
|
|
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: Could NOT Set DACL Security Descriptor - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// AppendAccessAllowedACE
|
|
//
|
|
// This routine adds an ACE to the ACL for administrators.
|
|
//
|
|
// 03-08-93 JulieB Created.
|
|
////////////////////////////////////////////////////////////////////////////
|
|
|
|
ULONG AppendAccessAllowedACE(
|
|
PSECURITY_DESCRIPTOR pSecurityDescriptor,
|
|
ACCESS_MASK AccessMask)
|
|
{
|
|
ULONG rc = 0L; // return code
|
|
PACL pDaclBuffer; // ptr to DACL buffer
|
|
ULONG SidLength; // length of SID - 2 sub authorities
|
|
PSID pWSid; // ptr to world SID
|
|
SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY;
|
|
BOOLEAN DaclPresent;
|
|
BOOLEAN DaclDefaulted;
|
|
|
|
|
|
//
|
|
// Create World SID.
|
|
//
|
|
SidLength = RtlLengthRequiredSid(2);
|
|
|
|
if ((pWSid = (PSID)NLS_ALLOC_MEM(SidLength)) == NULL)
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Allocate SID Buffer.\n"));
|
|
return (ERROR_OUTOFMEMORY);
|
|
}
|
|
|
|
RtlInitializeSid( pWSid,
|
|
&SidAuth,
|
|
2 );
|
|
|
|
*(RtlSubAuthoritySid(pWSid, 0)) = SECURITY_BUILTIN_DOMAIN_RID;
|
|
*(RtlSubAuthoritySid(pWSid, 1)) = DOMAIN_ALIAS_RID_ADMINS;
|
|
|
|
//
|
|
// Get DACL.
|
|
//
|
|
rc = RtlGetDaclSecurityDescriptor( pSecurityDescriptor,
|
|
&DaclPresent,
|
|
&pDaclBuffer,
|
|
&DaclDefaulted );
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Get DACL Security Descriptor - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Add an ACE to the ACL that allows Admin query access to the
|
|
// section object.
|
|
//
|
|
rc = RtlAddAccessAllowedAce( (PACL)pDaclBuffer,
|
|
ACL_REVISION2,
|
|
AccessMask,
|
|
pWSid );
|
|
if (!NT_SUCCESS(rc))
|
|
{
|
|
KdPrint(("NLSAPI: Could NOT Add Access Allowed ACE - %lx.\n", rc));
|
|
return (rc);
|
|
}
|
|
|
|
//
|
|
// Free SID.
|
|
//
|
|
NLS_FREE_MEM(pWSid);
|
|
|
|
//
|
|
// Return success.
|
|
//
|
|
return (NO_ERROR);
|
|
}
|
|
|
|
|