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

http://wald.intevation.org/projects/trustbridge/