Mercurial > trustbridge
comparison cinst/nssstore_win.c @ 856:797aa8d9c785
(issue48) Fallback to HKEY_USERS on hive load failure
If the hive can not be loaded it might mean that the user
is currently logged on. In that case we can access his
registry via HKEY_USERS.
author | Andre Heinecke <andre.heinecke@intevation.de> |
---|---|
date | Thu, 31 Jul 2014 12:56:26 +0200 |
parents | 216a65d7fc4b |
children | 698b6a9bd75e |
comparison
equal
deleted
inserted
replaced
855:e4cf249ba1a6 | 856:797aa8d9c785 |
---|---|
67 /**@def The maximum time to wait for the NSS Process */ | 67 /**@def The maximum time to wait for the NSS Process */ |
68 #define PROCESS_TIMEOUT 30000 | 68 #define PROCESS_TIMEOUT 30000 |
69 | 69 |
70 /**@def The registry key to look for user profile directories */ | 70 /**@def The registry key to look for user profile directories */ |
71 #define PROFILE_LIST L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList" | 71 #define PROFILE_LIST L"Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList" |
72 #define RUNONCE_PATH L"Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce" | |
73 | |
74 struct profile_key_path { | |
75 char *sid; | |
76 char *hive_path; | |
77 struct profile_key_path *next; | |
78 }; | |
79 | |
80 /** | |
81 * @brief combination of sid and hive path | |
82 */ | |
83 typedef struct profile_key_path pkp_t; | |
84 | |
85 static void | |
86 pkp_t_free (pkp_t *item) | |
87 { | |
88 if (!item) | |
89 { | |
90 return; | |
91 } | |
92 xfree (item->sid); | |
93 xfree (item->hive_path); | |
94 if (item->next) | |
95 { | |
96 pkp_t_free (item->next); | |
97 } | |
98 xfree (item); | |
99 } | |
72 | 100 |
73 /** @brief get a restricted access token to execute nss process | 101 /** @brief get a restricted access token to execute nss process |
74 * | 102 * |
75 * This function uses the Software Restriction API to obtain the | 103 * This function uses the Software Restriction API to obtain the |
76 * access token for a process run als normal user. | 104 * access token for a process run als normal user. |
172 return true; | 200 return true; |
173 } | 201 } |
174 /**@brief Get the path to all users default registry hive | 202 /**@brief Get the path to all users default registry hive |
175 * | 203 * |
176 * Enumerates the keys in #PROFILE_LIST and retuns a | 204 * Enumerates the keys in #PROFILE_LIST and retuns a |
177 * strv array with the utf-8 encoded paths to their suggested | 205 * list of their profile path / sid pairs with the utf-8 encoded paths to |
178 * registry hive location. | 206 * their suggestedregistry hive location. |
179 * | 207 * |
180 * Users with an SID not starting with S-1-5-21- are ignored | 208 * Users with an SID not starting with S-1-5-21- are ignored |
181 * as is the current user. | 209 * as is the current user. |
182 * | 210 * |
183 * Use strv_free to free that array. | 211 * The return value should be freed with pkp_t_free |
184 * | 212 * |
185 * @returns a newly allocated strv of the paths to the registry hives or NULL | 213 * @returns a newly allocated strv of the paths to the registry hives or NULL |
186 */ | 214 */ |
187 static char** | 215 static pkp_t* |
188 locate_other_hives() | 216 locate_other_hives() |
189 { | 217 { |
190 HKEY profile_list = NULL; | 218 HKEY profile_list = NULL; |
191 int ret = 0; | 219 int ret = 0; |
192 DWORD index = 0, | 220 DWORD index = 0, |
196 a registry key is limited to 255 characters. But according to | 224 a registry key is limited to 255 characters. But according to |
197 http://www.sepago.de/e/holger/2010/07/20/how-long-can-a-registry-key-name-really-be | 225 http://www.sepago.de/e/holger/2010/07/20/how-long-can-a-registry-key-name-really-be |
198 the actual limit is 256 + \0 thus we create a buffer for 257 wchar_t's*/ | 226 the actual limit is 256 + \0 thus we create a buffer for 257 wchar_t's*/ |
199 wchar_t key_name[257], | 227 wchar_t key_name[257], |
200 *current_user_sid = NULL; | 228 *current_user_sid = NULL; |
201 char **retval = NULL; | 229 pkp_t *retval = NULL, |
230 *cur_item = NULL; | |
202 bool error = true; | 231 bool error = true; |
203 PSID current_user = NULL; | 232 PSID current_user = NULL; |
204 | 233 |
205 ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE, PROFILE_LIST, 0, | 234 ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE, PROFILE_LIST, 0, |
206 KEY_READ, &profile_list); | 235 KEY_READ, &profile_list); |
254 key_path_len = key_len + wcslen(PROFILE_LIST L"\\") + 1; | 283 key_path_len = key_len + wcslen(PROFILE_LIST L"\\") + 1; |
255 key_path = xmalloc (key_path_len * sizeof (wchar_t)); | 284 key_path = xmalloc (key_path_len * sizeof (wchar_t)); |
256 | 285 |
257 wcscpy_s (key_path, key_path_len, PROFILE_LIST L"\\"); | 286 wcscpy_s (key_path, key_path_len, PROFILE_LIST L"\\"); |
258 wcscat_s (key_path, key_path_len, key_name); | 287 wcscat_s (key_path, key_path_len, key_name); |
259 key_path[key_len - 1] = '\0'; | 288 key_path[key_path_len - 1] = '\0'; |
260 | 289 |
261 DEBUGPRINTF ("Key : %S", key_name); | 290 DEBUGPRINTF ("Key : %S", key_name); |
262 profile_path = read_registry_string (HKEY_LOCAL_MACHINE, | 291 profile_path = read_registry_string (HKEY_LOCAL_MACHINE, |
263 key_path, L"ProfileImagePath"); | 292 key_path, L"ProfileImagePath"); |
264 xfree (key_path); | 293 xfree (key_path); |
268 ERRORPRINTF ("Failed to get profile path."); | 297 ERRORPRINTF ("Failed to get profile path."); |
269 continue; | 298 continue; |
270 } | 299 } |
271 profile_path_len = strlen (profile_path); | 300 profile_path_len = strlen (profile_path); |
272 str_append_str (&profile_path, &profile_path_len, "\\ntuser.dat", 11); | 301 str_append_str (&profile_path, &profile_path_len, "\\ntuser.dat", 11); |
273 | 302 if (retval == NULL) |
274 strv_append (&retval, profile_path, profile_path_len); | 303 { |
304 retval = xmalloc (sizeof (pkp_t)); | |
305 cur_item = retval; | |
306 } | |
307 else | |
308 { | |
309 cur_item->next = xmalloc (sizeof(pkp_t)); | |
310 cur_item = cur_item->next; | |
311 } | |
312 cur_item->hive_path = profile_path; | |
313 cur_item->sid = wchar_to_utf8 (key_name, wcslen(key_name)); | |
314 cur_item->next = NULL; | |
315 | |
275 DEBUGPRINTF ("Trying to access registry hive: %s", profile_path); | 316 DEBUGPRINTF ("Trying to access registry hive: %s", profile_path); |
276 | |
277 xfree (profile_path); | |
278 } | 317 } |
279 | 318 |
280 if (ret != ERROR_NO_MORE_ITEMS) | 319 if (ret != ERROR_NO_MORE_ITEMS) |
281 { | 320 { |
282 ERRORPRINTF ("Failed to enumeratre profile list. Error: %i", ret); | 321 ERRORPRINTF ("Failed to enumeratre profile list. Error: %i", ret); |
295 LocalFree (current_user_sid); | 334 LocalFree (current_user_sid); |
296 } | 335 } |
297 | 336 |
298 if (error) | 337 if (error) |
299 { | 338 { |
300 strv_free (retval); | 339 pkp_t_free (retval); |
301 retval = NULL; | 340 retval = NULL; |
302 } | 341 } |
303 | 342 |
304 return retval; | 343 return retval; |
305 } | 344 } |
466 * the users install / remove selection. | 505 * the users install / remove selection. |
467 */ | 506 */ |
468 static void | 507 static void |
469 register_proccesses_for_others (wchar_t *selection_file) | 508 register_proccesses_for_others (wchar_t *selection_file) |
470 { | 509 { |
471 char **hives = locate_other_hives(); | 510 pkp_t *pkplist = locate_other_hives(), |
472 int i = 0; | 511 *cur = NULL; |
473 wchar_t *run_command = NULL; | 512 wchar_t *run_command = NULL; |
474 | 513 |
475 if (hives == NULL) | 514 if (pkplist == NULL) |
476 { | 515 { |
477 DEBUGPRINTF ("No hives found."); | 516 DEBUGPRINTF ("No hives found."); |
478 return; | 517 return; |
479 } | 518 } |
480 | 519 |
483 ERRORPRINTF ("Failed to obtain backup / restore privileges."); | 522 ERRORPRINTF ("Failed to obtain backup / restore privileges."); |
484 return; | 523 return; |
485 } | 524 } |
486 | 525 |
487 run_command = get_command_line (selection_file); | 526 run_command = get_command_line (selection_file); |
488 for (i = 0; hives[i] != NULL; i++) | 527 for (cur = pkplist; cur != NULL; cur = cur->next) |
489 { | 528 { |
490 LONG ret = 0; | 529 LONG ret = 0; |
491 wchar_t *hivepath = utf8_to_wchar (hives[i], strlen(hives[i])); | 530 wchar_t *hivepath = utf8_to_wchar (cur->hive_path, strlen(cur->hive_path)); |
492 HKEY key_handle = NULL; | 531 HKEY key_handle = NULL; |
532 bool key_loaded = false; | |
493 | 533 |
494 if (hivepath == NULL) | 534 if (hivepath == NULL) |
495 { | 535 { |
496 ERRORPRINTF ("Failed to read hive path"); | 536 ERRORPRINTF ("Failed to read hive path"); |
497 continue; | 537 continue; |
502 hivepath = NULL; | 542 hivepath = NULL; |
503 | 543 |
504 if (ret != ERROR_SUCCESS) | 544 if (ret != ERROR_SUCCESS) |
505 { | 545 { |
506 /* This is somewhat expected if the registry is not located | 546 /* This is somewhat expected if the registry is not located |
507 in the standard location. Failure is accepted in that case. */ | 547 in the standard location or already loaded. Try to access |
548 the loaded registry in that case*/ | |
549 wchar_t *user_key = NULL, | |
550 *w_sid = NULL; | |
551 size_t user_key_len = 0; | |
552 | |
508 SetLastError((DWORD)ret); | 553 SetLastError((DWORD)ret); |
509 PRINTLASTERROR ("Failed to load hive."); | 554 PRINTLASTERROR ("Failed to load hive. Trying to access already loaded hive."); |
510 continue; | 555 |
511 } | 556 w_sid = utf8_to_wchar (cur->sid, strlen(cur->sid)); |
512 | 557 if (!w_sid) |
513 ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE, | 558 { |
514 APPNAME L"_tmphive\\Software\\Microsoft\\Windows\\CurrentVersion\\RunOnce", | 559 ERRORPRINTF ("Failed to read sid."); |
515 0, | 560 continue; |
516 KEY_WRITE, | 561 } |
517 &key_handle); | 562 user_key_len = wcslen (L"\\" RUNONCE_PATH) + wcslen(w_sid) + 1; |
518 | 563 user_key = xmalloc (user_key_len * sizeof (wchar_t)); |
519 if (ret != ERROR_SUCCESS) | 564 wcscpy_s (user_key, user_key_len, w_sid); |
520 { | 565 wcscat_s (user_key, user_key_len, L"\\" RUNONCE_PATH); |
521 ERRORPRINTF ("Failed to find RunOnce key in other registry."); | 566 user_key[user_key_len - 1] = '\0'; |
522 RegUnLoadKey (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive"); | 567 xfree (w_sid); |
523 continue; | 568 w_sid = NULL; |
569 | |
570 ret = RegOpenKeyExW (HKEY_USERS, | |
571 user_key, | |
572 0, | |
573 KEY_WRITE, | |
574 &key_handle); | |
575 xfree (user_key); | |
576 if (ret != ERROR_SUCCESS) | |
577 { | |
578 ERRORPRINTF ("Failed to find RunOnce key for sid: %s in HKEY_USERS.", cur->sid); | |
579 continue; | |
580 } | |
581 } | |
582 else | |
583 { | |
584 key_loaded = true; | |
585 ret = RegOpenKeyExW (HKEY_LOCAL_MACHINE, | |
586 APPNAME L"_tmphive\\" RUNONCE_PATH, | |
587 0, | |
588 KEY_WRITE, | |
589 &key_handle); | |
590 | |
591 if (ret != ERROR_SUCCESS) | |
592 { | |
593 ERRORPRINTF ("Failed to find RunOnce key in other registry."); | |
594 RegUnLoadKey (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive"); | |
595 continue; | |
596 } | |
597 | |
524 } | 598 } |
525 | 599 |
526 ret = RegSetValueExW (key_handle, APPNAME, 0, REG_SZ, (LPBYTE) run_command, | 600 ret = RegSetValueExW (key_handle, APPNAME, 0, REG_SZ, (LPBYTE) run_command, |
527 (wcslen(run_command) + 1) * sizeof(wchar_t)); | 601 (wcslen(run_command) + 1) * sizeof(wchar_t)); |
528 | 602 |
530 { | 604 { |
531 ERRORPRINTF ("Failed to write RunOnce key."); | 605 ERRORPRINTF ("Failed to write RunOnce key."); |
532 } | 606 } |
533 | 607 |
534 RegCloseKey (key_handle); | 608 RegCloseKey (key_handle); |
535 ret = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive"); | 609 if (key_loaded) |
536 if (ret != ERROR_SUCCESS) | 610 { |
537 { | 611 ret = RegUnLoadKeyW (HKEY_LOCAL_MACHINE, APPNAME L"_tmphive"); |
538 SetLastError ((DWORD)ret); | 612 if (ret != ERROR_SUCCESS) |
539 PRINTLASTERROR ("Failed to unload hive."); | 613 { |
614 SetLastError ((DWORD)ret); | |
615 PRINTLASTERROR ("Failed to unload hive."); | |
616 } | |
540 } | 617 } |
541 } | 618 } |
542 | 619 |
543 xfree (run_command); | 620 xfree (run_command); |
544 strv_free (hives); | 621 pkp_t_free (pkplist); |
545 } | 622 } |
546 | 623 |
547 /**@brief Start the process to install / remove | 624 /**@brief Start the process to install / remove |
548 * | 625 * |
549 * Starts the NSS installation process for the current user | 626 * Starts the NSS installation process for the current user |