/*++ Copyright (c) 1991-2000, 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 CreateRegKey OpenRegKey QueryRegValue SetRegValue CreateSectionFromReg CreateSectionOneValue CreateSectionTemp OpenSection MapSection UnMapSection GetNlsSectionName GetCodePageDLLPathName 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 CreateNlsSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, UINT SecurityDescriptorSize, 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)) //-------------------------------------------------------------------------// // EXTERNAL ROUTINES // //-------------------------------------------------------------------------// //////////////////////////////////////////////////////////////////////////// // // CreateNlsObjectDirectory // // This routine creates the object directory for the NLS memory mapped // sections. // // 05-31-91 JulieB Created. //////////////////////////////////////////////////////////////////////////// ULONG CreateNlsObjectDirectory() { BYTE pSecurityDescriptor[MAX_SECURITY_BUF_LEN]; // security descriptor buffer (currently we use like 60 bytes or so of this) UNICODE_STRING ObDirName; // directory name OBJECT_ATTRIBUTES ObjA; // object attributes structure HANDLE hDirHandle; // directory handle ULONG rc = 0L; // return code // // Create the security descriptor with READ access to the world. // rc = CreateNlsSecurityDescriptor( pSecurityDescriptor, MAX_SECURITY_BUF_LEN, DIRECTORY_QUERY | DIRECTORY_TRAVERSE ); if (!NT_SUCCESS(rc)) { return (rc); } // // Add Admin Access for Query. // rc = AppendAccessAllowedACE( pSecurityDescriptor, DIRECTORY_QUERY | DIRECTORY_TRAVERSE | DIRECTORY_CREATE_OBJECT ); if (!NT_SUCCESS(rc)) { 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 ); // // Close the directory handle. // 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); } //////////////////////////////////////////////////////////////////////////// // // CreateRegKey // // This routine creates a key in the registry. // // 12-17-97 JulieB Created. //////////////////////////////////////////////////////////////////////////// ULONG CreateRegKey( 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); // // Create the registry key. // RtlInitUnicodeString(&ObKeyName, pwszKeyName); InitializeObjectAttributes( &ObjA, &ObKeyName, OBJ_CASE_INSENSITIVE, UserKeyHandle, NULL ); rc = NtCreateKey( phKeyHandle, fAccess, &ObjA, 0, NULL, REG_OPTION_NON_VOLATILE, NULL ); // // Close the current user handle, if necessary. // if (UserKeyHandle != NULL) { NtClose(UserKeyHandle); } // // Check for error from NtCreateKey. // if (!NT_SUCCESS(rc)) { *phKeyHandle = NULL; } // // Return the status from NtCreateKey. // return (rc); } //////////////////////////////////////////////////////////////////////////// // // 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); } if (pKey) { 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)) { *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); } //////////////////////////////////////////////////////////////////////////// // // SetRegValue // // This routine sets the given value in the registry. // // 12-17-97 JulieB Created. //////////////////////////////////////////////////////////////////////////// ULONG SetRegValue( HANDLE hKeyHandle, LPCWSTR pValue, LPCWSTR pData, ULONG DataLength) { UNICODE_STRING ObValueName; // value name // // Set the value in the registry. // RtlInitUnicodeString(&ObValueName, pValue); return (NtSetValueKey( hKeyHandle, &ObValueName, 0, REG_SZ, (PVOID)pData, DataLength )); } //////////////////////////////////////////////////////////////////////////// // // 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) { SIZE_T 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-1991 JulieB Created. // 06-04-2002 ShawnSte Added more security //////////////////////////////////////////////////////////////////////////// ULONG GetNlsSectionName( UINT Value, UINT Base, UINT Padding, LPWSTR pwszPrefix, LPWSTR pwszSecName, UINT cchSecName) { size_t cchUsed; // // Create section name string. // NlsStrCpyW(pwszSecName, pwszPrefix); // See how much we used already cchUsed = NlsStrLenW(pwszPrefix); // Now convert the number, passing along the used buffer length return ( NlsConvertIntegerToString( Value, Base, Padding, pwszSecName + NlsStrLenW(pwszSecName), cchSecName - cchUsed )); // Some characters are already used } //////////////////////////////////////////////////////////////////////////// // // GetCodePageDLLPathName // // This routine returns the full path name for the DLL file found in // the CodePage section of the registry for the given code page value. // // 10-23-96 JulieB Created. //////////////////////////////////////////////////////////////////////////// ULONG GetCodePageDLLPathName( UINT CodePage, LPWSTR pDllName, USHORT cchLen) { WCHAR pTmpBuf[MAX_SMALL_BUF_LEN]; // temp buffer PKEY_VALUE_FULL_INFORMATION pKeyValueFull; // ptr to query info BYTE pStatic[MAX_KEY_VALUE_FULLINFO]; // ptr to static buffer BOOL IfAlloc = FALSE; // if buffer was allocated ULONG rc = 0L; // return code // // Open the CodePage registry key. // OPEN_CODEPAGE_KEY(ERROR_BADDB); // // Convert the code page value to a unicode string. // if (rc = NlsConvertIntegerToString( CodePage, 10, 0, pTmpBuf, MAX_SMALL_BUF_LEN )) { return (rc); } // // Query the registry for the code page value. // pKeyValueFull = (PKEY_VALUE_FULL_INFORMATION)pStatic; if (rc = QueryRegValue( hCodePageKey, pTmpBuf, &pKeyValueFull, MAX_KEY_VALUE_FULLINFO, &IfAlloc )) { return (rc); } // // Make sure there is data with this value. // if (pKeyValueFull->DataLength > 2) { // // Get the full path name for the DLL file. // GetSystemDirectoryW(pDllName, cchLen / 2); NlsStrCatW(pDllName, L"\\"); NlsStrCatW(pDllName, GET_VALUE_DATA_PTR(pKeyValueFull)); } else { rc = ERROR_INVALID_PARAMETER; } // // Free the buffer used for the query. // if (IfAlloc) { NLS_FREE_MEM(pKeyValueFull); } // // Return. // return (rc); } //-------------------------------------------------------------------------// // 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 ); // // Check for error from NtOpenFile. // if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Open File %wZ - %lx.\n", &ObFileName, rc)); RtlFreeHeap(RtlProcessHeap(), 0, ObFileName.Buffer); return (rc); } if (!NT_SUCCESS(iosb.Status)) { KdPrint(("NLSAPI: Could NOT Open File %wZ - Status = %lx.\n", &ObFileName, iosb.Status)); RtlFreeHeap(RtlProcessHeap(), 0, ObFileName.Buffer); return ((ULONG)iosb.Status); } // // Return success. // RtlFreeHeap(RtlProcessHeap(), 0, ObFileName.Buffer); return (NO_ERROR); } //////////////////////////////////////////////////////////////////////////// // // GetNTFileName // // This routine returns the full path name for the data file found in // the given registry information buffer. // // NOTE: The pFileName parameter will contain a newly allocated buffer // that must be freed by the caller (pFileName->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. // pwszFilePath[0] = L'\0'; 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); } //////////////////////////////////////////////////////////////////////////// // // CreateNlsSecurityDescriptor // // 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 CreateNlsSecurityDescriptor( PSECURITY_DESCRIPTOR pSecurityDescriptor, UINT SecurityDescriptorSize, ACCESS_MASK AccessMask) { ULONG rc = STATUS_SUCCESS; // return code (positive thinking) PACL pAclBuffer; // ptr to ACL buffer PSID pWorldSid = NULL; // ptr to world SID SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_WORLD_SID_AUTHORITY; // // Create World SID. // rc = RtlAllocateAndInitializeSid( &SidAuth, 1, SECURITY_WORLD_RID, 0, 0, 0, 0, 0, 0, 0, &pWorldSid ); if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Create SID - %lx.\n", rc)); goto CSD_Exit; } // // Initialize Security Descriptor. // rc = RtlCreateSecurityDescriptor( pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Create Security Descriptor - %lx.\n", rc)); goto CSD_Exit; } // // Initialize ACL. // pAclBuffer = (PACL)((PBYTE)pSecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); rc = RtlCreateAcl( (PACL)pAclBuffer, SecurityDescriptorSize - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION2 ); if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Create ACL - %lx.\n", rc)); goto CSD_Exit; } // // Add an ACE to the ACL that allows World GENERIC_READ to the // section object. // rc = RtlAddAccessAllowedAce( (PACL)pAclBuffer, ACL_REVISION2, AccessMask, pWorldSid ); if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Add Access Allowed ACE - %lx.\n", rc)); goto CSD_Exit; } // // 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)); goto CSD_Exit; } CSD_Exit: // // Free the Sid. // if (pWorldSid) RtlFreeHeap(RtlProcessHeap(), 0, pWorldSid); // // Return the result. // return (rc); } //////////////////////////////////////////////////////////////////////////// // // 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 = STATUS_SUCCESS; // return code (positive thinking) PACL pDaclBuffer; // ptr to DACL buffer ULONG SidLength; // length of SID - 2 sub authorities PSID pLocalSystemSid = NULL; // ptr to local system SID SID_IDENTIFIER_AUTHORITY SidAuth = SECURITY_NT_AUTHORITY; BOOLEAN DaclPresent; BOOLEAN DaclDefaulted; // // Create Local System Account SID. // rc = RtlAllocateAndInitializeSid( &SidAuth, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pLocalSystemSid ); if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Create SID - %lx.\n", rc)); goto AAA_EXIT; } // // Get DACL. // rc = RtlGetDaclSecurityDescriptor( pSecurityDescriptor, &DaclPresent, &pDaclBuffer, &DaclDefaulted ); if (!NT_SUCCESS(rc) || !pDaclBuffer || !DaclPresent) { KdPrint(("NLSAPI: Could NOT Get DACL Security Descriptor - %lx.\n", rc)); goto AAA_EXIT; } // // Add an ACE to the ACL that allows Admin query access to the // section object. // rc = RtlAddAccessAllowedAce( (PACL)pDaclBuffer, ACL_REVISION2, AccessMask, pLocalSystemSid ); if (!NT_SUCCESS(rc)) { KdPrint(("NLSAPI: Could NOT Add Access Allowed ACE - %lx.\n", rc)); goto AAA_EXIT; } AAA_EXIT: // // Free SID. // if (pLocalSystemSid) RtlFreeHeap(RtlProcessHeap(), 0, pLocalSystemSid); // // Return condition. // return rc; }