1 /* registry.c - Registry routines
2 SPDX-FileCopyrightText: 2005, 2007 g 10 Code GmbH
3
4 This file is part of GpgEX.
5
6 SPDX-License-Identifier: LGPL-2.1-or-later
7 */
8
9 /* keep this in sync with svn://cvs.gnupg.org/gpgex/trunk/src/registry.c (last checked against rev. 32) */
10
11 #include <config-kleopatra.h>
12
13 #if 0 /* We don't have a config.h in ONLY_KLEO, fix if needed */
14 #if HAVE_CONFIG_H
15 #include <config.h>
16 #endif
17 #endif
18
19 #include <unistd.h>
20 #include <windows.h>
21
22 #include <shlobj.h>
23 #ifndef CSIDL_APPDATA
24 #define CSIDL_APPDATA 0x001a
25 #endif
26 #ifndef CSIDL_LOCAL_APPDATA
27 #define CSIDL_LOCAL_APPDATA 0x001c
28 #endif
29 #ifndef CSIDL_FLAG_CREATE
30 #define CSIDL_FLAG_CREATE 0x8000
31 #endif
32
33 #include "gnupg-registry.h"
34
35 /* This is a helper function to load a Windows function from either of
36 one DLLs. */
37 HRESULT
w32_shgetfolderpath(HWND a,int b,HANDLE c,DWORD d,LPSTR e)38 w32_shgetfolderpath(HWND a, int b, HANDLE c, DWORD d, LPSTR e)
39 {
40 static int initialized;
41 static HRESULT(WINAPI * func)(HWND, int, HANDLE, DWORD, LPSTR);
42
43 if (!initialized) {
44 static char *dllnames[] = { "shell32.dll", "shfolder.dll", NULL };
45 void *handle;
46 int i;
47
48 initialized = 1;
49
50 for (i = 0, handle = NULL; !handle && dllnames[i]; i++) {
51 handle = LoadLibraryA(dllnames[i]);
52 if (handle) {
53 func = (HRESULT(WINAPI *)(HWND, int, HANDLE, DWORD, LPSTR))
54 GetProcAddress(handle, "SHGetFolderPathA");
55 if (!func) {
56 FreeLibrary(handle);
57 handle = NULL;
58 }
59 }
60 }
61 }
62
63 if (func) {
64 return func(a, b, c, d, e);
65 } else {
66 return -1;
67 }
68 }
69
70 /* Helper for read_w32_registry_string(). */
71 static HKEY
get_root_key(const char * root)72 get_root_key(const char *root)
73 {
74 HKEY root_key;
75
76 if (!root) {
77 root_key = HKEY_CURRENT_USER;
78 } else if (!strcmp(root, "HKEY_CLASSES_ROOT")) {
79 root_key = HKEY_CLASSES_ROOT;
80 } else if (!strcmp(root, "HKEY_CURRENT_USER")) {
81 root_key = HKEY_CURRENT_USER;
82 } else if (!strcmp(root, "HKEY_LOCAL_MACHINE")) {
83 root_key = HKEY_LOCAL_MACHINE;
84 } else if (!strcmp(root, "HKEY_USERS")) {
85 root_key = HKEY_USERS;
86 } else if (!strcmp(root, "HKEY_PERFORMANCE_DATA")) {
87 root_key = HKEY_PERFORMANCE_DATA;
88 } else if (!strcmp(root, "HKEY_CURRENT_CONFIG")) {
89 root_key = HKEY_CURRENT_CONFIG;
90 } else {
91 return NULL;
92 }
93 return root_key;
94 }
95
96 /* Return a string from the Win32 Registry or NULL in case of error.
97 Caller must release the return value. A NULL for root is an alias
98 for HKEY_CURRENT_USER, HKEY_LOCAL_MACHINE in turn. */
99 char *
read_w32_registry_string(const char * root,const char * dir,const char * name)100 read_w32_registry_string(const char *root, const char *dir, const char *name)
101 {
102 HKEY root_key, key_handle;
103 DWORD n1, nbytes, type;
104 char *result = NULL;
105
106 if (!(root_key = get_root_key(root))) {
107 return NULL;
108 }
109
110 if (RegOpenKeyExA(root_key, dir, 0, KEY_READ, &key_handle)) {
111 if (root) {
112 return NULL; /* no need for a RegClose, so return direct */
113 }
114 /* It seems to be common practice to fall back to HKLM. */
115 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) {
116 return NULL; /* still no need for a RegClose, so return direct */
117 }
118 }
119
120 nbytes = 1;
121 if (RegQueryValueExA(key_handle, name, 0, NULL, NULL, &nbytes)) {
122 if (root) {
123 goto leave;
124 }
125 /* Try to fallback to HKLM also vor a missing value. */
126 RegCloseKey(key_handle);
127 if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, dir, 0, KEY_READ, &key_handle)) {
128 return NULL; /* Nope. */
129 }
130 if (RegQueryValueExA(key_handle, name, 0, NULL, NULL, &nbytes)) {
131 goto leave;
132 }
133 }
134 result = malloc((n1 = nbytes + 1));
135 if (!result) {
136 goto leave;
137 }
138 if (RegQueryValueExA(key_handle, name, 0, &type, result, &n1)) {
139 free(result); result = NULL;
140 goto leave;
141 }
142 result[nbytes] = 0; /* make sure it is really a string */
143 if (type == REG_EXPAND_SZ && strchr(result, '%')) {
144 char *tmp;
145
146 n1 += 1000;
147 tmp = malloc(n1 + 1);
148 if (!tmp) {
149 goto leave;
150 }
151 nbytes = ExpandEnvironmentStringsA(result, tmp, n1);
152 if (nbytes && nbytes > n1) {
153 free(tmp);
154 n1 = nbytes;
155 tmp = malloc(n1 + 1);
156 if (!tmp) {
157 goto leave;
158 }
159 nbytes = ExpandEnvironmentStringsA(result, tmp, n1);
160 if (nbytes && nbytes > n1) {
161 free(tmp); /* oops - truncated, better don't expand at all */
162 goto leave;
163 }
164 tmp[nbytes] = 0;
165 free(result);
166 result = tmp;
167 } else if (nbytes) { /* okay, reduce the length */
168 tmp[nbytes] = 0;
169 free(result);
170 result = malloc(strlen(tmp) + 1);
171 if (!result) {
172 result = tmp;
173 } else {
174 strcpy(result, tmp);
175 free(tmp);
176 }
177 } else { /* error - don't expand */
178 free(tmp);
179 }
180 }
181
182 leave:
183 RegCloseKey(key_handle);
184 return result;
185 }
186