/* * Registry management * * Copyright (C) 1999 Alexandre Julliard * Copyright (C) 2017 Dmitry Timoshkov * * Based on misc/registry.c code * Copyright (C) 1996 Marcus Meissner * Copyright (C) 1998 Matthew Becker * Copyright (C) 1999 Sylvain St-Germain * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winreg.h" #include "winerror.h" #include "winternl.h" #include "wine/unicode.h" #include "wine/debug.h" #include "wine/list.h" WINE_DEFAULT_DEBUG_CHANNEL(reg); NTSTATUS WINAPI RemapPredefinedHandleInternal( HKEY hkey, HKEY override ); NTSTATUS WINAPI DisablePredefinedHandleTableInternal( HKEY hkey ); /****************************************************************************** * RegOverridePredefKey [ADVAPI32.@] */ LSTATUS WINAPI RegOverridePredefKey( HKEY hkey, HKEY override ) { return RtlNtStatusToDosError( RemapPredefinedHandleInternal( hkey, override )); } /****************************************************************************** * RegCreateKeyW [ADVAPI32.@] * * Creates the specified reg key. * * PARAMS * hKey [I] Handle to an open key. * lpSubKey [I] Name of a key that will be opened or created. * phkResult [O] Receives a handle to the opened or created key. * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code defined in Winerror.h */ LSTATUS WINAPI RegCreateKeyW( HKEY hkey, LPCWSTR lpSubKey, PHKEY phkResult ) { return RegCreateKeyExW( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL ); } /****************************************************************************** * RegCreateKeyA [ADVAPI32.@] * * See RegCreateKeyW. */ LSTATUS WINAPI RegCreateKeyA( HKEY hkey, LPCSTR lpSubKey, PHKEY phkResult ) { return RegCreateKeyExA( hkey, lpSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, MAXIMUM_ALLOWED, NULL, phkResult, NULL ); } /****************************************************************************** * RegCreateKeyTransactedW [ADVAPI32.@] */ LSTATUS WINAPI RegCreateKeyTransactedW( HKEY hkey, LPCWSTR name, DWORD reserved, LPWSTR class, DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, PHKEY retkey, LPDWORD dispos, HANDLE transaction, PVOID reserved2 ) { FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey, debugstr_w(name), reserved, debugstr_w(class), options, access, sa, retkey, dispos, transaction, reserved2 ); return ERROR_CALL_NOT_IMPLEMENTED; } /****************************************************************************** * RegCreateKeyTransactedA [ADVAPI32.@] */ LSTATUS WINAPI RegCreateKeyTransactedA( HKEY hkey, LPCSTR name, DWORD reserved, LPSTR class, DWORD options, REGSAM access, SECURITY_ATTRIBUTES *sa, PHKEY retkey, LPDWORD dispos, HANDLE transaction, PVOID reserved2 ) { FIXME( "(%p,%s,%u,%s,%u,%u,%p,%p,%p,%p,%p): stub\n", hkey, debugstr_a(name), reserved, debugstr_a(class), options, access, sa, retkey, dispos, transaction, reserved2 ); return ERROR_CALL_NOT_IMPLEMENTED; } /****************************************************************************** * RegOpenKeyW [ADVAPI32.@] * * See RegOpenKeyA. */ LSTATUS WINAPI RegOpenKeyW( HKEY hkey, LPCWSTR name, PHKEY retkey ) { if (!retkey) return ERROR_INVALID_PARAMETER; if (!name || !*name) { *retkey = hkey; return ERROR_SUCCESS; } return RegOpenKeyExW( hkey, name, 0, MAXIMUM_ALLOWED, retkey ); } /****************************************************************************** * RegOpenKeyA [ADVAPI32.@] * * Open a registry key. * * PARAMS * hkey [I] Handle of parent key to open the new key under * name [I] Name of the key under hkey to open * retkey [O] Destination for the resulting Handle * * RETURNS * Success: ERROR_SUCCESS * Failure: A standard Win32 error code. When retkey is valid, *retkey is set to 0. */ LSTATUS WINAPI RegOpenKeyA( HKEY hkey, LPCSTR name, PHKEY retkey ) { if (!retkey) return ERROR_INVALID_PARAMETER; if (!name || !*name) { *retkey = hkey; return ERROR_SUCCESS; } return RegOpenKeyExA( hkey, name, 0, MAXIMUM_ALLOWED, retkey ); } /****************************************************************************** * RegEnumKeyW [ADVAPI32.@] * * Enumerates subkeys of the specified open reg key. * * PARAMS * hKey [I] Handle to an open key. * dwIndex [I] Index of the subkey of hKey to retrieve. * lpName [O] Name of the subkey. * cchName [I] Size of lpName in TCHARS. * * RETURNS * Success: ERROR_SUCCESS * Failure: system error code. If there are no more subkeys available, the * function returns ERROR_NO_MORE_ITEMS. */ LSTATUS WINAPI RegEnumKeyW( HKEY hkey, DWORD index, LPWSTR name, DWORD name_len ) { return RegEnumKeyExW( hkey, index, name, &name_len, NULL, NULL, NULL, NULL ); } /****************************************************************************** * RegEnumKeyA [ADVAPI32.@] * * See RegEnumKeyW. */ LSTATUS WINAPI RegEnumKeyA( HKEY hkey, DWORD index, LPSTR name, DWORD name_len ) { return RegEnumKeyExA( hkey, index, name, &name_len, NULL, NULL, NULL, NULL ); } /****************************************************************************** * RegQueryMultipleValuesA [ADVAPI32.@] * * Retrieves the type and data for a list of value names associated with a key. * * PARAMS * hKey [I] Handle to an open key. * val_list [O] Array of VALENT structures that describes the entries. * num_vals [I] Number of elements in val_list. * lpValueBuf [O] Pointer to a buffer that receives the data for each value. * ldwTotsize [I/O] Size of lpValueBuf. * * RETURNS * Success: ERROR_SUCCESS. ldwTotsize contains num bytes copied. * Failure: nonzero error code from Winerror.h ldwTotsize contains num needed * bytes. */ LSTATUS WINAPI RegQueryMultipleValuesA( HKEY hkey, PVALENTA val_list, DWORD num_vals, LPSTR lpValueBuf, LPDWORD ldwTotsize ) { unsigned int i; DWORD maxBytes = *ldwTotsize; LSTATUS status; LPSTR bufptr = lpValueBuf; *ldwTotsize = 0; TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); for(i=0; i < num_vals; ++i) { val_list[i].ve_valuelen=0; status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen); if(status != ERROR_SUCCESS) { return status; } if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) { status = RegQueryValueExA(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type, (LPBYTE)bufptr, &val_list[i].ve_valuelen); if(status != ERROR_SUCCESS) { return status; } val_list[i].ve_valueptr = (DWORD_PTR)bufptr; bufptr += val_list[i].ve_valuelen; } *ldwTotsize += val_list[i].ve_valuelen; } return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA; } /****************************************************************************** * RegQueryMultipleValuesW [ADVAPI32.@] * * See RegQueryMultipleValuesA. */ LSTATUS WINAPI RegQueryMultipleValuesW( HKEY hkey, PVALENTW val_list, DWORD num_vals, LPWSTR lpValueBuf, LPDWORD ldwTotsize ) { unsigned int i; DWORD maxBytes = *ldwTotsize; LSTATUS status; LPSTR bufptr = (LPSTR)lpValueBuf; *ldwTotsize = 0; TRACE("(%p,%p,%d,%p,%p=%d)\n", hkey, val_list, num_vals, lpValueBuf, ldwTotsize, *ldwTotsize); for(i=0; i < num_vals; ++i) { val_list[i].ve_valuelen=0; status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, NULL, NULL, &val_list[i].ve_valuelen); if(status != ERROR_SUCCESS) { return status; } if(lpValueBuf != NULL && *ldwTotsize + val_list[i].ve_valuelen <= maxBytes) { status = RegQueryValueExW(hkey, val_list[i].ve_valuename, NULL, &val_list[i].ve_type, (LPBYTE)bufptr, &val_list[i].ve_valuelen); if(status != ERROR_SUCCESS) { return status; } val_list[i].ve_valueptr = (DWORD_PTR)bufptr; bufptr += val_list[i].ve_valuelen; } *ldwTotsize += val_list[i].ve_valuelen; } return lpValueBuf != NULL && *ldwTotsize <= maxBytes ? ERROR_SUCCESS : ERROR_MORE_DATA; } /****************************************************************************** * RegQueryReflectionKey [ADVAPI32.@] */ LONG WINAPI RegQueryReflectionKey( HKEY hkey, BOOL *is_reflection_disabled ) { FIXME( "%p, %p stub\n", hkey, is_reflection_disabled ); *is_reflection_disabled = TRUE; return ERROR_CALL_NOT_IMPLEMENTED; } /****************************************************************************** * RegDeleteKeyW [ADVAPI32.@] * * See RegDeleteKeyA. */ LSTATUS WINAPI RegDeleteKeyW( HKEY hkey, LPCWSTR name ) { return RegDeleteKeyExW( hkey, name, 0, 0 ); } /****************************************************************************** * RegDeleteKeyA [ADVAPI32.@] * * Delete a registry key. * * PARAMS * hkey [I] Handle to parent key containing the key to delete * name [I] Name of the key user hkey to delete * * NOTES * * MSDN is wrong when it says that hkey must be opened with the DELETE access * right. In reality, it opens a new handle with DELETE access. * * RETURNS * Success: ERROR_SUCCESS * Failure: Error code */ LSTATUS WINAPI RegDeleteKeyA( HKEY hkey, LPCSTR name ) { return RegDeleteKeyExA( hkey, name, 0, 0 ); } /****************************************************************************** * RegSetValueW [ADVAPI32.@] * * Sets the data for the default or unnamed value of a reg key. * * PARAMS * hkey [I] Handle to an open key. * subkey [I] Name of a subkey of hKey. * type [I] Type of information to store. * data [I] String that contains the data to set for the default value. * count [I] Ignored. * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegSetValueW( HKEY hkey, LPCWSTR subkey, DWORD type, LPCWSTR data, DWORD count ) { TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_w(subkey), type, debugstr_w(data), count ); if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER; return RegSetKeyValueW( hkey, subkey, NULL, type, data, (strlenW(data) + 1)*sizeof(WCHAR) ); } /****************************************************************************** * RegSetValueA [ADVAPI32.@] * * See RegSetValueW. */ LSTATUS WINAPI RegSetValueA( HKEY hkey, LPCSTR subkey, DWORD type, LPCSTR data, DWORD count ) { TRACE("(%p,%s,%d,%s,%d)\n", hkey, debugstr_a(subkey), type, debugstr_a(data), count ); if (type != REG_SZ || !data) return ERROR_INVALID_PARAMETER; return RegSetKeyValueA( hkey, subkey, NULL, type, data, strlen(data) + 1 ); } /****************************************************************************** * RegQueryValueW [ADVAPI32.@] * * Retrieves the data associated with the default or unnamed value of a key. * * PARAMS * hkey [I] Handle to an open key. * name [I] Name of the subkey of hKey. * data [O] Receives the string associated with the default value * of the key. * count [I/O] Size of lpValue in bytes. * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegQueryValueW( HKEY hkey, LPCWSTR name, LPWSTR data, LPLONG count ) { DWORD ret; HKEY subkey = hkey; TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_w(name), data, count ? *count : 0 ); if (name && name[0]) { if ((ret = RegOpenKeyW( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; } ret = RegQueryValueExW( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); if (subkey != hkey) RegCloseKey( subkey ); if (ret == ERROR_FILE_NOT_FOUND) { /* return empty string if default value not found */ if (data) *data = 0; if (count) *count = sizeof(WCHAR); ret = ERROR_SUCCESS; } return ret; } /****************************************************************************** * RegQueryValueA [ADVAPI32.@] * * See RegQueryValueW. */ LSTATUS WINAPI RegQueryValueA( HKEY hkey, LPCSTR name, LPSTR data, LPLONG count ) { DWORD ret; HKEY subkey = hkey; TRACE("(%p,%s,%p,%d)\n", hkey, debugstr_a(name), data, count ? *count : 0 ); if (name && name[0]) { if ((ret = RegOpenKeyA( hkey, name, &subkey )) != ERROR_SUCCESS) return ret; } ret = RegQueryValueExA( subkey, NULL, NULL, NULL, (LPBYTE)data, (LPDWORD)count ); if (subkey != hkey) RegCloseKey( subkey ); if (ret == ERROR_FILE_NOT_FOUND) { /* return empty string if default value not found */ if (data) *data = 0; if (count) *count = 1; ret = ERROR_SUCCESS; } return ret; } /****************************************************************************** * RegSaveKeyW [ADVAPI32.@] * * Save a key and all of its subkeys and values to a new file in the standard format. * * PARAMS * hkey [I] Handle of key where save begins * lpFile [I] Address of filename to save to * sa [I] Address of security structure * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegSaveKeyW( HKEY hkey, LPCWSTR file, LPSECURITY_ATTRIBUTES sa ) { return RegSaveKeyExW(hkey, file, sa, 0); } /****************************************************************************** * RegSaveKeyA [ADVAPI32.@] * * See RegSaveKeyW. */ LSTATUS WINAPI RegSaveKeyA( HKEY hkey, LPCSTR file, LPSECURITY_ATTRIBUTES sa ) { return RegSaveKeyExA(hkey, file, sa, 0); } /****************************************************************************** * RegReplaceKeyW [ADVAPI32.@] * * Replace the file backing a registry key and all its subkeys with another file. * * PARAMS * hkey [I] Handle of open key * lpSubKey [I] Address of name of subkey * lpNewFile [I] Address of filename for file with new data * lpOldFile [I] Address of filename for backup file * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegReplaceKeyW( HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpNewFile, LPCWSTR lpOldFile ) { FIXME("(%p,%s,%s,%s): stub\n", hkey, debugstr_w(lpSubKey), debugstr_w(lpNewFile),debugstr_w(lpOldFile)); return ERROR_SUCCESS; } /****************************************************************************** * RegReplaceKeyA [ADVAPI32.@] * * See RegReplaceKeyW. */ LSTATUS WINAPI RegReplaceKeyA( HKEY hkey, LPCSTR lpSubKey, LPCSTR lpNewFile, LPCSTR lpOldFile ) { UNICODE_STRING lpSubKeyW; UNICODE_STRING lpNewFileW; UNICODE_STRING lpOldFileW; LONG ret; RtlCreateUnicodeStringFromAsciiz( &lpSubKeyW, lpSubKey ); RtlCreateUnicodeStringFromAsciiz( &lpOldFileW, lpOldFile ); RtlCreateUnicodeStringFromAsciiz( &lpNewFileW, lpNewFile ); ret = RegReplaceKeyW( hkey, lpSubKeyW.Buffer, lpNewFileW.Buffer, lpOldFileW.Buffer ); RtlFreeUnicodeString( &lpOldFileW ); RtlFreeUnicodeString( &lpNewFileW ); RtlFreeUnicodeString( &lpSubKeyW ); return ret; } /****************************************************************************** * RegConnectRegistryW [ADVAPI32.@] * * Establish a connection to a predefined registry key on another computer. * * PARAMS * lpMachineName [I] Address of name of remote computer * hHey [I] Predefined registry handle * phkResult [I] Address of buffer for remote registry handle * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h */ LSTATUS WINAPI RegConnectRegistryW( LPCWSTR lpMachineName, HKEY hKey, PHKEY phkResult ) { LONG ret; TRACE("(%s,%p,%p)\n",debugstr_w(lpMachineName), hKey, phkResult); if (!lpMachineName || !*lpMachineName) { /* Use the local machine name */ ret = RegOpenKeyW( hKey, NULL, phkResult ); } else { WCHAR compName[MAX_COMPUTERNAME_LENGTH + 1]; DWORD len = ARRAY_SIZE( compName ); /* MSDN says lpMachineName must start with \\ : not so */ if( lpMachineName[0] == '\\' && lpMachineName[1] == '\\') lpMachineName += 2; if (GetComputerNameW(compName, &len)) { if (!strcmpiW(lpMachineName, compName)) ret = RegOpenKeyW(hKey, NULL, phkResult); else { FIXME("Connect to %s is not supported.\n",debugstr_w(lpMachineName)); ret = ERROR_BAD_NETPATH; } } else ret = GetLastError(); } return ret; } /****************************************************************************** * RegConnectRegistryA [ADVAPI32.@] * * See RegConnectRegistryW. */ LSTATUS WINAPI RegConnectRegistryA( LPCSTR machine, HKEY hkey, PHKEY reskey ) { UNICODE_STRING machineW; LONG ret; RtlCreateUnicodeStringFromAsciiz( &machineW, machine ); ret = RegConnectRegistryW( machineW.Buffer, hkey, reskey ); RtlFreeUnicodeString( &machineW ); return ret; } /****************************************************************************** * RegDisablePredefinedCache [ADVAPI32.@] * * Disables the caching of the HKEY_CURRENT_USER key for the process. * * PARAMS * None. * * RETURNS * Success: ERROR_SUCCESS * Failure: nonzero error code from Winerror.h * * NOTES * This is useful for services that use impersonation. */ LSTATUS WINAPI RegDisablePredefinedCache(void) { return RtlNtStatusToDosError( DisablePredefinedHandleTableInternal( HKEY_CURRENT_USER )); } /****************************************************************************** * RegCopyTreeA [ADVAPI32.@] * */ LONG WINAPI RegCopyTreeA( HKEY hsrc, const char *subkey, HKEY hdst ) { UNICODE_STRING subkeyW; LONG ret; if (subkey) RtlCreateUnicodeStringFromAsciiz( &subkeyW, subkey ); else subkeyW.Buffer = NULL; ret = RegCopyTreeW( hsrc, subkeyW.Buffer, hdst ); RtlFreeUnicodeString( &subkeyW ); return ret; } /****************************************************************************** * RegEnableReflectionKey [ADVAPI32.@] * */ LONG WINAPI RegEnableReflectionKey(HKEY base) { FIXME("%p: stub\n", base); return ERROR_CALL_NOT_IMPLEMENTED; } /****************************************************************************** * RegDisableReflectionKey [ADVAPI32.@] * */ LONG WINAPI RegDisableReflectionKey(HKEY base) { FIXME("%p: stub\n", base); return ERROR_SUCCESS; }