query.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408
  1. /*
  2. * Copyright 2016-2017, 2021 Hugh McMaster
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Lesser General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2.1 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Lesser General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Lesser General Public
  15. * License along with this library; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  17. */
  18. #include <stdio.h>
  19. #include "reg.h"
  20. static const WCHAR *reg_type_to_wchar(DWORD type)
  21. {
  22. int i, array_size = ARRAY_SIZE(type_rels);
  23. for (i = 0; i < array_size; i++)
  24. {
  25. if (type == type_rels[i].type)
  26. return type_rels[i].name;
  27. }
  28. return NULL;
  29. }
  30. static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes)
  31. {
  32. WCHAR *buffer = NULL;
  33. int i;
  34. switch (type)
  35. {
  36. case REG_SZ:
  37. case REG_EXPAND_SZ:
  38. buffer = malloc(size_bytes);
  39. lstrcpyW(buffer, (WCHAR *)src);
  40. break;
  41. case REG_NONE:
  42. case REG_BINARY:
  43. {
  44. WCHAR *ptr;
  45. buffer = malloc((size_bytes * 2 + 1) * sizeof(WCHAR));
  46. if (!size_bytes)
  47. {
  48. *buffer = 0;
  49. break;
  50. }
  51. ptr = buffer;
  52. for (i = 0; i < size_bytes; i++)
  53. ptr += swprintf(ptr, 3, L"%02X", src[i]);
  54. break;
  55. }
  56. case REG_DWORD:
  57. /* case REG_DWORD_LITTLE_ENDIAN: */
  58. case REG_DWORD_BIG_ENDIAN:
  59. {
  60. const int zero_x_dword = 10;
  61. buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR));
  62. swprintf(buffer, zero_x_dword + 1, L"0x%x", *(DWORD *)src);
  63. break;
  64. }
  65. case REG_MULTI_SZ:
  66. {
  67. const int two_wchars = 2 * sizeof(WCHAR);
  68. DWORD tmp_size;
  69. const WCHAR *tmp = (const WCHAR *)src;
  70. int len, destindex;
  71. if (size_bytes <= two_wchars)
  72. {
  73. buffer = malloc(sizeof(WCHAR));
  74. *buffer = 0;
  75. return buffer;
  76. }
  77. tmp_size = size_bytes - two_wchars; /* exclude both null terminators */
  78. buffer = malloc(tmp_size * 2 + sizeof(WCHAR));
  79. len = tmp_size / sizeof(WCHAR);
  80. for (i = 0, destindex = 0; i < len; i++, destindex++)
  81. {
  82. if (tmp[i])
  83. buffer[destindex] = tmp[i];
  84. else
  85. {
  86. buffer[destindex++] = '\\';
  87. buffer[destindex] = '0';
  88. }
  89. }
  90. buffer[destindex] = 0;
  91. break;
  92. }
  93. }
  94. return buffer;
  95. }
  96. static const WCHAR *newlineW = L"\n";
  97. static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size)
  98. {
  99. static const WCHAR *fmt = L" %1";
  100. WCHAR defval[32];
  101. WCHAR *reg_data;
  102. if (value_name && value_name[0])
  103. output_string(fmt, value_name);
  104. else
  105. {
  106. LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval));
  107. output_string(fmt, defval);
  108. }
  109. output_string(fmt, reg_type_to_wchar(type));
  110. if (data)
  111. {
  112. reg_data = reg_data_to_wchar(type, data, data_size);
  113. output_string(fmt, reg_data);
  114. free(reg_data);
  115. }
  116. else
  117. {
  118. LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval));
  119. output_string(fmt, defval);
  120. }
  121. output_string(newlineW);
  122. }
  123. static unsigned int num_values_found = 0;
  124. static REGSAM sam = 0;
  125. static int query_value(HKEY hkey, WCHAR *value_name, WCHAR *path, BOOL recurse)
  126. {
  127. LONG rc;
  128. DWORD max_data_bytes = 2048, data_size;
  129. DWORD subkey_len;
  130. DWORD type, path_len, i;
  131. BYTE *data;
  132. static const WCHAR *fmt = L"%1\n";
  133. WCHAR *subkey_name, *subkey_path;
  134. HKEY subkey;
  135. data = malloc(max_data_bytes);
  136. for (;;)
  137. {
  138. data_size = max_data_bytes;
  139. rc = RegQueryValueExW(hkey, value_name, NULL, &type, data, &data_size);
  140. if (rc == ERROR_MORE_DATA)
  141. {
  142. max_data_bytes = data_size;
  143. data = realloc(data, max_data_bytes);
  144. }
  145. else break;
  146. }
  147. if (rc == ERROR_SUCCESS)
  148. {
  149. output_string(fmt, path);
  150. output_value(value_name, type, data, data_size);
  151. output_string(newlineW);
  152. num_values_found++;
  153. }
  154. free(data);
  155. if (!recurse)
  156. {
  157. if (rc == ERROR_FILE_NOT_FOUND)
  158. {
  159. if (value_name && *value_name)
  160. {
  161. output_message(STRING_VALUE_NONEXIST);
  162. return 1;
  163. }
  164. output_string(fmt, path);
  165. output_value(NULL, REG_SZ, NULL, 0);
  166. }
  167. return 0;
  168. }
  169. subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
  170. path_len = lstrlenW(path);
  171. i = 0;
  172. for (;;)
  173. {
  174. subkey_len = MAX_SUBKEY_LEN;
  175. rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
  176. if (rc == ERROR_SUCCESS)
  177. {
  178. subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
  179. if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
  180. {
  181. query_value(subkey, value_name, subkey_path, recurse);
  182. RegCloseKey(subkey);
  183. }
  184. free(subkey_path);
  185. i++;
  186. }
  187. else break;
  188. }
  189. free(subkey_name);
  190. return 0;
  191. }
  192. static int query_all(HKEY hkey, WCHAR *path, BOOL recurse, BOOL recursing)
  193. {
  194. LONG rc;
  195. DWORD num_subkeys, num_values;
  196. DWORD max_value_len = 256, value_len;
  197. DWORD max_data_bytes = 2048, data_size;
  198. DWORD subkey_len;
  199. DWORD i, type, path_len;
  200. WCHAR *value_name, *subkey_name, *subkey_path;
  201. BYTE *data;
  202. HKEY subkey;
  203. rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, &num_subkeys, NULL,
  204. NULL, &num_values, NULL, NULL, NULL, NULL);
  205. if (rc) return 1;
  206. if (num_values || recursing)
  207. output_string(L"%1\n", path);
  208. value_name = malloc(max_value_len * sizeof(WCHAR));
  209. data = malloc(max_data_bytes);
  210. i = 0;
  211. for (;;)
  212. {
  213. value_len = max_value_len;
  214. data_size = max_data_bytes;
  215. rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, data, &data_size);
  216. if (rc == ERROR_SUCCESS)
  217. {
  218. output_value(value_name, type, data, data_size);
  219. i++;
  220. }
  221. else if (rc == ERROR_MORE_DATA)
  222. {
  223. if (data_size > max_data_bytes)
  224. {
  225. max_data_bytes = data_size;
  226. data = realloc(data, max_data_bytes);
  227. }
  228. else
  229. {
  230. max_value_len *= 2;
  231. value_name = realloc(value_name, max_value_len * sizeof(WCHAR));
  232. }
  233. }
  234. else break;
  235. }
  236. free(data);
  237. free(value_name);
  238. if (i || recursing)
  239. output_string(newlineW);
  240. if (!num_subkeys)
  241. return 0;
  242. subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR));
  243. path_len = lstrlenW(path);
  244. i = 0;
  245. for (;;)
  246. {
  247. subkey_len = MAX_SUBKEY_LEN;
  248. rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL);
  249. if (rc == ERROR_SUCCESS)
  250. {
  251. if (recurse)
  252. {
  253. subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len);
  254. if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ|sam, &subkey))
  255. {
  256. query_all(subkey, subkey_path, recurse, TRUE);
  257. RegCloseKey(subkey);
  258. }
  259. free(subkey_path);
  260. }
  261. else output_string(L"%1\\%2\n", path, subkey_name);
  262. i++;
  263. }
  264. else break;
  265. }
  266. free(subkey_name);
  267. return 0;
  268. }
  269. static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name,
  270. BOOL value_empty, BOOL recurse)
  271. {
  272. HKEY hkey;
  273. int ret;
  274. if (RegOpenKeyExW(root, path, 0, KEY_READ|sam, &hkey))
  275. {
  276. output_message(STRING_KEY_NONEXIST);
  277. return 1;
  278. }
  279. output_string(newlineW);
  280. if (value_name || value_empty)
  281. {
  282. ret = query_value(hkey, value_name, key_name, recurse);
  283. if (recurse)
  284. output_message(STRING_MATCHES_FOUND, num_values_found);
  285. }
  286. else
  287. ret = query_all(hkey, key_name, recurse, FALSE);
  288. RegCloseKey(hkey);
  289. return ret;
  290. }
  291. int reg_query(int argc, WCHAR *argvW[])
  292. {
  293. HKEY root;
  294. WCHAR *path, *key_name, *value_name = NULL;
  295. BOOL value_empty = FALSE, recurse = FALSE;
  296. int i;
  297. if (!parse_registry_key(argvW[2], &root, &path))
  298. return 1;
  299. for (i = 3; i < argc; i++)
  300. {
  301. WCHAR *str;
  302. if (argvW[i][0] != '/' && argvW[i][0] != '-')
  303. goto invalid;
  304. str = &argvW[i][1];
  305. if (!lstrcmpiW(str, L"ve"))
  306. {
  307. if (value_empty) goto invalid;
  308. value_empty = TRUE;
  309. continue;
  310. }
  311. else if (!lstrcmpiW(str, L"reg:32"))
  312. {
  313. if (sam & KEY_WOW64_32KEY) goto invalid;
  314. sam |= KEY_WOW64_32KEY;
  315. continue;
  316. }
  317. else if (!lstrcmpiW(str, L"reg:64"))
  318. {
  319. if (sam & KEY_WOW64_64KEY) goto invalid;
  320. sam |= KEY_WOW64_64KEY;
  321. continue;
  322. }
  323. else if (!str[0] || str[1])
  324. goto invalid;
  325. switch (towlower(*str))
  326. {
  327. case 'v':
  328. if (value_name || !(value_name = argvW[++i]))
  329. goto invalid;
  330. break;
  331. case 's':
  332. if (recurse) goto invalid;
  333. recurse = TRUE;
  334. break;
  335. default:
  336. goto invalid;
  337. }
  338. }
  339. if (value_name && value_empty)
  340. goto invalid;
  341. if (sam == (KEY_WOW64_32KEY|KEY_WOW64_64KEY))
  342. goto invalid;
  343. key_name = get_long_key(root, path);
  344. return run_query(root, path, key_name, value_name, value_empty, recurse);
  345. invalid:
  346. output_message(STRING_INVALID_SYNTAX);
  347. output_message(STRING_FUNC_HELP, wcsupr(argvW[1]));
  348. return 1;
  349. }