diff options
Diffstat (limited to 'winpr/libwinpr/registry')
-rw-r--r-- | winpr/libwinpr/registry/CMakeLists.txt | 21 | ||||
-rw-r--r-- | winpr/libwinpr/registry/ModuleOptions.cmake | 9 | ||||
-rw-r--r-- | winpr/libwinpr/registry/registry.c | 554 | ||||
-rw-r--r-- | winpr/libwinpr/registry/registry_reg.c | 570 | ||||
-rw-r--r-- | winpr/libwinpr/registry/registry_reg.h | 72 |
5 files changed, 1226 insertions, 0 deletions
diff --git a/winpr/libwinpr/registry/CMakeLists.txt b/winpr/libwinpr/registry/CMakeLists.txt new file mode 100644 index 0000000..4400afd --- /dev/null +++ b/winpr/libwinpr/registry/CMakeLists.txt @@ -0,0 +1,21 @@ +# WinPR: Windows Portable Runtime +# libwinpr-registry cmake build script +# +# Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +winpr_module_add( + registry_reg.c + registry_reg.h + registry.c) diff --git a/winpr/libwinpr/registry/ModuleOptions.cmake b/winpr/libwinpr/registry/ModuleOptions.cmake new file mode 100644 index 0000000..a83eb09 --- /dev/null +++ b/winpr/libwinpr/registry/ModuleOptions.cmake @@ -0,0 +1,9 @@ + +set(MINWIN_LAYER "1") +set(MINWIN_GROUP "core") +set(MINWIN_MAJOR_VERSION "1") +set(MINWIN_MINOR_VERSION "0") +set(MINWIN_SHORT_NAME "registry") +set(MINWIN_LONG_NAME "Registry Functions") +set(MODULE_LIBRARY_NAME "api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}") + diff --git a/winpr/libwinpr/registry/registry.c b/winpr/libwinpr/registry/registry.c new file mode 100644 index 0000000..7422d8b --- /dev/null +++ b/winpr/libwinpr/registry/registry.c @@ -0,0 +1,554 @@ +/** + * WinPR: Windows Portable Runtime + * Windows Registry + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> + +#include <winpr/registry.h> + +/* + * Windows registry MSDN pages: + * Reference: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724880/ + * Functions: http://msdn.microsoft.com/en-us/library/windows/desktop/ms724875/ + */ + +#if !defined(_WIN32) || defined(_UWP) + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <winpr/crt.h> +#include <winpr/assert.h> + +#include "registry_reg.h" + +#include "../log.h" +#define TAG WINPR_TAG("registry") + +static Reg* instance = NULL; + +static Reg* RegGetInstance(void) +{ + if (!instance) + instance = reg_open(1); + + return instance; +} + +LONG RegCloseKey(HKEY hKey) +{ + WINPR_UNUSED(hKey); + return 0; +} + +LONG RegCopyTreeW(HKEY hKeySrc, LPCWSTR lpSubKey, HKEY hKeyDest) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegCopyTreeA(HKEY hKeySrc, LPCSTR lpSubKey, HKEY hKeyDest) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegCreateKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD Reserved, LPWSTR lpClass, DWORD dwOptions, + REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, + LPDWORD lpdwDisposition) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegCreateKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD Reserved, LPSTR lpClass, DWORD dwOptions, + REGSAM samDesired, LPSECURITY_ATTRIBUTES lpSecurityAttributes, PHKEY phkResult, + LPDWORD lpdwDisposition) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDeleteKeyExW(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDeleteKeyExA(HKEY hKey, LPCSTR lpSubKey, REGSAM samDesired, DWORD Reserved) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDeleteTreeW(HKEY hKey, LPCWSTR lpSubKey) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDeleteTreeA(HKEY hKey, LPCSTR lpSubKey) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDeleteValueW(HKEY hKey, LPCWSTR lpValueName) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDeleteValueA(HKEY hKey, LPCSTR lpValueName) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegDisablePredefinedCacheEx(void) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegEnumKeyExW(HKEY hKey, DWORD dwIndex, LPWSTR lpName, LPDWORD lpcName, LPDWORD lpReserved, + LPWSTR lpClass, LPDWORD lpcClass, PFILETIME lpftLastWriteTime) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegEnumKeyExA(HKEY hKey, DWORD dwIndex, LPSTR lpName, LPDWORD lpcName, LPDWORD lpReserved, + LPSTR lpClass, LPDWORD lpcClass, PFILETIME lpftLastWriteTime) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegEnumValueW(HKEY hKey, DWORD dwIndex, LPWSTR lpValueName, LPDWORD lpcchValueName, + LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegEnumValueA(HKEY hKey, DWORD dwIndex, LPSTR lpValueName, LPDWORD lpcchValueName, + LPDWORD lpReserved, LPDWORD lpType, LPBYTE lpData, LPDWORD lpcbData) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegFlushKey(HKEY hKey) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegGetKeySecurity(HKEY hKey, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor, LPDWORD lpcbSecurityDescriptor) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegGetValueW(HKEY hkey, LPCWSTR lpSubKey, LPCWSTR lpValue, DWORD dwFlags, LPDWORD pdwType, + PVOID pvData, LPDWORD pcbData) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegGetValueA(HKEY hkey, LPCSTR lpSubKey, LPCSTR lpValue, DWORD dwFlags, LPDWORD pdwType, + PVOID pvData, LPDWORD pcbData) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegLoadAppKeyW(LPCWSTR lpFile, PHKEY phkResult, REGSAM samDesired, DWORD dwOptions, + DWORD Reserved) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegLoadAppKeyA(LPCSTR lpFile, PHKEY phkResult, REGSAM samDesired, DWORD dwOptions, + DWORD Reserved) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegLoadKeyW(HKEY hKey, LPCWSTR lpSubKey, LPCWSTR lpFile) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegLoadKeyA(HKEY hKey, LPCSTR lpSubKey, LPCSTR lpFile) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegLoadMUIStringW(HKEY hKey, LPCWSTR pszValue, LPWSTR pszOutBuf, DWORD cbOutBuf, + LPDWORD pcbData, DWORD Flags, LPCWSTR pszDirectory) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegLoadMUIStringA(HKEY hKey, LPCSTR pszValue, LPSTR pszOutBuf, DWORD cbOutBuf, LPDWORD pcbData, + DWORD Flags, LPCSTR pszDirectory) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegNotifyChangeKeyValue(HKEY hKey, BOOL bWatchSubtree, DWORD dwNotifyFilter, HANDLE hEvent, + BOOL fAsynchronous) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegOpenCurrentUser(REGSAM samDesired, PHKEY phkResult) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegOpenKeyExW(HKEY hKey, LPCWSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) +{ + LONG rc = 0; + char* str = ConvertWCharToUtf8Alloc(lpSubKey, NULL); + if (!str) + return ERROR_FILE_NOT_FOUND; + + rc = RegOpenKeyExA(hKey, str, ulOptions, samDesired, phkResult); + free(str); + return rc; +} + +LONG RegOpenKeyExA(HKEY hKey, LPCSTR lpSubKey, DWORD ulOptions, REGSAM samDesired, PHKEY phkResult) +{ + Reg* reg = RegGetInstance(); + + if (!reg) + return -1; + + if (hKey != HKEY_LOCAL_MACHINE) + { + WLog_WARN(TAG, "Registry emulation only supports HKEY_LOCAL_MACHINE"); + return ERROR_FILE_NOT_FOUND; + } + + WINPR_ASSERT(reg->root_key); + RegKey* pKey = reg->root_key->subkeys; + + while (pKey != NULL) + { + WINPR_ASSERT(lpSubKey); + + if (pKey->subname && (_stricmp(pKey->subname, lpSubKey) == 0)) + { + *phkResult = (HKEY)pKey; + return ERROR_SUCCESS; + } + + pKey = pKey->next; + } + + *phkResult = NULL; + + return ERROR_FILE_NOT_FOUND; +} + +LONG RegOpenUserClassesRoot(HANDLE hToken, DWORD dwOptions, REGSAM samDesired, PHKEY phkResult) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegQueryInfoKeyW(HKEY hKey, LPWSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, + LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, + LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, + LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegQueryInfoKeyA(HKEY hKey, LPSTR lpClass, LPDWORD lpcClass, LPDWORD lpReserved, + LPDWORD lpcSubKeys, LPDWORD lpcMaxSubKeyLen, LPDWORD lpcMaxClassLen, + LPDWORD lpcValues, LPDWORD lpcMaxValueNameLen, LPDWORD lpcMaxValueLen, + LPDWORD lpcbSecurityDescriptor, PFILETIME lpftLastWriteTime) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +static LONG reg_read_int(const RegVal* pValue, LPBYTE lpData, LPDWORD lpcbData) +{ + const BYTE* ptr = NULL; + DWORD required = 0; + + WINPR_ASSERT(pValue); + + switch (pValue->type) + { + case REG_DWORD: + case REG_DWORD_BIG_ENDIAN: + required = sizeof(DWORD); + ptr = (const BYTE*)&pValue->data.dword; + break; + case REG_QWORD: + required = sizeof(UINT64); + ptr = (const BYTE*)&pValue->data.qword; + break; + default: + return ERROR_INTERNAL_ERROR; + } + + if (lpcbData) + { + DWORD size = *lpcbData; + *lpcbData = required; + if (lpData) + { + if (size < *lpcbData) + return ERROR_MORE_DATA; + } + } + + if (lpData != NULL) + { + DWORD size = 0; + WINPR_ASSERT(lpcbData); + + size = *lpcbData; + *lpcbData = required; + if (size < required) + return ERROR_MORE_DATA; + memcpy(lpData, ptr, required); + } + else if (lpcbData != NULL) + *lpcbData = required; + return ERROR_SUCCESS; +} + +LONG RegQueryValueExW(HKEY hKey, LPCWSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, + LPBYTE lpData, LPDWORD lpcbData) +{ + LONG status = ERROR_FILE_NOT_FOUND; + RegKey* key = NULL; + RegVal* pValue = NULL; + char* valueName = NULL; + + WINPR_UNUSED(lpReserved); + + key = (RegKey*)hKey; + WINPR_ASSERT(key); + + valueName = ConvertWCharToUtf8Alloc(lpValueName, NULL); + if (!valueName) + goto end; + + pValue = key->values; + + while (pValue != NULL) + { + if (strcmp(pValue->name, valueName) == 0) + { + if (lpType) + *lpType = pValue->type; + + switch (pValue->type) + { + case REG_DWORD_BIG_ENDIAN: + case REG_QWORD: + case REG_DWORD: + return reg_read_int(pValue, lpData, lpcbData); + case REG_SZ: + { + const size_t length = strnlen(pValue->data.string, UINT32_MAX) * sizeof(WCHAR); + + if (lpData != NULL) + { + DWORD size = 0; + union + { + WCHAR* wc; + BYTE* b; + } cnv; + WINPR_ASSERT(lpcbData); + + cnv.b = lpData; + size = *lpcbData; + *lpcbData = (DWORD)length; + if (size < length) + return ERROR_MORE_DATA; + if (ConvertUtf8NToWChar(pValue->data.string, length, cnv.wc, length) < 0) + return ERROR_OUTOFMEMORY; + } + else if (lpcbData) + *lpcbData = (UINT32)length; + + status = ERROR_SUCCESS; + goto end; + } + default: + WLog_WARN(TAG, + "Registry emulation does not support value type %s [0x%08" PRIx32 "]", + reg_type_string(pValue->type), pValue->type); + break; + } + } + + pValue = pValue->next; + } + +end: + free(valueName); + return status; +} + +LONG RegQueryValueExA(HKEY hKey, LPCSTR lpValueName, LPDWORD lpReserved, LPDWORD lpType, + LPBYTE lpData, LPDWORD lpcbData) +{ + RegKey* key = NULL; + RegVal* pValue = NULL; + + WINPR_UNUSED(lpReserved); + + key = (RegKey*)hKey; + WINPR_ASSERT(key); + + pValue = key->values; + + while (pValue != NULL) + { + if (strcmp(pValue->name, lpValueName) == 0) + { + if (lpType) + *lpType = pValue->type; + + switch (pValue->type) + { + case REG_DWORD_BIG_ENDIAN: + case REG_QWORD: + case REG_DWORD: + return reg_read_int(pValue, lpData, lpcbData); + case REG_SZ: + { + const size_t length = strnlen(pValue->data.string, UINT32_MAX); + char* pData = (char*)lpData; + + if (pData != NULL) + { + DWORD size = 0; + WINPR_ASSERT(lpcbData); + + size = *lpcbData; + *lpcbData = (DWORD)length; + if (size < length) + return ERROR_MORE_DATA; + memcpy(pData, pValue->data.string, length); + pData[length] = '\0'; + } + else if (lpcbData) + *lpcbData = (UINT32)length; + + return ERROR_SUCCESS; + } + default: + WLog_WARN(TAG, + "Registry emulation does not support value type %s [0x%08" PRIx32 "]", + reg_type_string(pValue->type), pValue->type); + break; + } + } + + pValue = pValue->next; + } + + return ERROR_FILE_NOT_FOUND; +} + +LONG RegRestoreKeyW(HKEY hKey, LPCWSTR lpFile, DWORD dwFlags) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegRestoreKeyA(HKEY hKey, LPCSTR lpFile, DWORD dwFlags) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegSaveKeyExW(HKEY hKey, LPCWSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD Flags) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegSaveKeyExA(HKEY hKey, LPCSTR lpFile, LPSECURITY_ATTRIBUTES lpSecurityAttributes, + DWORD Flags) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegSetKeySecurity(HKEY hKey, SECURITY_INFORMATION SecurityInformation, + PSECURITY_DESCRIPTOR pSecurityDescriptor) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegSetValueExW(HKEY hKey, LPCWSTR lpValueName, DWORD Reserved, DWORD dwType, + const BYTE* lpData, DWORD cbData) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegSetValueExA(HKEY hKey, LPCSTR lpValueName, DWORD Reserved, DWORD dwType, const BYTE* lpData, + DWORD cbData) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegUnLoadKeyW(HKEY hKey, LPCWSTR lpSubKey) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +LONG RegUnLoadKeyA(HKEY hKey, LPCSTR lpSubKey) +{ + WLog_ERR(TAG, "TODO: Implement"); + return -1; +} + +#endif diff --git a/winpr/libwinpr/registry/registry_reg.c b/winpr/libwinpr/registry/registry_reg.c new file mode 100644 index 0000000..a1803b6 --- /dev/null +++ b/winpr/libwinpr/registry/registry_reg.c @@ -0,0 +1,570 @@ +/** + * WinPR: Windows Portable Runtime + * Windows Registry (.reg file format) + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <winpr/config.h> + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <winpr/wtypes.h> +#include <winpr/assert.h> +#include <winpr/crt.h> +#include <winpr/file.h> + +#include "registry_reg.h" + +#include "../log.h" +#define TAG WINPR_TAG("registry") + +#define WINPR_HKLM_HIVE "/etc/winpr/HKLM.reg" + +struct reg_data_type +{ + char* tag; + size_t length; + DWORD type; +}; + +static struct reg_data_type REG_DATA_TYPE_TABLE[] = { { "\"", 1, REG_SZ }, + { "dword:", 6, REG_DWORD }, + { "str:\"", 5, REG_SZ }, + { "str(2):\"", 8, REG_EXPAND_SZ }, + { "str(7):\"", 8, REG_MULTI_SZ }, + { "hex:", 4, REG_BINARY }, + { "hex(2):\"", 8, REG_EXPAND_SZ }, + { "hex(7):\"", 8, REG_MULTI_SZ }, + { "hex(b):\"", 8, REG_QWORD } }; + +static char* reg_data_type_string(DWORD type) +{ + switch (type) + { + case REG_NONE: + return "REG_NONE"; + case REG_SZ: + return "REG_SZ"; + case REG_EXPAND_SZ: + return "REG_EXPAND_SZ"; + case REG_BINARY: + return "REG_BINARY"; + case REG_DWORD: + return "REG_DWORD"; + case REG_DWORD_BIG_ENDIAN: + return "REG_DWORD_BIG_ENDIAN"; + case REG_LINK: + return "REG_LINK"; + case REG_MULTI_SZ: + return "REG_MULTI_SZ"; + case REG_RESOURCE_LIST: + return "REG_RESOURCE_LIST"; + case REG_FULL_RESOURCE_DESCRIPTOR: + return "REG_FULL_RESOURCE_DESCRIPTOR"; + case REG_RESOURCE_REQUIREMENTS_LIST: + return "REG_RESOURCE_REQUIREMENTS_LIST"; + case REG_QWORD: + return "REG_QWORD"; + default: + return "REG_UNKNOWN"; + } +} + +static BOOL reg_load_start(Reg* reg) +{ + char* buffer = NULL; + INT64 file_size = 0; + + WINPR_ASSERT(reg); + WINPR_ASSERT(reg->fp); + + _fseeki64(reg->fp, 0, SEEK_END); + file_size = _ftelli64(reg->fp); + _fseeki64(reg->fp, 0, SEEK_SET); + reg->line = NULL; + reg->next_line = NULL; + + if (file_size < 1) + return FALSE; + + buffer = (char*)realloc(reg->buffer, (size_t)file_size + 2); + + if (!buffer) + return FALSE; + reg->buffer = buffer; + + if (fread(reg->buffer, (size_t)file_size, 1, reg->fp) != 1) + return FALSE; + + reg->buffer[file_size] = '\n'; + reg->buffer[file_size + 1] = '\0'; + reg->next_line = strtok(reg->buffer, "\n"); + return TRUE; +} + +static void reg_load_finish(Reg* reg) +{ + if (!reg) + return; + + if (reg->buffer) + { + free(reg->buffer); + reg->buffer = NULL; + } +} + +static RegVal* reg_load_value(const Reg* reg, RegKey* key) +{ + const char* p[5] = { 0 }; + size_t length = 0; + char* name = NULL; + const char* type = NULL; + const char* data = NULL; + RegVal* value = NULL; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + WINPR_ASSERT(reg->line); + + p[0] = reg->line + 1; + p[1] = strstr(p[0], "\"="); + if (!p[1]) + return NULL; + + p[2] = p[1] + 2; + type = p[2]; + + if (p[2][0] == '"') + p[3] = p[2]; + else + p[3] = strchr(p[2], ':'); + + if (!p[3]) + return NULL; + + data = p[3] + 1; + length = (size_t)(p[1] - p[0]); + if (length < 1) + goto fail; + + name = (char*)calloc(length + 1, sizeof(char)); + + if (!name) + goto fail; + + memcpy(name, p[0], length); + value = (RegVal*)calloc(1, sizeof(RegVal)); + + if (!value) + goto fail; + + value->name = name; + value->type = REG_NONE; + + for (size_t index = 0; index < ARRAYSIZE(REG_DATA_TYPE_TABLE); index++) + { + const struct reg_data_type* current = ®_DATA_TYPE_TABLE[index]; + WINPR_ASSERT(current->tag); + WINPR_ASSERT(current->length > 0); + WINPR_ASSERT(current->type != REG_NONE); + + if (strncmp(type, current->tag, current->length) == 0) + { + value->type = current->type; + break; + } + } + + switch (value->type) + { + case REG_DWORD: + { + unsigned long val = 0; + errno = 0; + val = strtoul(data, NULL, 0); + + if ((errno != 0) || (val > UINT32_MAX)) + { + WLog_WARN(TAG, "%s::%s value %s invalid", key->name, value->name, data); + goto fail; + } + value->data.dword = (DWORD)val; + } + break; + case REG_QWORD: + { + unsigned long long val = 0; + errno = 0; + val = strtoull(data, NULL, 0); + + if ((errno != 0) || (val > UINT64_MAX)) + { + WLog_WARN(TAG, "%s::%s value %s invalid", key->name, value->name, data); + goto fail; + } + + value->data.qword = (UINT64)val; + } + break; + case REG_SZ: + { + size_t len = 0; + size_t cmp = 0; + char* end = NULL; + char* start = strchr(data, '"'); + if (!start) + goto fail; + + /* Check for terminating quote, check it is the last symbol */ + len = strlen(start); + end = strchr(start + 1, '"'); + if (!end) + goto fail; + cmp = end - start + 1; + if (len != cmp) + goto fail; + if (start[0] == '"') + start++; + if (end[0] == '"') + end[0] = '\0'; + value->data.string = _strdup(start); + + if (!value->data.string) + goto fail; + } + break; + default: + WLog_ERR(TAG, "[%s] %s unimplemented format: %s", key->name, value->name, + reg_data_type_string(value->type)); + break; + } + + if (!key->values) + { + key->values = value; + } + else + { + RegVal* pValue = key->values; + + while (pValue->next != NULL) + { + pValue = pValue->next; + } + + pValue->next = value; + value->prev = pValue; + } + + return value; + +fail: + free(value); + free(name); + return NULL; +} + +static BOOL reg_load_has_next_line(Reg* reg) +{ + if (!reg) + return 0; + + return (reg->next_line != NULL) ? 1 : 0; +} + +static char* reg_load_get_next_line(Reg* reg) +{ + if (!reg) + return NULL; + + reg->line = reg->next_line; + reg->next_line = strtok(NULL, "\n"); + reg->line_length = strlen(reg->line); + return reg->line; +} + +static char* reg_load_peek_next_line(Reg* reg) +{ + WINPR_ASSERT(reg); + return reg->next_line; +} + +static void reg_insert_key(Reg* reg, RegKey* key, RegKey* subkey) +{ + char* name = NULL; + char* path = NULL; + char* save = NULL; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + WINPR_ASSERT(subkey); + WINPR_ASSERT(subkey->name); + + path = _strdup(subkey->name); + + if (!path) + return; + + name = strtok_s(path, "\\", &save); + + while (name != NULL) + { + if (strcmp(key->name, name) == 0) + { + if (save) + subkey->subname = _strdup(save); + + /* TODO: free allocated memory in error case */ + if (!subkey->subname) + { + free(path); + return; + } + } + + name = strtok_s(NULL, "\\", &save); + } + + free(path); +} + +static RegKey* reg_load_key(Reg* reg, RegKey* key) +{ + char* p[2]; + size_t length = 0; + RegKey* subkey = NULL; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + + WINPR_ASSERT(reg->line); + p[0] = reg->line + 1; + p[1] = strrchr(p[0], ']'); + if (!p[1]) + return NULL; + + subkey = (RegKey*)calloc(1, sizeof(RegKey)); + + if (!subkey) + return NULL; + + length = (size_t)(p[1] - p[0]); + subkey->name = (char*)malloc(length + 1); + + if (!subkey->name) + { + free(subkey); + return NULL; + } + + memcpy(subkey->name, p[0], length); + subkey->name[length] = '\0'; + + while (reg_load_has_next_line(reg)) + { + char* line = reg_load_peek_next_line(reg); + + if (line[0] == '[') + break; + + reg_load_get_next_line(reg); + + if (reg->line[0] == '"') + { + reg_load_value(reg, subkey); + } + } + + reg_insert_key(reg, key, subkey); + + if (!key->subkeys) + { + key->subkeys = subkey; + } + else + { + RegKey* pKey = key->subkeys; + + while (pKey->next != NULL) + { + pKey = pKey->next; + } + + pKey->next = subkey; + subkey->prev = pKey; + } + + return subkey; +} + +static void reg_load(Reg* reg) +{ + reg_load_start(reg); + + while (reg_load_has_next_line(reg)) + { + reg_load_get_next_line(reg); + + if (reg->line[0] == '[') + { + reg_load_key(reg, reg->root_key); + } + } + + reg_load_finish(reg); +} + +static void reg_unload_value(Reg* reg, RegVal* value) +{ + WINPR_ASSERT(reg); + WINPR_ASSERT(value); + + switch (value->type) + { + case REG_SZ: + free(value->data.string); + break; + default: + break; + } + + free(value); +} + +static void reg_unload_key(Reg* reg, RegKey* key) +{ + RegVal* pValue = NULL; + + WINPR_ASSERT(reg); + WINPR_ASSERT(key); + + pValue = key->values; + + while (pValue != NULL) + { + RegVal* pValueNext = pValue->next; + reg_unload_value(reg, pValue); + pValue = pValueNext; + } + + free(key->name); + free(key); +} + +static void reg_unload(Reg* reg) +{ + WINPR_ASSERT(reg); + if (reg->root_key) + { + RegKey* pKey = reg->root_key->subkeys; + + while (pKey != NULL) + { + RegKey* pKeyNext = pKey->next; + reg_unload_key(reg, pKey); + pKey = pKeyNext; + } + + free(reg->root_key); + } +} + +Reg* reg_open(BOOL read_only) +{ + Reg* reg = (Reg*)calloc(1, sizeof(Reg)); + + if (!reg) + return NULL; + + reg->read_only = read_only; + reg->filename = WINPR_HKLM_HIVE; + + if (reg->read_only) + reg->fp = winpr_fopen(reg->filename, "r"); + else + { + reg->fp = winpr_fopen(reg->filename, "r+"); + + if (!reg->fp) + reg->fp = winpr_fopen(reg->filename, "w+"); + } + + if (!reg->fp) + goto fail; + + reg->root_key = (RegKey*)calloc(1, sizeof(RegKey)); + + if (!reg->root_key) + goto fail; + + reg->root_key->values = NULL; + reg->root_key->subkeys = NULL; + reg->root_key->name = "HKEY_LOCAL_MACHINE"; + reg_load(reg); + return reg; + +fail: + reg_close(reg); + return NULL; +} + +void reg_close(Reg* reg) +{ + if (reg) + { + reg_unload(reg); + if (reg->fp) + fclose(reg->fp); + free(reg); + } +} + +const char* reg_type_string(DWORD type) +{ + switch (type) + { + case REG_NONE: + return "REG_NONE"; + case REG_SZ: + return "REG_SZ"; + case REG_EXPAND_SZ: + return "REG_EXPAND_SZ"; + case REG_BINARY: + return "REG_BINARY"; + case REG_DWORD: + return "REG_DWORD"; + case REG_DWORD_BIG_ENDIAN: + return "REG_DWORD_BIG_ENDIAN"; + case REG_LINK: + return "REG_LINK"; + case REG_MULTI_SZ: + return "REG_MULTI_SZ"; + case REG_RESOURCE_LIST: + return "REG_RESOURCE_LIST"; + case REG_FULL_RESOURCE_DESCRIPTOR: + return "REG_FULL_RESOURCE_DESCRIPTOR"; + case REG_RESOURCE_REQUIREMENTS_LIST: + return "REG_RESOURCE_REQUIREMENTS_LIST"; + case REG_QWORD: + return "REG_QWORD"; + default: + return "REG_UNKNOWN"; + } +} diff --git a/winpr/libwinpr/registry/registry_reg.h b/winpr/libwinpr/registry/registry_reg.h new file mode 100644 index 0000000..4ef283e --- /dev/null +++ b/winpr/libwinpr/registry/registry_reg.h @@ -0,0 +1,72 @@ +/** + * WinPR: Windows Portable Runtime + * Windows Registry (.reg file format) + * + * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com> + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef REGISTRY_REG_H_ +#define REGISTRY_REG_H_ + +#include <winpr/registry.h> + +typedef struct s_reg Reg; +typedef struct s_reg_key RegKey; +typedef struct s_reg_val RegVal; + +struct s_reg +{ + FILE* fp; + char* line; + char* next_line; + size_t line_length; + char* buffer; + char* filename; + BOOL read_only; + RegKey* root_key; +}; + +struct s_reg_val +{ + char* name; + DWORD type; + RegVal* prev; + RegVal* next; + + union reg_data + { + DWORD dword; + UINT64 qword; + char* string; + } data; +}; + +struct s_reg_key +{ + char* name; + DWORD type; + RegKey* prev; + RegKey* next; + + char* subname; + RegVal* values; + RegKey* subkeys; +}; + +Reg* reg_open(BOOL read_only); +void reg_close(Reg* reg); + +const char* reg_type_string(DWORD type); + +#endif |