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 19 #include <stdio.h> 20 #include "reg.h" 21 22 static const WCHAR *reg_type_to_wchar(DWORD type) 23 { 24 int i, array_size = ARRAY_SIZE(type_rels); 25 26 for (i = 0; i < array_size; i++) 27 { 28 if (type == type_rels[i].type) 29 return type_rels[i].name; 30 } 31 32 return NULL; 33 } 34 35 static WCHAR *reg_data_to_wchar(DWORD type, const BYTE *src, DWORD size_bytes) 36 { 37 WCHAR *buffer = NULL; 38 int i; 39 40 switch (type) 41 { 42 case REG_SZ: 43 case REG_EXPAND_SZ: 44 buffer = malloc(size_bytes); 45 lstrcpyW(buffer, (WCHAR *)src); 46 break; 47 case REG_NONE: 48 case REG_BINARY: 49 { 50 WCHAR *ptr; 51 52 buffer = malloc((size_bytes * 2 + 1) * sizeof(WCHAR)); 53 ptr = buffer; 54 for (i = 0; i < size_bytes; i++) 55 ptr += swprintf(ptr, 3, L"%02X", src[i]); 56 break; 57 } 58 case REG_DWORD: 59 /* case REG_DWORD_LITTLE_ENDIAN: */ 60 case REG_DWORD_BIG_ENDIAN: 61 { 62 const int zero_x_dword = 10; 63 64 buffer = malloc((zero_x_dword + 1) * sizeof(WCHAR)); 65 swprintf(buffer, zero_x_dword + 1, L"0x%x", *(DWORD *)src); 66 break; 67 } 68 case REG_MULTI_SZ: 69 { 70 const int two_wchars = 2 * sizeof(WCHAR); 71 DWORD tmp_size; 72 const WCHAR *tmp = (const WCHAR *)src; 73 int len, destindex; 74 75 if (size_bytes <= two_wchars) 76 { 77 buffer = malloc(sizeof(WCHAR)); 78 *buffer = 0; 79 return buffer; 80 } 81 82 tmp_size = size_bytes - two_wchars; /* exclude both null terminators */ 83 buffer = malloc(tmp_size * 2 + sizeof(WCHAR)); 84 len = tmp_size / sizeof(WCHAR); 85 86 for (i = 0, destindex = 0; i < len; i++, destindex++) 87 { 88 if (tmp[i]) 89 buffer[destindex] = tmp[i]; 90 else 91 { 92 buffer[destindex++] = '\\'; 93 buffer[destindex] = '0'; 94 } 95 } 96 buffer[destindex] = 0; 97 break; 98 } 99 } 100 return buffer; 101 } 102 103 static const WCHAR *newlineW = L"\n"; 104 105 static void output_value(const WCHAR *value_name, DWORD type, BYTE *data, DWORD data_size) 106 { 107 static const WCHAR *fmt = L" %1"; 108 WCHAR defval[32]; 109 WCHAR *reg_data; 110 111 if (value_name && value_name[0]) 112 output_string(fmt, value_name); 113 else 114 { 115 LoadStringW(GetModuleHandleW(NULL), STRING_DEFAULT_VALUE, defval, ARRAY_SIZE(defval)); 116 output_string(fmt, defval); 117 } 118 output_string(fmt, reg_type_to_wchar(type)); 119 120 if (data) 121 { 122 reg_data = reg_data_to_wchar(type, data, data_size); 123 output_string(fmt, reg_data); 124 free(reg_data); 125 } 126 else 127 { 128 LoadStringW(GetModuleHandleW(NULL), STRING_VALUE_NOT_SET, defval, ARRAY_SIZE(defval)); 129 output_string(fmt, defval); 130 } 131 output_string(newlineW); 132 } 133 134 static unsigned int num_values_found = 0; 135 136 static int query_value(HKEY hkey, WCHAR *value_name, WCHAR *path, BOOL recurse) 137 { 138 LONG rc; 139 DWORD max_data_bytes = 2048, data_size; 140 DWORD subkey_len; 141 DWORD type, path_len, i; 142 BYTE *data; 143 static const WCHAR *fmt = L"%1\n"; 144 WCHAR *subkey_name, *subkey_path; 145 HKEY subkey; 146 147 data = malloc(max_data_bytes); 148 149 for (;;) 150 { 151 data_size = max_data_bytes; 152 rc = RegQueryValueExW(hkey, value_name, NULL, &type, data, &data_size); 153 if (rc == ERROR_MORE_DATA) 154 { 155 max_data_bytes = data_size; 156 data = realloc(data, max_data_bytes); 157 } 158 else break; 159 } 160 161 if (rc == ERROR_SUCCESS) 162 { 163 output_string(fmt, path); 164 output_value(value_name, type, data, data_size); 165 output_string(newlineW); 166 num_values_found++; 167 } 168 169 free(data); 170 171 if (!recurse) 172 { 173 if (rc == ERROR_FILE_NOT_FOUND) 174 { 175 if (value_name && *value_name) 176 { 177 output_message(STRING_VALUE_NONEXIST); 178 return 1; 179 } 180 output_string(fmt, path); 181 output_value(NULL, REG_SZ, NULL, 0); 182 } 183 return 0; 184 } 185 186 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); 187 188 path_len = lstrlenW(path); 189 190 i = 0; 191 for (;;) 192 { 193 subkey_len = MAX_SUBKEY_LEN; 194 rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); 195 if (rc == ERROR_SUCCESS) 196 { 197 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); 198 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ, &subkey)) 199 { 200 query_value(subkey, value_name, subkey_path, recurse); 201 RegCloseKey(subkey); 202 } 203 free(subkey_path); 204 i++; 205 } 206 else break; 207 } 208 209 free(subkey_name); 210 return 0; 211 } 212 213 static int query_all(HKEY hkey, WCHAR *path, BOOL recurse, BOOL recursing) 214 { 215 LONG rc; 216 DWORD num_values; 217 DWORD max_value_len = 256, value_len; 218 DWORD max_data_bytes = 2048, data_size; 219 DWORD subkey_len; 220 DWORD i, type, path_len; 221 WCHAR *value_name, *subkey_name, *subkey_path; 222 BYTE *data; 223 HKEY subkey; 224 225 rc = RegQueryInfoKeyW(hkey, NULL, NULL, NULL, NULL, NULL, NULL, 226 &num_values, NULL, NULL, NULL, NULL); 227 if (rc) return 1; 228 229 if (num_values || recursing) 230 output_string(L"%1\n", path); 231 232 value_name = malloc(max_value_len * sizeof(WCHAR)); 233 data = malloc(max_data_bytes); 234 235 i = 0; 236 for (;;) 237 { 238 value_len = max_value_len; 239 data_size = max_data_bytes; 240 rc = RegEnumValueW(hkey, i, value_name, &value_len, NULL, &type, data, &data_size); 241 if (rc == ERROR_SUCCESS) 242 { 243 output_value(value_name, type, data, data_size); 244 i++; 245 } 246 else if (rc == ERROR_MORE_DATA) 247 { 248 if (data_size > max_data_bytes) 249 { 250 max_data_bytes = data_size; 251 data = realloc(data, max_data_bytes); 252 } 253 else 254 { 255 max_value_len *= 2; 256 value_name = realloc(value_name, max_value_len * sizeof(WCHAR)); 257 } 258 } 259 else break; 260 } 261 262 free(data); 263 free(value_name); 264 265 if (i || recursing) 266 output_string(newlineW); 267 268 subkey_name = malloc(MAX_SUBKEY_LEN * sizeof(WCHAR)); 269 270 path_len = lstrlenW(path); 271 272 i = 0; 273 for (;;) 274 { 275 subkey_len = MAX_SUBKEY_LEN; 276 rc = RegEnumKeyExW(hkey, i, subkey_name, &subkey_len, NULL, NULL, NULL, NULL); 277 if (rc == ERROR_SUCCESS) 278 { 279 if (recurse) 280 { 281 subkey_path = build_subkey_path(path, path_len, subkey_name, subkey_len); 282 if (!RegOpenKeyExW(hkey, subkey_name, 0, KEY_READ, &subkey)) 283 { 284 query_all(subkey, subkey_path, recurse, TRUE); 285 RegCloseKey(subkey); 286 } 287 free(subkey_path); 288 } 289 else output_string(L"%1\\%2\n", path, subkey_name); 290 i++; 291 } 292 else break; 293 } 294 295 free(subkey_name); 296 return 0; 297 } 298 299 static int run_query(HKEY root, WCHAR *path, WCHAR *key_name, WCHAR *value_name, 300 BOOL value_empty, BOOL recurse) 301 { 302 HKEY hkey; 303 int ret; 304 305 if (RegOpenKeyExW(root, path, 0, KEY_READ, &hkey) != ERROR_SUCCESS) 306 { 307 output_message(STRING_KEY_NONEXIST); 308 return 1; 309 } 310 311 output_string(newlineW); 312 313 if (value_name || value_empty) 314 { 315 ret = query_value(hkey, value_name, key_name, recurse); 316 if (recurse) 317 output_message(STRING_MATCHES_FOUND, num_values_found); 318 } 319 else 320 ret = query_all(hkey, key_name, recurse, FALSE); 321 322 RegCloseKey(hkey); 323 324 return ret; 325 } 326 327 int reg_query(int argc, WCHAR *argvW[]) 328 { 329 HKEY root; 330 WCHAR *path, *key_name, *value_name = NULL; 331 BOOL value_empty = FALSE, recurse = FALSE; 332 int i; 333 334 if (!parse_registry_key(argvW[2], &root, &path)) 335 return 1; 336 337 for (i = 3; i < argc; i++) 338 { 339 WCHAR *str; 340 341 if (argvW[i][0] != '/' && argvW[i][0] != '-') 342 goto invalid; 343 344 str = &argvW[i][1]; 345 346 if (!lstrcmpiW(str, L"ve")) 347 { 348 if (value_empty) goto invalid; 349 value_empty = TRUE; 350 continue; 351 } 352 else if (!lstrcmpiW(str, L"reg:32") || !lstrcmpiW(str, L"reg:64")) 353 continue; 354 else if (!str[0] || str[1]) 355 goto invalid; 356 357 switch (towlower(*str)) 358 { 359 case 'v': 360 if (value_name || !(value_name = argvW[++i])) 361 goto invalid; 362 break; 363 case 's': 364 if (recurse) goto invalid; 365 recurse = TRUE; 366 break; 367 default: 368 goto invalid; 369 } 370 } 371 372 if (value_name && value_empty) 373 goto invalid; 374 375 key_name = get_long_key(root, path); 376 377 return run_query(root, path, key_name, value_name, value_empty, recurse); 378 379 invalid: 380 output_message(STRING_INVALID_SYNTAX); 381 output_message(STRING_FUNC_HELP, wcsupr(argvW[1])); 382 return 1; 383 } 384