1761c3c98Swinesync /*
2761c3c98Swinesync * Copyright 2016-2017, 2021 Hugh McMaster
3761c3c98Swinesync *
4761c3c98Swinesync * This library is free software; you can redistribute it and/or
5761c3c98Swinesync * modify it under the terms of the GNU Lesser General Public
6761c3c98Swinesync * License as published by the Free Software Foundation; either
7761c3c98Swinesync * version 2.1 of the License, or (at your option) any later version.
8761c3c98Swinesync *
9761c3c98Swinesync * This library is distributed in the hope that it will be useful,
10761c3c98Swinesync * but WITHOUT ANY WARRANTY; without even the implied warranty of
11761c3c98Swinesync * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12761c3c98Swinesync * Lesser General Public License for more details.
13761c3c98Swinesync *
14761c3c98Swinesync * You should have received a copy of the GNU Lesser General Public
15761c3c98Swinesync * License along with this library; if not, write to the Free Software
16761c3c98Swinesync * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17761c3c98Swinesync */
18761c3c98Swinesync
19761c3c98Swinesync #include <stdio.h>
20761c3c98Swinesync #include "reg.h"
21761c3c98Swinesync
reg_type_to_wchar(DWORD type)22761c3c98Swinesync static const WCHAR *reg_type_to_wchar(DWORD type)
23761c3c98Swinesync {
24761c3c98Swinesync int i, array_size = ARRAY_SIZE(type_rels);
25761c3c98Swinesync
26761c3c98Swinesync for (i = 0; i < array_size; i++)
27761c3c98Swinesync {
28761c3c98Swinesync if (type == type_rels[i].type)
29761c3c98Swinesync return type_rels[i].name;
30761c3c98Swinesync }
31761c3c98Swinesync
32761c3c98Swinesync return NULL;
33761c3c98Swinesync }
34761c3c98Swinesync
reg_data_to_wchar(DWORD type,const BYTE * src,DWORD size_bytes)35761c3c98Swinesync static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes)
36761c3c98Swinesync {
37761c3c98Swinesync WCHAR *buffer = NULL;
38761c3c98Swinesync int i;
39761c3c98Swinesync
40761c3c98Swinesync switch (type)
41761c3c98Swinesync {
42761c3c98Swinesync case REG_SZ:
43761c3c98Swinesync case REG_EXPAND_SZ:
4468d5548fSwinesync buffer = malloc(size_bytes);
45761c3c98Swinesync lstrcpyW(buffer, (WCHAR *)src);
46761c3c98Swinesync break;
47761c3c98Swinesync case REG_NONE:
48761c3c98Swinesync case REG_BINARY:
49761c3c98Swinesync {
50761c3c98Swinesync WCHAR *ptr;
51761c3c98Swinesync
5268d5548fSwinesync buffer = malloc((size_bytes * 2 + 1) * sizeof(WCHAR));
5364312c4fSwinesync
5464312c4fSwinesync if (!size_bytes)
5564312c4fSwinesync {
5664312c4fSwinesync *buffer = 0;
5764312c4fSwinesync break;
5864312c4fSwinesync }
5964312c4fSwinesync
60761c3c98Swinesync ptr = buffer;
6164312c4fSwinesync
62761c3c98Swinesync for (i = 0; i < size_bytes; i++)
63*1a6f523eSThomas Csovcsity ptr += swprintf(ptr, L"%02X", src[i]);
64761c3c98Swinesync break;
65761c3c98Swinesync }
66761c3c98Swinesync case REG_DWORD:
67761c3c98Swinesync /* case REG_DWORD_LITTLE_ENDIAN: */
68761c3c98Swinesync case REG_DWORD_BIG_ENDIAN:
69761c3c98Swinesync {
70761c3c98Swinesync const int zero_x_dword = 10;
71761c3c98Swinesync
7268d5548fSwinesync buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR));
73*1a6f523eSThomas Csovcsity swprintf(buffer, L"0x%x", *(DWORD *)src);
74761c3c98Swinesync break;
75761c3c98Swinesync }
76761c3c98Swinesync case REG_MULTI_SZ:
77761c3c98Swinesync {
78761c3c98Swinesync const int two_wchars = 2 * sizeof(WCHAR);
79761c3c98Swinesync DWORD tmp_size;
80761c3c98Swinesync const WCHAR *tmp = (const WCHAR *)src;
81761c3c98Swinesync int len, destindex;
82761c3c98Swinesync
83761c3c98Swinesync if (size_bytes <= two_wchars)
84761c3c98Swinesync {
8568d5548fSwinesync buffer = malloc(sizeof(WCHAR));
86761c3c98Swinesync *buffer = 0;
87761c3c98Swinesync return buffer;
88761c3c98Swinesync }
89761c3c98Swinesync
90761c3c98Swinesync tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
9168d5548fSwinesync buffer = malloc(tmp_size * 2 + sizeof(WCHAR));
92761c3c98Swinesync len = tmp_size / sizeof(WCHAR);
93761c3c98Swinesync
94761c3c98Swinesync for (i = 0, destindex = 0; i < len; i++, destindex++)
95761c3c98Swinesync {
96761c3c98Swinesync if (tmp[i])
97761c3c98Swinesync buffer[destindex] = tmp[i];
98761c3c98Swinesync else
99761c3c98Swinesync {
100761c3c98Swinesync buffer[destindex++] = '\\';
101761c3c98Swinesync buffer[destindex] = '0';
102761c3c98Swinesync }
103761c3c98Swinesync }
104761c3c98Swinesync buffer[destindex] = 0;
105761c3c98Swinesync break;
106761c3c98Swinesync }
107761c3c98Swinesync }
108761c3c98Swinesync return buffer;
109761c3c98Swinesync }
110761c3c98Swinesync
1115eb878feSwinesync static const WCHAR *newlineW = L"\n";
112761c3c98Swinesync
output_value(const WCHAR * value_name,DWORD type,BYTE * data,DWORD data_size)113761c3c98Swinesync static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
114761c3c98Swinesync {
1155eb878feSwinesync static const WCHAR *fmt = L" %1";
116761c3c98Swinesync WCHAR defval[32];
117761c3c98Swinesync WCHAR *reg_data;
118761c3c98Swinesync
119761c3c98Swinesync if (value_name && value_name[0])
120761c3c98Swinesync output_string(fmt, value_name);
121761c3c98Swinesync else
122761c3c98Swinesync {
123761c3c98Swinesync LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
124761c3c98Swinesync output_string(fmt, defval);
125761c3c98Swinesync }
126761c3c98Swinesync output_string(fmt, reg_type_to_wchar(type));
127761c3c98Swinesync
128761c3c98Swinesync if (data)
129761c3c98Swinesync {
130761c3c98Swinesync reg_data = reg_data_to_wchar(type, data, data_size);
131761c3c98Swinesync output_string(fmt, reg_data);
13268d5548fSwinesync free(reg_data);
133761c3c98Swinesync }
134761c3c98Swinesync else
135761c3c98Swinesync {
136761c3c98Swinesync LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
137761c3c98Swinesync output_string(fmt, defval);
138761c3c98Swinesync }
139761c3c98Swinesync output_string(newlineW);
140761c3c98Swinesync }
141761c3c98Swinesync
142761c3c98Swinesync static unsigned int num_values_found = 0;
143c6993373Swinesync static REGSAM sam = 0;
144761c3c98Swinesync
query_value(HKEY hkey,WCHAR * value_name,WCHAR * path,BOOL recurse)145f0c76942Swinesync static int query_value(HKEY hkey, WCHAR *value_name, WCHAR *path, BOOL recurse)
146761c3c98Swinesync {
147761c3c98Swinesync LONG rc;
148761c3c98Swinesync DWORD max_data_bytes = 2048, data_size;
149761c3c98Swinesync DWORD subkey_len;
150761c3c98Swinesync DWORD type, path_len, i;
151761c3c98Swinesync BYTE *data;
1525eb878feSwinesync static const WCHAR *fmt = L"%1\n";
153761c3c98Swinesync WCHAR *subkey_name, *subkey_path;
154761c3c98Swinesync HKEY subkey;
155761c3c98Swinesync
15668d5548fSwinesync data = malloc(max_data_bytes);
157761c3c98Swinesync
158761c3c98Swinesync for (;;)
159761c3c98Swinesync {
160761c3c98Swinesync data_size = max_data_bytes;
161f0c76942Swinesync rc = RegQueryValueExW(hkey, value_name, NULL, &type, data, &data_size);
162761c3c98Swinesync if (rc == ERROR_MORE_DATA)
163761c3c98Swinesync {
164761c3c98Swinesync max_data_bytes = data_size;
16568d5548fSwinesync data = realloc(data, max_data_bytes);
166761c3c98Swinesync }
167761c3c98Swinesync else break;
168761c3c98Swinesync }
169761c3c98Swinesync
170761c3c98Swinesync if (rc == ERROR_SUCCESS)
171761c3c98Swinesync {
172761c3c98Swinesync output_string(fmt, path);
173761c3c98Swinesync output_value(value_name, type, data, data_size);
174761c3c98Swinesync output_string(newlineW);
175761c3c98Swinesync num_values_found++;
176761c3c98Swinesync }
177761c3c98Swinesync
17868d5548fSwinesync free(data);
179761c3c98Swinesync
180761c3c98Swinesync if (!recurse)
181761c3c98Swinesync {
182761c3c98Swinesync if (rc == ERROR_FILE_NOT_FOUND)
183761c3c98Swinesync {
184761c3c98Swinesync if (value_name && *value_name)
185761c3c98Swinesync {
1866c0f70dbSwinesync output_message(STRING_VALUE_NONEXIST);
187761c3c98Swinesync return 1;
188761c3c98Swinesync }
189761c3c98Swinesync output_string(fmt, path);
190761c3c98Swinesync output_value(NULL, REG_SZ, NULL, 0);
191761c3c98Swinesync }
192761c3c98Swinesync return 0;
193761c3c98Swinesync }
194761c3c98Swinesync
19568d5548fSwinesync subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
196761c3c98Swinesync
197761c3c98Swinesync path_len = lstrlenW(path);
198761c3c98Swinesync
199761c3c98Swinesync i = 0;
200761c3c98Swinesync for (;;)
201761c3c98Swinesync {
202761c3c98Swinesync subkey_len = MAX_SUBKEY_LEN;
203f0c76942Swinesync rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
204761c3c98Swinesync if (rc == ERROR_SUCCESS)
205761c3c98Swinesync {
206761c3c98Swinesync subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
207c6993373Swinesync if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
208761c3c98Swinesync {
209761c3c98Swinesync query_value(subkey, value_name, subkey_path, recurse);
210761c3c98Swinesync RegCloseKey(subkey);
211761c3c98Swinesync }
21268d5548fSwinesync free(subkey_path);
213761c3c98Swinesync i++;
214761c3c98Swinesync }
215761c3c98Swinesync else break;
216761c3c98Swinesync }
217761c3c98Swinesync
21868d5548fSwinesync free(subkey_name);
219761c3c98Swinesync return 0;
220761c3c98Swinesync }
221761c3c98Swinesync
query_all(HKEY hkey,WCHAR * path,BOOL recurse,BOOL recursing)22214b77379Swinesync static int query_all(HKEY hkey, WCHAR *path, BOOL recurse, BOOL recursing)
223761c3c98Swinesync {
224761c3c98Swinesync LONG rc;
225d9ac7716Swinesync DWORD num_subkeys, num_values;
226761c3c98Swinesync DWORD max_value_len = 256, value_len;
227761c3c98Swinesync DWORD max_data_bytes = 2048, data_size;
228761c3c98Swinesync DWORD subkey_len;
229761c3c98Swinesync DWORD i, type, path_len;
230761c3c98Swinesync WCHAR *value_name, *subkey_name, *subkey_path;
231761c3c98Swinesync BYTE *data;
232761c3c98Swinesync HKEY subkey;
233761c3c98Swinesync
234d9ac7716Swinesync rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, &num_subkeys, NULL,
235d9ac7716Swinesync NULL, &num_values, NULL, NULL, NULL, NULL);
23614b77379Swinesync if (rc) return 1;
23714b77379Swinesync
23814b77379Swinesync if (num_values || recursing)
2395eb878feSwinesync output_string(L"%1\n", path);
240761c3c98Swinesync
24168d5548fSwinesync value_name = malloc(max_value_len * sizeof(WCHAR));
24268d5548fSwinesync data = malloc(max_data_bytes);
243761c3c98Swinesync
244761c3c98Swinesync i = 0;
245761c3c98Swinesync for (;;)
246761c3c98Swinesync {
247761c3c98Swinesync value_len = max_value_len;
248761c3c98Swinesync data_size = max_data_bytes;
249f0c76942Swinesync rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, data, &data_size);
250761c3c98Swinesync if (rc == ERROR_SUCCESS)
251761c3c98Swinesync {
252761c3c98Swinesync output_value(value_name, type, data, data_size);
253761c3c98Swinesync i++;
254761c3c98Swinesync }
255761c3c98Swinesync else if (rc == ERROR_MORE_DATA)
256761c3c98Swinesync {
257761c3c98Swinesync if (data_size > max_data_bytes)
258761c3c98Swinesync {
259761c3c98Swinesync max_data_bytes = data_size;
26068d5548fSwinesync data = realloc(data, max_data_bytes);
261761c3c98Swinesync }
262761c3c98Swinesync else
263761c3c98Swinesync {
264761c3c98Swinesync max_value_len *= 2;
26568d5548fSwinesync value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
266761c3c98Swinesync }
267761c3c98Swinesync }
268761c3c98Swinesync else break;
269761c3c98Swinesync }
270761c3c98Swinesync
27168d5548fSwinesync free(data);
27268d5548fSwinesync free(value_name);
273761c3c98Swinesync
2743dbd4208Swinesync if (i || recursing)
275761c3c98Swinesync output_string(newlineW);
276761c3c98Swinesync
277d9ac7716Swinesync if (!num_subkeys)
278d9ac7716Swinesync return 0;
279d9ac7716Swinesync
28068d5548fSwinesync subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
281761c3c98Swinesync
282761c3c98Swinesync path_len = lstrlenW(path);
283761c3c98Swinesync
284761c3c98Swinesync i = 0;
285761c3c98Swinesync for (;;)
286761c3c98Swinesync {
287761c3c98Swinesync subkey_len = MAX_SUBKEY_LEN;
288f0c76942Swinesync rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
289761c3c98Swinesync if (rc == ERROR_SUCCESS)
290761c3c98Swinesync {
291761c3c98Swinesync if (recurse)
292761c3c98Swinesync {
293761c3c98Swinesync subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
294c6993373Swinesync if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
295761c3c98Swinesync {
29614b77379Swinesync query_all(subkey, subkey_path, recurse, TRUE);
297761c3c98Swinesync RegCloseKey(subkey);
298761c3c98Swinesync }
29968d5548fSwinesync free(subkey_path);
300761c3c98Swinesync }
3015eb878feSwinesync else output_string(L"%1\\%2\n", path, subkey_name);
302761c3c98Swinesync i++;
303761c3c98Swinesync }
304761c3c98Swinesync else break;
305761c3c98Swinesync }
306761c3c98Swinesync
30768d5548fSwinesync free(subkey_name);
308761c3c98Swinesync return 0;
309761c3c98Swinesync }
310761c3c98Swinesync
run_query(HKEY root,WCHAR * path,WCHAR * key_name,WCHAR * value_name,BOOL value_empty,BOOL recurse)311354e1582Swinesync static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
312761c3c98Swinesync BOOL value_empty, BOOL recurse)
313761c3c98Swinesync {
314f0c76942Swinesync HKEY hkey;
315761c3c98Swinesync int ret;
316761c3c98Swinesync
317c6993373Swinesync if (RegOpenKeyExW(root, path, 0, KEY_READ|sam, &hkey))
318761c3c98Swinesync {
319e11511daSwinesync output_message(STRING_KEY_NONEXIST);
320761c3c98Swinesync return 1;
321761c3c98Swinesync }
322761c3c98Swinesync
323761c3c98Swinesync output_string(newlineW);
324761c3c98Swinesync
325761c3c98Swinesync if (value_name || value_empty)
326761c3c98Swinesync {
327f0c76942Swinesync ret = query_value(hkey, value_name, key_name, recurse);
328761c3c98Swinesync if (recurse)
329761c3c98Swinesync output_message(STRING_MATCHES_FOUND, num_values_found);
330761c3c98Swinesync }
331761c3c98Swinesync else
33214b77379Swinesync ret = query_all(hkey, key_name, recurse, FALSE);
333761c3c98Swinesync
334f0c76942Swinesync RegCloseKey(hkey);
335761c3c98Swinesync
336761c3c98Swinesync return ret;
337761c3c98Swinesync }
338354e1582Swinesync
reg_query(int argc,WCHAR * argvW[])339354e1582Swinesync int reg_query(int argc, WCHAR *argvW[])
340354e1582Swinesync {
341354e1582Swinesync HKEY root;
342354e1582Swinesync WCHAR *path, *key_name, *value_name = NULL;
343354e1582Swinesync BOOL value_empty = FALSE, recurse = FALSE;
344354e1582Swinesync int i;
345354e1582Swinesync
346a1c74056Swinesync if (!parse_registry_key(argvW[2], &root, &path))
347354e1582Swinesync return 1;
348354e1582Swinesync
349354e1582Swinesync for (i = 3; i < argc; i++)
350354e1582Swinesync {
351091880d2Swinesync WCHAR *str;
352091880d2Swinesync
353091880d2Swinesync if (argvW[i][0] != '/' && argvW[i][0] != '-')
354091880d2Swinesync goto invalid;
355091880d2Swinesync
356091880d2Swinesync str = &argvW[i][1];
357354e1582Swinesync
358354e1582Swinesync if (!lstrcmpiW(str, L"ve"))
359354e1582Swinesync {
3608dc46f32Swinesync if (value_empty) goto invalid;
361354e1582Swinesync value_empty = TRUE;
362354e1582Swinesync continue;
363354e1582Swinesync }
364c6993373Swinesync else if (!lstrcmpiW(str, L"reg:32"))
365c6993373Swinesync {
366c6993373Swinesync if (sam & KEY_WOW64_32KEY) goto invalid;
367c6993373Swinesync sam |= KEY_WOW64_32KEY;
368b6bc8e13Swinesync continue;
369c6993373Swinesync }
370c6993373Swinesync else if (!lstrcmpiW(str, L"reg:64"))
371c6993373Swinesync {
372c6993373Swinesync if (sam & KEY_WOW64_64KEY) goto invalid;
373c6993373Swinesync sam |= KEY_WOW64_64KEY;
374c6993373Swinesync continue;
375c6993373Swinesync }
376354e1582Swinesync else if (!str[0] || str[1])
377354e1582Swinesync goto invalid;
378354e1582Swinesync
379354e1582Swinesync switch (towlower(*str))
380354e1582Swinesync {
381354e1582Swinesync case 'v':
382354e1582Swinesync if (value_name || !(value_name = argvW[++i]))
383354e1582Swinesync goto invalid;
384354e1582Swinesync break;
385354e1582Swinesync case 's':
3868dc46f32Swinesync if (recurse) goto invalid;
387354e1582Swinesync recurse = TRUE;
388354e1582Swinesync break;
389354e1582Swinesync default:
390354e1582Swinesync goto invalid;
391354e1582Swinesync }
392354e1582Swinesync }
393354e1582Swinesync
394354e1582Swinesync if (value_name && value_empty)
395354e1582Swinesync goto invalid;
396354e1582Swinesync
397c6993373Swinesync if (sam == (KEY_WOW64_32KEY|KEY_WOW64_64KEY))
398c6993373Swinesync goto invalid;
399c6993373Swinesync
400a1c74056Swinesync key_name = get_long_key(root, path);
401a1c74056Swinesync
402354e1582Swinesync return run_query(root, path, key_name, value_name, value_empty, recurse);
403354e1582Swinesync
404354e1582Swinesync invalid:
4059cf114d7Swinesync output_message(STRING_INVALID_SYNTAX);
406*1a6f523eSThomas Csovcsity output_message(STRING_FUNC_HELP, _wcsupr(argvW[1]));
407354e1582Swinesync return 1;
408354e1582Swinesync }
409