/****************************** Module Header ******************************\ * Module Name: profile.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * This module contains code to emulate ini file mapping. * * History: * 30-Nov-1993 SanfordS Created. \***************************************************************************/ #include "precomp.h" #pragma hdrstop /***************************************************************************\ * aFastRegMap[] * * This array maps section ids (PMAP_) to cached registry keys and section * addresses within the registry. IF INI FILE MAPPING CHANGES ARE MADE, * THIS TABLE MUST BE UPDATED. * * The first character of the szSection field indicates what root the * section is in. (or locked open status) * M = LocalMachine * U = CurrentUser * L = Locked open - used only on M mappings. * * History: \***************************************************************************/ #define PROOT_CPANEL 0 #define PROOT_ACCESS 1 #define PROOT_CURRENTM 2 #define PROOT_CURRENTU 3 #define PROOT_CONTROL 4 #define PROOT_SERVICES 5 #define PROOT_KEYBOARD 6 #define PROOT_SYSTEM 7 typedef struct tagFASTREGMAP { UINT idRoot; PCWSTR szSection; } FASTREGMAP, *PFASTREGMAP; CONST PCWSTR aFastRegRoot[] = { L"UControl Panel\\", // PROOT_CPANEL L"UControl Panel\\Accessibility\\", // PROOT_ACCESS L"MSoftware\\Microsoft\\Windows NT\\CurrentVersion\\", // PROOT_CURRENTM L"USoftware\\Microsoft\\Windows NT\\CurrentVersion\\", // PROOT_CURRENTU L"MSystem\\CurrentControlSet\\Control\\", // PROOT_CONTROL L"MSystem\\CurrentControlSet\\Services\\", // PROOT_SERVICES L"UKeyboard Layout\\", // PROOT_KEYBOARD L"MSystem\\", // PROOT_SYSTEM }; CONST FASTREGMAP aFastRegMap[PMAP_LAST + 1] = { { PROOT_CPANEL, L"Colors" }, // PMAP_COLORS { PROOT_CPANEL, L"Cursors" }, // PMAP_CURSORS { PROOT_CURRENTM, L"Windows" }, // PMAP_WINDOWSM { PROOT_CURRENTU, L"Windows" }, // PMAP_WINDOWSU { PROOT_CPANEL, L"Desktop" }, // PMAP_DESKTOP { PROOT_CPANEL, L"Icons" }, // PMAP_ICONS { PROOT_CURRENTM, L"Fonts" }, // PMAP_FONTS { PROOT_CURRENTU, L"TrueType" }, // PMAP_TRUETYPE { PROOT_CONTROL, L"Keyboard Layout" }, // PMAP_KBDLAYOUT { PROOT_SERVICES, L"RIT" }, // PMAP_INPUT { PROOT_CURRENTM, L"Compatibility" }, // PMAP_COMPAT { PROOT_CONTROL, L"Session Manager\\SubSystems" }, // PMAP_SUBSYSTEMS { PROOT_CPANEL, L"Sound" }, // PMAP_BEEP { PROOT_CPANEL, L"Mouse" }, // PMAP_MOUSE { PROOT_CPANEL, L"Keyboard" }, // PMAP_KEYBOARD { PROOT_ACCESS, L"StickyKeys" }, // PMAP_STICKYKEYS { PROOT_ACCESS, L"Keyboard Response" }, // PMAP_KEYBOARDRESPONSE { PROOT_ACCESS, L"MouseKeys" }, // PMAP_MOUSEKEYS { PROOT_ACCESS, L"ToggleKeys" }, // PMAP_TOGGLEKEYS { PROOT_ACCESS, L"TimeOut" }, // PMAP_TIMEOUT { PROOT_ACCESS, L"SoundSentry" }, // PMAP_SOUNDSENTRY { PROOT_ACCESS, L"ShowSounds" }, // PMAP_SHOWSOUNDS { PROOT_CURRENTM, L"AeDebug" }, // PMAP_AEDEBUG { PROOT_CONTROL, L"NetworkProvider" }, // PMAP_NETWORK { PROOT_CPANEL, L"Desktop\\WindowMetrics" }, // PMAP_METRICS { PROOT_KEYBOARD, L"" }, // PMAP_UKBDLAYOUT { PROOT_KEYBOARD, L"Toggle" }, // PMAP_UKBDLAYOUTTOGGLE { PROOT_CURRENTM, L"Winlogon" }, // PMAP_WINLOGON { PROOT_ACCESS, L"Keyboard Preference" }, // PMAP_KEYBOARDPREF { PROOT_ACCESS, L"Blind Access" }, // PMAP_SCREENREADER { PROOT_ACCESS, L"HighContrast" }, // PMAP_HIGHCONTRAST { PROOT_CURRENTM, L"IME Compatibility" }, // PMAP_IMECOMPAT { PROOT_CURRENTM, L"IMM" }, // PMAP_IMM { PROOT_CONTROL, L"Session Manager\\SubSystems\\Pool" }, // PMAP_POOLLIMITS { PROOT_CURRENTM, L"Compatibility32" }, // PMAP_COMPAT32 { PROOT_CURRENTM, L"WOW\\SetupPrograms" }, // PMAP_SETUPPROGRAMNAMES { PROOT_CPANEL, L"Input Method" }, // PMAP_INPUTMETHOD { PROOT_CURRENTM, L"Compatibility2" }, // PMAP_COMPAT2 { PROOT_SERVICES, L"Mouclass\\Parameters" }, // PMAP_MOUCLASS_PARAMS { PROOT_SERVICES, L"Kbdclass\\Parameters" }, // PMAP_KBDCLASS_PARAMS { PROOT_CONTROL, L"ComputerName\\ComputerName" }, // PMAP_COMPUTERNAME { PROOT_CONTROL, L"Terminal Server" }, // PMAP_TS { PROOT_SYSTEM, L"WPA\\TabletPC" }, // PMAP_TABLETPC { PROOT_SYSTEM, L"WPA\\MediaCenter" }, // PMAP_MEDIACENTER { PROOT_CURRENTM, L"Windows" }, // PMAP_TS_EXCLUDE_DESKTOP_VERSION }; WCHAR PreviousUserStringBuf[256]; UNICODE_STRING PreviousUserString = {0, sizeof PreviousUserStringBuf, PreviousUserStringBuf}; LUID luidPrevious; CONST WCHAR wszDefaultUser[] = L"\\Registry\\User\\.Default"; UNICODE_STRING DefaultUserString = {sizeof wszDefaultUser - sizeof(WCHAR), sizeof wszDefaultUser, (WCHAR *)wszDefaultUser}; void InitPreviousUserString(void) { UNICODE_STRING UserString; LUID luidCaller; CheckCritIn(); /* * Speed hack, check if luid of this process == system or previous to * save work. */ if (NT_SUCCESS(GetProcessLuid(NULL, &luidCaller))) { if (RtlEqualLuid(&luidCaller, &luidPrevious)) { return; // same as last time - no work. } luidPrevious = luidCaller; if (RtlEqualLuid(&luidCaller, &luidSystem)) goto DefaultUser; } else { luidPrevious = RtlConvertLongToLuid(0); } /* * Set up current user registry base string. */ if (!NT_SUCCESS(RtlFormatCurrentUserKeyPath(&UserString))) { DefaultUser: RtlCopyUnicodeString(&PreviousUserString, &DefaultUserString); } else { UserAssert(sizeof(PreviousUserStringBuf) >= UserString.Length + 4); RtlCopyUnicodeString(&PreviousUserString, &UserString); RtlFreeUnicodeString(&UserString); } RtlAppendUnicodeToString(&PreviousUserString, L"\\"); } typedef struct tagPROFILEUSERNAME { WCHAR awcName[MAXPROFILEBUF]; UNICODE_STRING NameString; } PROFILEUSERNAME, *PPROFILEUSERNAME; PUNICODE_STRING CreateProfileUserName(TL *ptl) { PPROFILEUSERNAME pMapName; CheckCritIn(); pMapName = UserAllocPoolWithQuota(sizeof (PROFILEUSERNAME), TAG_PROFILEUSERNAME); if (!pMapName) { RIPMSG0(RIP_WARNING, "CreateProfileUserName: Allocation failed"); return NULL; } ThreadLockPool(PtiCurrent(), pMapName, ptl); pMapName->NameString.Length = 0; pMapName->NameString.MaximumLength = sizeof (pMapName->awcName); pMapName->NameString.Buffer = pMapName->awcName; InitPreviousUserString(); RtlCopyUnicodeString(&pMapName->NameString, &PreviousUserString); return &(pMapName->NameString); } void FreeProfileUserName(PUNICODE_STRING pProfileUserName,TL *ptl) { UNREFERENCED_PARAMETER(ptl); CheckCritIn(); if (pProfileUserName) { ThreadUnlockAndFreePool(PtiCurrent(), ptl); } } /*****************************************************************************\ * OpenCacheKeyEx * * Attempts to open a cached key for a given section. If we are calling * for a client thread, we must check the access rights for the key after * opening it. * * Returns fSuccess. * * Note -- param 1 can be NULL. If the section name is a per-user registry * section, we ill use the first parameter if available or set up * and use the cached one if the first parameter is NULL. * * History: * 03-Dec-1993 SanfordS Created. \*****************************************************************************/ HANDLE OpenCacheKeyEx( PUNICODE_STRING pMapName OPTIONAL, UINT idSection, ACCESS_MASK amRequest, PDWORD pdwPolicyFlags ) { OBJECT_ATTRIBUTES OA; WCHAR UnicodeStringBuf[256]; WCHAR pszSessionId[13]; UNICODE_STRING UnicodeString; LONG Status; HANDLE hKey = NULL; PEPROCESS peCurrent = PsGetCurrentProcess(); DWORD dwPolicyFlags; CheckCritIn(); UserAssert(idSection <= PMAP_LAST); /* * If we're opening the desktop or CPL\keyboard key for read access, we should be checking * for relevant policy. */ if ((amRequest == KEY_READ) && (idSection == PMAP_DESKTOP)) { UserAssert(pdwPolicyFlags); UserAssert(!(*pdwPolicyFlags & ~POLICY_VALID)); dwPolicyFlags = *pdwPolicyFlags; } else { /* * if we are here because Policy was changed and there is not POLICY_ flags set then return. */ if (pdwPolicyFlags && (*pdwPolicyFlags & POLICY_ONLY)) { *pdwPolicyFlags = 0; UserAssert(FALSE); return NULL; } dwPolicyFlags = POLICY_NONE; } TryAgain: UnicodeString.Length = 0; UnicodeString.MaximumLength = sizeof(UnicodeStringBuf); UnicodeString.Buffer = UnicodeStringBuf; if (dwPolicyFlags & POLICY_MACHINE) { dwPolicyFlags &= ~POLICY_MACHINE; RtlAppendUnicodeToString(&UnicodeString, L"\\Registry\\Machine\\"); RtlAppendUnicodeToString(&UnicodeString, L"Software\\Policies\\Microsoft\\Windows\\"); } else { if (aFastRegRoot[aFastRegMap[idSection].idRoot][0] == L'M') { RtlAppendUnicodeToString(&UnicodeString, L"\\Registry\\Machine\\"); } else { if (!pMapName) { InitPreviousUserString(); RtlAppendUnicodeStringToString( &UnicodeString, &PreviousUserString); } else { RtlAppendUnicodeStringToString( &UnicodeString, pMapName); } } if (dwPolicyFlags & POLICY_USER) { dwPolicyFlags &= ~POLICY_USER; RtlAppendUnicodeToString(&UnicodeString, L"Software\\Policies\\Microsoft\\Windows\\"); } else if (dwPolicyFlags & POLICY_REMOTE) { dwPolicyFlags &= ~POLICY_REMOTE; RtlAppendUnicodeToString(&UnicodeString, L"Remote\\"); swprintf(pszSessionId, L"%ld\\", gSessionId); RtlAppendUnicodeToString(&UnicodeString, pszSessionId); } else { /* * if we are here because Policy was changed then do not try preferences. */ if (pdwPolicyFlags && (*pdwPolicyFlags & POLICY_ONLY)) { *pdwPolicyFlags = 0; return NULL; } dwPolicyFlags &= ~POLICY_NONE; } } RtlAppendUnicodeToString(&UnicodeString, (PWSTR)&aFastRegRoot[aFastRegMap[idSection].idRoot][1]); RtlAppendUnicodeToString(&UnicodeString, (PWSTR)aFastRegMap[idSection].szSection); /* * Open the key for kernel mode access */ InitializeObjectAttributes(&OA, &UnicodeString, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE, NULL, NULL); Status = ZwOpenKey(&hKey, amRequest, &OA); if ( (amRequest == KEY_READ) || /* * We must be able to read * our registry settings. */ (peCurrent == gpepCSRSS) || (peCurrent == gpepInit) ) { } else { /* * Now check if the user has access to the key */ if (NT_SUCCESS(Status)) { PVOID pKey; NTSTATUS Status2; Status2 = ObReferenceObjectByHandle(hKey, amRequest, NULL, KernelMode, &pKey, NULL); if (NT_SUCCESS(Status2)) { if (!AccessCheckObject(pKey, amRequest, UserMode, &KeyMapping)) { ZwClose(hKey); Status = STATUS_ACCESS_DENIED; } ObDereferenceObject(pKey); } else { ZwClose(hKey); Status = STATUS_ACCESS_DENIED; } } } #if DBG if (!NT_SUCCESS(Status)) { UnicodeStringBuf[UnicodeString.Length / 2] = 0; if (PsGetCurrentProcessId() != gpidLogon) { if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { RIPMSG1(RIP_WARNING | RIP_THERESMORE, "OpenCacheKeyEx failed with Status = %lx key:", Status); RIPMSG1(RIP_WARNING | RIP_THERESMORE | RIP_NONAME | RIP_NONEWLINE, " %ws\\", UnicodeStringBuf); } } } #endif /* * If we didn't succeed and we're not down to bottom of policy chain, try again. */ if (!NT_SUCCESS(Status) && dwPolicyFlags) { goto TryAgain; } /* * Update policy level */ if (pdwPolicyFlags) { *pdwPolicyFlags = dwPolicyFlags; } return (NT_SUCCESS(Status) ? hKey : NULL); } /*****************************************************************************\ * CheckDesktopPolicy * * Check if a desktop value has an associated policy. * * Returns TRUE if there is a policy, FALSE otherwise. * * History: * 07-Feb-2000 JerrySh Created. \*****************************************************************************/ BOOL CheckDesktopPolicy( PUNICODE_STRING pProfileUserName OPTIONAL, PCWSTR lpKeyName ) { WCHAR szKey[80]; HANDLE hKey; DWORD cbSize; NTSTATUS Status; UNICODE_STRING UnicodeString; KEY_VALUE_BASIC_INFORMATION KeyInfo; DWORD dwPolicyFlags = gdwPolicyFlags & (POLICY_MACHINE | POLICY_USER); /* * If there is no policy or the caller is winlogon, let it go. */ if (!dwPolicyFlags || PsGetCurrentProcessId() == gpidLogon) { return FALSE; } /* * Convert the ID to a string if we need to. */ if (!IS_PTR(lpKeyName)) { ServerLoadString(hModuleWin, PTR_TO_ID(lpKeyName), szKey, ARRAY_SIZE(szKey)); lpKeyName = szKey; } TryAgain: /* * Try to open a key. */ if ((hKey = OpenCacheKeyEx(pProfileUserName, PMAP_DESKTOP, KEY_READ, &dwPolicyFlags)) == NULL) { return FALSE; } /* * See if the value exists. */ RtlInitUnicodeString(&UnicodeString, lpKeyName); Status = ZwQueryValueKey(hKey, &UnicodeString, KeyValueBasicInformation, &KeyInfo, sizeof(KeyInfo), &cbSize); ZwClose(hKey); if (!NT_ERROR(Status)) { return TRUE; } else if (dwPolicyFlags) { goto TryAgain; } else { return FALSE; } } /*****************************************************************************\ * CheckDesktopPolicyChange * * Check if policy has changed since last time we checked. * * Returns TRUE if policy changed, FASLE otherwise. * * History: * 07-Feb-2000 JerrySh Created. \*****************************************************************************/ BOOL CheckDesktopPolicyChange( PUNICODE_STRING pProfileUserName OPTIONAL ) { static LARGE_INTEGER LastMachineWriteTime; static LARGE_INTEGER LastUserWriteTime; KEY_BASIC_INFORMATION KeyInfo; BOOL bPolicyChanged = FALSE; HANDLE hKey; DWORD cbSize; DWORD dwPolicyFlags; /* * Check if machine policy has changed since last time we checked. */ dwPolicyFlags = POLICY_MACHINE; KeyInfo.LastWriteTime.QuadPart = 0; hKey = OpenCacheKeyEx(pProfileUserName, PMAP_DESKTOP, KEY_READ, &dwPolicyFlags); if (hKey) { if (hKey) { ZwQueryKey(hKey, KeyValueBasicInformation, &KeyInfo, sizeof(KeyInfo), &cbSize); ZwClose(hKey); } gdwPolicyFlags |= POLICY_MACHINE; } else { gdwPolicyFlags &= ~POLICY_MACHINE; } if (LastMachineWriteTime.QuadPart != KeyInfo.LastWriteTime.QuadPart) { LastMachineWriteTime.QuadPart = KeyInfo.LastWriteTime.QuadPart; bPolicyChanged = TRUE; } /* * Check if user policy has changed since last time we checked. */ dwPolicyFlags = POLICY_USER; KeyInfo.LastWriteTime.QuadPart = 0; hKey = OpenCacheKeyEx(pProfileUserName, PMAP_DESKTOP, KEY_READ, &dwPolicyFlags); if (hKey) { ZwQueryKey(hKey, KeyValueBasicInformation, &KeyInfo, sizeof(KeyInfo), &cbSize); ZwClose(hKey); gdwPolicyFlags |= POLICY_USER; } else { gdwPolicyFlags &= ~POLICY_USER; } if (LastUserWriteTime.QuadPart != KeyInfo.LastWriteTime.QuadPart) { LastUserWriteTime.QuadPart = KeyInfo.LastWriteTime.QuadPart; bPolicyChanged = TRUE; } return bPolicyChanged; } /*****************************************************************************\ * FastGetProfileDwordW * * Reads a REG_DWORD type key from the registry. * * returns value read or default value on failure. * * History: * 02-Dec-1993 SanfordS Created. \*****************************************************************************/ BOOL FastGetProfileDwordW(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpKeyName, DWORD dwDefault, PDWORD pdwReturn, DWORD dwPolicyOnly ) { HANDLE hKey; DWORD cbSize; DWORD dwRet; LONG Status; UNICODE_STRING UnicodeString; BYTE Buf[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)]; DWORD dwPolicyFlags = gdwPolicyFlags | dwPolicyOnly; UserAssert(idSection <= PMAP_LAST); TryAgain: if ((hKey = OpenCacheKeyEx(pProfileUserName, idSection, KEY_READ, &dwPolicyFlags)) == NULL) { RIPMSG1(RIP_WARNING | RIP_NONAME, "%ws", lpKeyName); if (dwPolicyOnly & POLICY_ONLY) { return FALSE; } if (pdwReturn) { *pdwReturn = dwDefault; } return TRUE; } RtlInitUnicodeString(&UnicodeString, lpKeyName); Status = ZwQueryValueKey(hKey, &UnicodeString, KeyValuePartialInformation, (PKEY_VALUE_PARTIAL_INFORMATION)Buf, sizeof(Buf), &cbSize); dwRet = dwDefault; if (NT_SUCCESS(Status)) { dwRet = *((PDWORD)((PKEY_VALUE_PARTIAL_INFORMATION)Buf)->Data); } else if (dwPolicyFlags) { ZwClose(hKey); goto TryAgain; } else if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { RIPMSG1(RIP_WARNING, "FastGetProfileDwordW: ObjectName not found: %ws", lpKeyName); } ZwClose(hKey); if (pdwReturn) { *pdwReturn = dwRet; } return TRUE; } /*****************************************************************************\ * FastGetProfileKeysW() * * Reads all key names in the given section. * * History: * 15-Dec-1994 JimA Created. \*****************************************************************************/ DWORD FastGetProfileKeysW(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpDefault, LPWSTR *lpReturnedString ) { HANDLE hKey; DWORD cchSize; DWORD cchKey; LONG Status; WCHAR Buffer[256 + 6]; PKEY_VALUE_BASIC_INFORMATION pKeyInfo; ULONG iValue; LPWSTR lpTmp; LPWSTR lpKeys = NULL; DWORD dwPoolSize; UserAssert(idSection <= PMAP_LAST); if ((hKey = OpenCacheKeyEx(pProfileUserName, idSection, KEY_READ, NULL)) == NULL) { RIPMSG0(RIP_WARNING | RIP_NONAME, ""); goto DefExit; } pKeyInfo = (PKEY_VALUE_BASIC_INFORMATION)Buffer; cchSize = 0; *lpReturnedString = NULL; iValue = 0; while (TRUE) { #if DBG wcscpy(Buffer + 256, L"DON'T"); #endif Status = ZwEnumerateValueKey(hKey, iValue, KeyValueBasicInformation, pKeyInfo, sizeof(Buffer), &cchKey); UserAssert(_wcsicmp(Buffer + 256, L"DON'T") == 0); if (Status == STATUS_NO_MORE_ENTRIES) { break; } else if (!NT_SUCCESS(Status)) { if (lpKeys) { UserFreePool(lpKeys); lpKeys = NULL; } goto DefExit; } UserAssert(pKeyInfo->NameLength * sizeof(WCHAR) <= sizeof(Buffer) - sizeof(KEY_VALUE_BASIC_INFORMATION)); UserAssert(cchKey <= sizeof(Buffer)); /* * A key was found. Allocate space for it. Note that * NameLength is in bytes. */ cchKey = cchSize; cchSize += pKeyInfo->NameLength + sizeof(WCHAR); if (lpKeys == NULL) { dwPoolSize = cchSize + sizeof(WCHAR); lpKeys = UserAllocPoolWithQuota(dwPoolSize, TAG_PROFILE); } else { lpTmp = lpKeys; lpKeys = UserReAllocPoolWithQuota(lpTmp, dwPoolSize, cchSize + sizeof(WCHAR), TAG_PROFILE); /* * Free the original buffer if the allocation fails */ if (lpKeys == NULL) { UserFreePool(lpTmp); } dwPoolSize = cchSize + sizeof(WCHAR); } /* * Check for out of memory. */ if (lpKeys == NULL) goto DefExit; /* * NULL terminate the string and append it to * the key list. */ UserAssert(pKeyInfo->NameLength < sizeof(Buffer) - sizeof(KEY_VALUE_BASIC_INFORMATION)); RtlCopyMemory(&lpKeys[cchKey / sizeof(WCHAR)], pKeyInfo->Name, pKeyInfo->NameLength); lpKeys[(cchKey + pKeyInfo->NameLength) / sizeof(WCHAR)] = 0; iValue++; } /* * If no keys were found, return the default. */ if (iValue == 0) { DefExit: cchSize = wcslen(lpDefault)+1; lpKeys = UserAllocPoolWithQuota((cchSize+1) * sizeof(WCHAR), TAG_PROFILE); if (lpKeys) wcscpy(lpKeys, lpDefault); else cchSize = 0; } else { /* * Turn the byte count into a char count. */ cchSize /= sizeof(WCHAR); } /* * Make sure hKey is closed. */ if (hKey) ZwClose(hKey); /* * Append the ending NULL. */ if (lpKeys) lpKeys[cchSize] = 0; *lpReturnedString = lpKeys; return cchSize; } /*****************************************************************************\ * FastGetProfileStringW() * * Implements a fast version of the standard API using predefined registry * section indecies (PMAP_) that reference lazy-opened, cached registry * handles. FastCloseProfileUserMapping() should be called to clean up * cached entries when fast profile calls are completed. * * This api does NOT implement the NULL lpKeyName feature of the real API. * * History: * 02-Dec-1993 SanfordS Created. \*****************************************************************************/ DWORD FastGetProfileStringW(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpKeyName, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD cchBuf, DWORD dwPolicyOnly ) { HANDLE hKey = NULL; DWORD cbSize; LONG Status; UNICODE_STRING UnicodeString; PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo; DWORD dwPolicyFlags = gdwPolicyFlags | dwPolicyOnly; UserAssert(idSection <= PMAP_LAST); UserAssert(lpKeyName != NULL); TryAgain: if ((hKey = OpenCacheKeyEx(pProfileUserName, idSection, KEY_READ, &dwPolicyFlags)) == NULL) { #if DBG if (PsGetCurrentProcessId() != gpidLogon) { RIPMSG1(RIP_WARNING | RIP_NONAME, "%ws", lpKeyName); } #endif if (dwPolicyOnly & POLICY_ONLY) { return 0; } goto DefExit; } cbSize = (cchBuf * sizeof(WCHAR)) + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); if ((pKeyInfo = UserAllocPoolWithQuota(cbSize, TAG_PROFILE)) == NULL) { goto DefExit; } RtlInitUnicodeString(&UnicodeString, lpKeyName); Status = ZwQueryValueKey(hKey, &UnicodeString, KeyValuePartialInformation, pKeyInfo, cbSize, &cbSize); if (Status == STATUS_BUFFER_OVERFLOW) { RIPMSG0(RIP_WARNING, "FastGetProfileStringW: Buffer overflow"); Status = STATUS_SUCCESS; } UserAssert(NT_SUCCESS(Status) || (Status == STATUS_OBJECT_NAME_NOT_FOUND)); if (NT_SUCCESS(Status)) { if (pKeyInfo->DataLength >= sizeof(WCHAR)) { ((LPWSTR)(pKeyInfo->Data))[cchBuf - 1] = L'\0'; wcscpy(lpReturnedString, (LPWSTR)pKeyInfo->Data); } else { /* * Appears to be a bug with empty strings - only first * byte is set to NULL. (SAS) */ lpReturnedString[0] = TEXT('\0'); } cchBuf = pKeyInfo->DataLength; UserFreePool(pKeyInfo); ZwClose(hKey); /* * data length includes terminating zero [bodind] */ return (cchBuf / sizeof(WCHAR)); } else if (dwPolicyFlags) { UserFreePool(pKeyInfo); ZwClose(hKey); goto TryAgain; } UserFreePool(pKeyInfo); DefExit: /* * Make sure the key is closed. */ if (hKey) ZwClose(hKey); /* * wcscopy copies terminating zero, but the length returned by * wcslen does not, so add 1 to be consistent with success * return [bodind] */ if (lpDefault != NULL) { cchBuf = wcslen(lpDefault) + 1; RtlCopyMemory(lpReturnedString, lpDefault, cchBuf * sizeof(WCHAR)); return cchBuf; } return 0; } /*****************************************************************************\ * FastGetProfileIntW() * * Implements a fast version of the standard API using predefined registry * section indecies (PMAP_) that reference lazy-opened, cached registry * handles. FastCloseProfileUserMapping() should be called to clean up * cached entries when fast profile calls are completed. * * History: * 02-Dec-1993 SanfordS Created. \*****************************************************************************/ BOOL FastGetProfileIntW(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpKeyName, UINT nDefault, PUINT puiReturn, DWORD dwPolicyOnly ) { WCHAR ValueBuf[40]; UNICODE_STRING Value; UINT ReturnValue; UserAssert(idSection <= PMAP_LAST); UserAssert(puiReturn); if (!FastGetProfileStringW(pProfileUserName, idSection, lpKeyName, NULL, ValueBuf, sizeof(ValueBuf) / sizeof(WCHAR), dwPolicyOnly )) { if (dwPolicyOnly & POLICY_ONLY) { return FALSE; } *puiReturn = nDefault; return TRUE; } /* * Convert string to int. */ RtlInitUnicodeString(&Value, ValueBuf); RtlUnicodeStringToInteger(&Value, 10, &ReturnValue); *puiReturn = ReturnValue; return TRUE; } /*****************************************************************************\ * FastWriteProfileStringW * * Implements a fast version of the standard API using predefined registry * section indecies (PMAP_) that reference lazy-opened, cached registry * handles. FastCloseProfileUserMapping() should be called to clean up * cached entries when fast profile calls are completed. * * History: * 02-Dec-1993 SanfordS Created. \*****************************************************************************/ BOOL FastWriteProfileStringW(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpKeyName, LPCWSTR lpString ) { HANDLE hKey; LONG Status; UNICODE_STRING UnicodeString; UserAssert(idSection <= PMAP_LAST); /* * We shouldn't be writing values that are controlled by policy. */ if (idSection == PMAP_DESKTOP) { UserAssert(!CheckDesktopPolicy(pProfileUserName, lpKeyName)); } if ((hKey = OpenCacheKeyEx(pProfileUserName, idSection, KEY_WRITE, NULL)) == NULL) { RIPMSG1(RIP_WARNING | RIP_NONAME, "%ws", lpKeyName); return FALSE; } RtlInitUnicodeString(&UnicodeString, lpKeyName); Status = ZwSetValueKey(hKey, &UnicodeString, 0, REG_SZ, (PVOID)lpString, (wcslen(lpString) + 1) * sizeof(WCHAR)); ZwClose(hKey); return (NT_SUCCESS(Status)); } /*****************************************************************************\ * FastGetProfileIntFromID * * Just like FastGetProfileIntW except it reads the USER string table for the * key name. * * History: * 02-Dec-1993 SanfordS Created. * 25-Feb-1995 BradG Added TWIPS -> Pixel conversion. \*****************************************************************************/ BOOL FastGetProfileIntFromID(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, UINT idKey, int def, PINT pResult, DWORD dwPolicyOnly ) { int result; WCHAR szKey[80]; UserAssert(idSection <= PMAP_LAST); ServerLoadString(hModuleWin, idKey, szKey, ARRAY_SIZE(szKey)); if (FastGetProfileIntW(pProfileUserName,idSection, szKey, def, &result, dwPolicyOnly)) { /* * If you change the below list of STR_* make sure you make a * corresponding change in SetWindowMetricInt (rare.c) */ switch (idKey) { case STR_BORDERWIDTH: case STR_SCROLLWIDTH: case STR_SCROLLHEIGHT: case STR_CAPTIONWIDTH: case STR_CAPTIONHEIGHT: case STR_SMCAPTIONWIDTH: case STR_SMCAPTIONHEIGHT: case STR_MENUWIDTH: case STR_MENUHEIGHT: case STR_ICONHORZSPACING: case STR_ICONVERTSPACING: case STR_MINWIDTH: case STR_MINHORZGAP: case STR_MINVERTGAP: /* * Convert any registry values stored in TWIPS back to pixels */ if (result < 0) result = MultDiv(-result, gpsi->dmLogPixels, 72 * 20); break; } if (pResult) { *pResult = result; } return TRUE; } return FALSE; } /*****************************************************************************\ * FastGetProfileIntFromID * * Just like FastGetProfileStringW except it reads the USER string table for * the key name. * * History: * 02-Dec-1993 SanfordS Created. \*****************************************************************************/ DWORD FastGetProfileStringFromIDW(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, UINT idKey, LPCWSTR lpDefault, LPWSTR lpReturnedString, DWORD cch, DWORD dwPolicyOnly ) { WCHAR szKey[80]; UserAssert(idSection <= PMAP_LAST); ServerLoadString(hModuleWin, idKey, szKey, ARRAY_SIZE(szKey)); return FastGetProfileStringW(pProfileUserName, idSection, szKey, lpDefault, lpReturnedString, cch, dwPolicyOnly); } /*****************************************************************************\ * FastWriteProfileValue * * History: * 06/10/96 GerardoB Renamed and added uType parameter \*****************************************************************************/ BOOL FastWriteProfileValue(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpKeyName, UINT uType, LPBYTE lpStruct, UINT cbSizeStruct ) { HANDLE hKey; LONG Status; UNICODE_STRING UnicodeString; WCHAR szKey[SERVERSTRINGMAXSIZE]; UserAssert(idSection <= PMAP_LAST); if (!IS_PTR(lpKeyName)) { *szKey = (WCHAR)0; ServerLoadString(hModuleWin, PTR_TO_ID(lpKeyName), szKey, ARRAY_SIZE(szKey)); UserAssert(*szKey != (WCHAR)0); lpKeyName = szKey; } /* * We shouldn't be writing values that are controlled by policy. */ if (idSection == PMAP_DESKTOP) { UserAssert(!CheckDesktopPolicy(pProfileUserName, lpKeyName)); } if ((hKey = OpenCacheKeyEx(pProfileUserName, idSection, KEY_WRITE, NULL)) == NULL) { RIPMSG1(RIP_WARNING, "FastWriteProfileValue: Failed to open cache-key (%ws)", lpKeyName); return FALSE; } RtlInitUnicodeString(&UnicodeString, lpKeyName); Status = ZwSetValueKey(hKey, &UnicodeString, 0, uType, lpStruct, cbSizeStruct); ZwClose(hKey); #if DBG if (!NT_SUCCESS(Status)) { RIPMSG3 (RIP_WARNING, "FastWriteProfileValue: ZwSetValueKey Failed. Status:%#lx idSection:%#lx KeyName:%s", Status, idSection, UnicodeString.Buffer); } #endif return (NT_SUCCESS(Status)); } /*****************************************************************************\ * FastGetProfileValue * * If cbSizeReturn is 0, just return the size of the data * * History: * 06/10/96 GerardoB Renamed \*****************************************************************************/ DWORD FastGetProfileValue(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, LPCWSTR lpKeyName, LPBYTE lpDefault, LPBYTE lpReturn, UINT cbSizeReturn, DWORD dwPolicyOnly ) { HANDLE hKey; UINT cbSize; LONG Status; UNICODE_STRING UnicodeString; PKEY_VALUE_PARTIAL_INFORMATION pKeyInfo; WCHAR szKey[SERVERSTRINGMAXSIZE]; KEY_VALUE_PARTIAL_INFORMATION KeyInfo; DWORD dwPolicyFlags = gdwPolicyFlags | dwPolicyOnly; UserAssert(idSection <= PMAP_LAST); if (!IS_PTR(lpKeyName)) { *szKey = (WCHAR)0; ServerLoadString(hModuleWin, PTR_TO_ID(lpKeyName), szKey, ARRAY_SIZE(szKey)); UserAssert(*szKey != (WCHAR)0); lpKeyName = szKey; } TryAgain: if ((hKey = OpenCacheKeyEx(pProfileUserName, idSection, KEY_READ, &dwPolicyFlags)) == NULL) { // if hi-word of lpKeName is 0, it is a resource number not a string if (!IS_PTR(lpKeyName)) RIPMSG1(RIP_WARNING, "FastGetProfileValue: Failed to open cache-key (%08x)", lpKeyName); else RIPMSG1(RIP_WARNING | RIP_NONAME, "%ws", lpKeyName); if (dwPolicyOnly & POLICY_ONLY) { return 0; } goto DefExit; } if (cbSizeReturn == 0) { cbSize = sizeof(KeyInfo); pKeyInfo = &KeyInfo; } else { cbSize = cbSizeReturn + FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data); if ((pKeyInfo = UserAllocPoolWithQuota(cbSize, TAG_PROFILE)) == NULL) { goto DefExit; } } RtlInitUnicodeString(&UnicodeString, lpKeyName); Status = ZwQueryValueKey(hKey, &UnicodeString, KeyValuePartialInformation, pKeyInfo, cbSize, &cbSize); if (NT_SUCCESS(Status)) { UserAssert(cbSizeReturn >= pKeyInfo->DataLength); cbSize = pKeyInfo->DataLength; RtlCopyMemory(lpReturn, pKeyInfo->Data, cbSize); if (cbSizeReturn != 0) { UserFreePool(pKeyInfo); } ZwClose(hKey); return cbSize; } else if ((Status == STATUS_BUFFER_OVERFLOW) && (cbSizeReturn == 0)) { ZwClose(hKey); return pKeyInfo->DataLength; } else if (dwPolicyFlags) { if (cbSizeReturn != 0) { UserFreePool(pKeyInfo); } ZwClose(hKey); goto TryAgain; } #if DBG if (Status != STATUS_OBJECT_NAME_NOT_FOUND) { RIPMSG3 (RIP_WARNING, "FastGetProfileValue: ZwQueryValueKey Failed. Status:%#lx idSection:%#lx KeyName:%s", Status, idSection, UnicodeString.Buffer); } #endif if (cbSizeReturn != 0) { UserFreePool(pKeyInfo); } DefExit: if (hKey) ZwClose(hKey); if (lpDefault) { RtlMoveMemory(lpReturn, lpDefault, cbSizeReturn); return cbSizeReturn; } return 0; } /*****************************************************************************\ * UT_FastGetProfileIntsW * * Repeatedly calls FastGetProfileIntW on the given table. * * History: * 02-Dec-1993 SanfordS Created. \*****************************************************************************/ BOOL FastGetProfileIntsW(PUNICODE_STRING pProfileUserName OPTIONAL, PPROFINTINFO ppii, DWORD dwPolicyOnly ) { WCHAR szKey[40]; while (ppii->idSection != 0) { ServerLoadString(hModuleWin, PTR_TO_ID(ppii->lpKeyName), szKey, ARRAY_SIZE(szKey)); FastGetProfileIntW(pProfileUserName, ppii->idSection, szKey, ppii->nDefault, ppii->puResult, dwPolicyOnly); ppii++; } return TRUE; } /***************************************************************************\ * UpdateWinIni * * Handles impersonation stuff and writes the given value to the registry. * * History: * 28-Jun-1991 MikeHar Ported. * 03-Dec-1993 SanfordS Used FastProfile calls, moved to profile.c \***************************************************************************/ BOOL FastUpdateWinIni(PUNICODE_STRING pProfileUserName OPTIONAL, UINT idSection, UINT wKeyNameId, LPWSTR lpszValue ) { WCHAR szKeyName[40]; BOOL bResult = FALSE; UserAssert(idSection <= PMAP_LAST); ServerLoadString(hModuleWin, wKeyNameId, szKeyName, ARRAY_SIZE(szKeyName)); bResult = FastWriteProfileStringW(pProfileUserName, idSection, szKeyName, lpszValue); return bResult; }