1 /* 2 * PROJECT: ReactOS Service Control Manager 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/system/services/database.c 5 * PURPOSE: Database control interface 6 * COPYRIGHT: Copyright 2002-2006 Eric Kohl 7 * Copyright 2006 Herv� Poussineau <hpoussin@reactos.org> 8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 9 * Gregor Brunmar <gregor.brunmar@home.se> 10 * 11 */ 12 13 /* INCLUDES *****************************************************************/ 14 15 #include "services.h" 16 17 #include <userenv.h> 18 #include <strsafe.h> 19 20 #include <reactos/undocuser.h> 21 22 #define NDEBUG 23 #include <debug.h> 24 25 26 /* GLOBALS *******************************************************************/ 27 28 LIST_ENTRY ImageListHead; 29 LIST_ENTRY ServiceListHead; 30 31 static RTL_RESOURCE DatabaseLock; 32 static DWORD ResumeCount = 1; 33 static DWORD NoInteractiveServices = 0; 34 35 /* The critical section synchronizes service control requests */ 36 static CRITICAL_SECTION ControlServiceCriticalSection; 37 static DWORD PipeTimeout = 30000; /* 30 Seconds */ 38 39 40 /* FUNCTIONS *****************************************************************/ 41 42 static DWORD 43 ScmCreateNewControlPipe(PSERVICE_IMAGE pServiceImage) 44 { 45 WCHAR szControlPipeName[MAX_PATH + 1]; 46 HKEY hServiceCurrentKey = INVALID_HANDLE_VALUE; 47 DWORD ServiceCurrent = 0; 48 DWORD KeyDisposition; 49 DWORD dwKeySize; 50 DWORD dwError; 51 52 /* Get the service number */ 53 /* TODO: Create registry entry with correct write access */ 54 dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, 55 L"SYSTEM\\CurrentControlSet\\Control\\ServiceCurrent", 0, NULL, 56 REG_OPTION_VOLATILE, 57 KEY_WRITE | KEY_READ, 58 NULL, 59 &hServiceCurrentKey, 60 &KeyDisposition); 61 if (dwError != ERROR_SUCCESS) 62 { 63 DPRINT1("RegCreateKeyEx() failed with error %lu\n", dwError); 64 return dwError; 65 } 66 67 if (KeyDisposition == REG_OPENED_EXISTING_KEY) 68 { 69 dwKeySize = sizeof(DWORD); 70 dwError = RegQueryValueExW(hServiceCurrentKey, 71 L"", 0, NULL, (BYTE*)&ServiceCurrent, &dwKeySize); 72 73 if (dwError != ERROR_SUCCESS) 74 { 75 RegCloseKey(hServiceCurrentKey); 76 DPRINT1("RegQueryValueEx() failed with error %lu\n", dwError); 77 return dwError; 78 } 79 80 ServiceCurrent++; 81 } 82 83 dwError = RegSetValueExW(hServiceCurrentKey, L"", 0, REG_DWORD, (BYTE*)&ServiceCurrent, sizeof(ServiceCurrent)); 84 85 RegCloseKey(hServiceCurrentKey); 86 87 if (dwError != ERROR_SUCCESS) 88 { 89 DPRINT1("RegSetValueExW() failed (Error %lu)\n", dwError); 90 return dwError; 91 } 92 93 /* Create '\\.\pipe\net\NtControlPipeXXX' instance */ 94 StringCchPrintfW(szControlPipeName, ARRAYSIZE(szControlPipeName), 95 L"\\\\.\\pipe\\net\\NtControlPipe%lu", ServiceCurrent); 96 97 DPRINT("PipeName: %S\n", szControlPipeName); 98 99 pServiceImage->hControlPipe = CreateNamedPipeW(szControlPipeName, 100 PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, 101 PIPE_TYPE_MESSAGE | PIPE_READMODE_MESSAGE | PIPE_WAIT, 102 100, 103 8000, 104 4, 105 PipeTimeout, 106 NULL); 107 DPRINT("CreateNamedPipeW(%S) done\n", szControlPipeName); 108 if (pServiceImage->hControlPipe == INVALID_HANDLE_VALUE) 109 { 110 DPRINT1("Failed to create control pipe!\n"); 111 return GetLastError(); 112 } 113 114 return ERROR_SUCCESS; 115 } 116 117 118 static PSERVICE_IMAGE 119 ScmGetServiceImageByImagePath(LPWSTR lpImagePath) 120 { 121 PLIST_ENTRY ImageEntry; 122 PSERVICE_IMAGE CurrentImage; 123 124 DPRINT("ScmGetServiceImageByImagePath(%S) called\n", lpImagePath); 125 126 ImageEntry = ImageListHead.Flink; 127 while (ImageEntry != &ImageListHead) 128 { 129 CurrentImage = CONTAINING_RECORD(ImageEntry, 130 SERVICE_IMAGE, 131 ImageListEntry); 132 if (_wcsicmp(CurrentImage->pszImagePath, lpImagePath) == 0) 133 { 134 DPRINT("Found image: '%S'\n", CurrentImage->pszImagePath); 135 return CurrentImage; 136 } 137 138 ImageEntry = ImageEntry->Flink; 139 } 140 141 DPRINT("Couldn't find a matching image\n"); 142 143 return NULL; 144 145 } 146 147 148 static 149 BOOL 150 ScmIsSameServiceAccount( 151 _In_ PCWSTR pszAccountName1, 152 _In_ PCWSTR pszAccountName2) 153 { 154 if (pszAccountName1 == NULL && 155 pszAccountName2 == NULL) 156 return TRUE; 157 158 if (pszAccountName1 == NULL && 159 pszAccountName2 != NULL && 160 _wcsicmp(pszAccountName2, L"LocalSystem") == 0) 161 return TRUE; 162 163 if (pszAccountName1 != NULL && 164 pszAccountName2 == NULL && 165 _wcsicmp(pszAccountName1, L"LocalSystem") == 0) 166 return TRUE; 167 168 if (pszAccountName1 != NULL && 169 pszAccountName2 != NULL && 170 _wcsicmp(pszAccountName1, pszAccountName2) == 0) 171 return TRUE; 172 173 return FALSE; 174 } 175 176 177 static 178 BOOL 179 ScmIsLocalSystemAccount( 180 _In_ PCWSTR pszAccountName) 181 { 182 if (pszAccountName == NULL || 183 _wcsicmp(pszAccountName, L"LocalSystem") == 0) 184 return TRUE; 185 186 return FALSE; 187 } 188 189 190 static 191 DWORD 192 ScmLogonService( 193 IN PSERVICE pService, 194 IN PSERVICE_IMAGE pImage) 195 { 196 DWORD dwError = ERROR_SUCCESS; 197 PROFILEINFOW ProfileInfo; 198 PWSTR pszUserName = NULL; 199 PWSTR pszDomainName = NULL; 200 PWSTR pszPassword = NULL; 201 PWSTR ptr; 202 203 DPRINT("ScmLogonService(%p %p)\n", pService, pImage); 204 DPRINT("Service %S\n", pService->lpServiceName); 205 206 if (ScmIsLocalSystemAccount(pImage->pszAccountName)) 207 return ERROR_SUCCESS; 208 209 /* Get the user and domain names */ 210 ptr = wcschr(pImage->pszAccountName, L'\\'); 211 if (ptr != NULL) 212 { 213 *ptr = L'\0'; 214 pszUserName = ptr + 1; 215 pszDomainName = pImage->pszAccountName; 216 } 217 else 218 { 219 // ERROR_INVALID_SERVICE_ACCOUNT 220 pszUserName = pImage->pszAccountName; 221 pszDomainName = NULL; 222 } 223 224 /* Build the service 'password' */ 225 pszPassword = HeapAlloc(GetProcessHeap(), 226 HEAP_ZERO_MEMORY, 227 (wcslen(pService->lpServiceName) + 5) * sizeof(WCHAR)); 228 if (pszPassword == NULL) 229 { 230 dwError = ERROR_NOT_ENOUGH_MEMORY; 231 goto done; 232 } 233 234 wcscpy(pszPassword, L"_SC_"); 235 wcscat(pszPassword, pService->lpServiceName); 236 237 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName, pszUserName, pszPassword); 238 239 /* Do the service logon */ 240 if (!LogonUserW(pszUserName, 241 pszDomainName, 242 pszPassword, 243 LOGON32_LOGON_SERVICE, 244 LOGON32_PROVIDER_DEFAULT, 245 &pImage->hToken)) 246 { 247 dwError = GetLastError(); 248 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError); 249 250 /* Normalize the returned error */ 251 dwError = ERROR_SERVICE_LOGON_FAILED; 252 goto done; 253 } 254 255 /* Load the user profile; the per-user environment variables are thus correctly initialized */ 256 ZeroMemory(&ProfileInfo, sizeof(ProfileInfo)); 257 ProfileInfo.dwSize = sizeof(ProfileInfo); 258 ProfileInfo.dwFlags = PI_NOUI; 259 ProfileInfo.lpUserName = pszUserName; 260 // ProfileInfo.lpProfilePath = NULL; 261 // ProfileInfo.lpDefaultPath = NULL; 262 // ProfileInfo.lpServerName = NULL; 263 // ProfileInfo.lpPolicyPath = NULL; 264 // ProfileInfo.hProfile = NULL; 265 266 if (!LoadUserProfileW(pImage->hToken, &ProfileInfo)) 267 { 268 dwError = GetLastError(); 269 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError); 270 goto done; 271 } 272 273 pImage->hProfile = ProfileInfo.hProfile; 274 275 done: 276 if (pszPassword != NULL) 277 HeapFree(GetProcessHeap(), 0, pszPassword); 278 279 if (ptr != NULL) 280 *ptr = L'\\'; 281 282 return dwError; 283 } 284 285 286 static DWORD 287 ScmCreateOrReferenceServiceImage(PSERVICE pService) 288 { 289 RTL_QUERY_REGISTRY_TABLE QueryTable[3]; 290 UNICODE_STRING ImagePath; 291 UNICODE_STRING ObjectName; 292 PSERVICE_IMAGE pServiceImage = NULL; 293 NTSTATUS Status; 294 DWORD dwError = ERROR_SUCCESS; 295 DWORD dwRecordSize; 296 LPWSTR pString; 297 298 DPRINT("ScmCreateOrReferenceServiceImage(%p)\n", pService); 299 300 RtlInitUnicodeString(&ImagePath, NULL); 301 RtlInitUnicodeString(&ObjectName, NULL); 302 303 /* Get service data */ 304 RtlZeroMemory(&QueryTable, 305 sizeof(QueryTable)); 306 307 QueryTable[0].Name = L"ImagePath"; 308 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 309 QueryTable[0].EntryContext = &ImagePath; 310 QueryTable[1].Name = L"ObjectName"; 311 QueryTable[1].Flags = RTL_QUERY_REGISTRY_DIRECT; 312 QueryTable[1].EntryContext = &ObjectName; 313 314 Status = RtlQueryRegistryValues(RTL_REGISTRY_SERVICES, 315 pService->lpServiceName, 316 QueryTable, 317 NULL, 318 NULL); 319 if (!NT_SUCCESS(Status)) 320 { 321 DPRINT1("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 322 return RtlNtStatusToDosError(Status); 323 } 324 325 DPRINT("ImagePath: '%wZ'\n", &ImagePath); 326 DPRINT("ObjectName: '%wZ'\n", &ObjectName); 327 328 pServiceImage = ScmGetServiceImageByImagePath(ImagePath.Buffer); 329 if (pServiceImage == NULL) 330 { 331 dwRecordSize = sizeof(SERVICE_IMAGE) + 332 ImagePath.Length + sizeof(WCHAR) + 333 ((ObjectName.Length != 0) ? (ObjectName.Length + sizeof(WCHAR)) : 0); 334 335 /* Create a new service image */ 336 pServiceImage = HeapAlloc(GetProcessHeap(), 337 HEAP_ZERO_MEMORY, 338 dwRecordSize); 339 if (pServiceImage == NULL) 340 { 341 dwError = ERROR_NOT_ENOUGH_MEMORY; 342 goto done; 343 } 344 345 pServiceImage->dwImageRunCount = 1; 346 pServiceImage->hControlPipe = INVALID_HANDLE_VALUE; 347 pServiceImage->hProcess = INVALID_HANDLE_VALUE; 348 349 pString = (PWSTR)((INT_PTR)pServiceImage + sizeof(SERVICE_IMAGE)); 350 351 /* Set the image path */ 352 pServiceImage->pszImagePath = pString; 353 wcscpy(pServiceImage->pszImagePath, 354 ImagePath.Buffer); 355 356 /* Set the account name */ 357 if (ObjectName.Length > 0) 358 { 359 pString = pString + wcslen(pString) + 1; 360 361 pServiceImage->pszAccountName = pString; 362 wcscpy(pServiceImage->pszAccountName, 363 ObjectName.Buffer); 364 } 365 366 /* Service logon */ 367 dwError = ScmLogonService(pService, pServiceImage); 368 if (dwError != ERROR_SUCCESS) 369 { 370 DPRINT1("ScmLogonService() failed (Error %lu)\n", dwError); 371 372 /* Release the service image */ 373 HeapFree(GetProcessHeap(), 0, pServiceImage); 374 375 goto done; 376 } 377 378 /* Create the control pipe */ 379 dwError = ScmCreateNewControlPipe(pServiceImage); 380 if (dwError != ERROR_SUCCESS) 381 { 382 DPRINT1("ScmCreateNewControlPipe() failed (Error %lu)\n", dwError); 383 384 /* Unload the user profile */ 385 if (pServiceImage->hProfile != NULL) 386 UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile); 387 388 /* Close the logon token */ 389 if (pServiceImage->hToken != NULL) 390 CloseHandle(pServiceImage->hToken); 391 392 /* Release the service image */ 393 HeapFree(GetProcessHeap(), 0, pServiceImage); 394 395 goto done; 396 } 397 398 /* FIXME: Add more initialization code here */ 399 400 401 /* Append service record */ 402 InsertTailList(&ImageListHead, 403 &pServiceImage->ImageListEntry); 404 } 405 else 406 { 407 // if ((lpService->Status.dwServiceType & SERVICE_WIN32_SHARE_PROCESS) == 0) 408 409 /* Fail if services in an image use different accounts */ 410 if (!ScmIsSameServiceAccount(pServiceImage->pszAccountName, ObjectName.Buffer)) 411 { 412 dwError = ERROR_DIFFERENT_SERVICE_ACCOUNT; 413 goto done; 414 } 415 416 /* Increment the run counter */ 417 pServiceImage->dwImageRunCount++; 418 } 419 420 DPRINT("pServiceImage->pszImagePath: %S\n", pServiceImage->pszImagePath); 421 DPRINT("pServiceImage->pszAccountName: %S\n", pServiceImage->pszAccountName); 422 DPRINT("pServiceImage->dwImageRunCount: %lu\n", pServiceImage->dwImageRunCount); 423 424 /* Link the service image to the service */ 425 pService->lpImage = pServiceImage; 426 427 done: 428 RtlFreeUnicodeString(&ObjectName); 429 RtlFreeUnicodeString(&ImagePath); 430 431 DPRINT("ScmCreateOrReferenceServiceImage() done (Error: %lu)\n", dwError); 432 433 return dwError; 434 } 435 436 437 VOID 438 ScmRemoveServiceImage(PSERVICE_IMAGE pServiceImage) 439 { 440 DPRINT1("ScmRemoveServiceImage() called\n"); 441 442 /* FIXME: Terminate the process */ 443 444 /* Remove the service image from the list */ 445 RemoveEntryList(&pServiceImage->ImageListEntry); 446 447 /* Close the process handle */ 448 if (pServiceImage->hProcess != INVALID_HANDLE_VALUE) 449 CloseHandle(pServiceImage->hProcess); 450 451 /* Close the control pipe */ 452 if (pServiceImage->hControlPipe != INVALID_HANDLE_VALUE) 453 CloseHandle(pServiceImage->hControlPipe); 454 455 /* Unload the user profile */ 456 if (pServiceImage->hProfile != NULL) 457 UnloadUserProfile(pServiceImage->hToken, pServiceImage->hProfile); 458 459 /* Close the logon token */ 460 if (pServiceImage->hToken != NULL) 461 CloseHandle(pServiceImage->hToken); 462 463 /* Release the service image */ 464 HeapFree(GetProcessHeap(), 0, pServiceImage); 465 } 466 467 468 PSERVICE 469 ScmGetServiceEntryByName(LPCWSTR lpServiceName) 470 { 471 PLIST_ENTRY ServiceEntry; 472 PSERVICE CurrentService; 473 474 DPRINT("ScmGetServiceEntryByName() called\n"); 475 476 ServiceEntry = ServiceListHead.Flink; 477 while (ServiceEntry != &ServiceListHead) 478 { 479 CurrentService = CONTAINING_RECORD(ServiceEntry, 480 SERVICE, 481 ServiceListEntry); 482 if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0) 483 { 484 DPRINT("Found service: '%S'\n", CurrentService->lpServiceName); 485 return CurrentService; 486 } 487 488 ServiceEntry = ServiceEntry->Flink; 489 } 490 491 DPRINT("Couldn't find a matching service\n"); 492 493 return NULL; 494 } 495 496 497 PSERVICE 498 ScmGetServiceEntryByDisplayName(LPCWSTR lpDisplayName) 499 { 500 PLIST_ENTRY ServiceEntry; 501 PSERVICE CurrentService; 502 503 DPRINT("ScmGetServiceEntryByDisplayName() called\n"); 504 505 ServiceEntry = ServiceListHead.Flink; 506 while (ServiceEntry != &ServiceListHead) 507 { 508 CurrentService = CONTAINING_RECORD(ServiceEntry, 509 SERVICE, 510 ServiceListEntry); 511 if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0) 512 { 513 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); 514 return CurrentService; 515 } 516 517 ServiceEntry = ServiceEntry->Flink; 518 } 519 520 DPRINT("Couldn't find a matching service\n"); 521 522 return NULL; 523 } 524 525 526 PSERVICE 527 ScmGetServiceEntryByResumeCount(DWORD dwResumeCount) 528 { 529 PLIST_ENTRY ServiceEntry; 530 PSERVICE CurrentService; 531 532 DPRINT("ScmGetServiceEntryByResumeCount() called\n"); 533 534 ServiceEntry = ServiceListHead.Flink; 535 while (ServiceEntry != &ServiceListHead) 536 { 537 CurrentService = CONTAINING_RECORD(ServiceEntry, 538 SERVICE, 539 ServiceListEntry); 540 if (CurrentService->dwResumeCount > dwResumeCount) 541 { 542 DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName); 543 return CurrentService; 544 } 545 546 ServiceEntry = ServiceEntry->Flink; 547 } 548 549 DPRINT("Couldn't find a matching service\n"); 550 551 return NULL; 552 } 553 554 555 DWORD 556 ScmCreateNewServiceRecord(LPCWSTR lpServiceName, 557 PSERVICE *lpServiceRecord, 558 DWORD dwServiceType, 559 DWORD dwStartType) 560 { 561 PSERVICE lpService = NULL; 562 563 DPRINT("Service: '%S'\n", lpServiceName); 564 565 /* Allocate service entry */ 566 lpService = HeapAlloc(GetProcessHeap(), 567 HEAP_ZERO_MEMORY, 568 FIELD_OFFSET(SERVICE, szServiceName[wcslen(lpServiceName) + 1])); 569 if (lpService == NULL) 570 return ERROR_NOT_ENOUGH_MEMORY; 571 572 *lpServiceRecord = lpService; 573 574 /* Copy service name */ 575 wcscpy(lpService->szServiceName, lpServiceName); 576 lpService->lpServiceName = lpService->szServiceName; 577 lpService->lpDisplayName = lpService->lpServiceName; 578 579 /* Set the start type */ 580 lpService->dwStartType = dwStartType; 581 582 /* Set the resume count */ 583 lpService->dwResumeCount = ResumeCount++; 584 585 /* Append service record */ 586 InsertTailList(&ServiceListHead, 587 &lpService->ServiceListEntry); 588 589 /* Initialize the service status */ 590 lpService->Status.dwServiceType = dwServiceType; 591 lpService->Status.dwCurrentState = SERVICE_STOPPED; 592 lpService->Status.dwControlsAccepted = 0; 593 lpService->Status.dwWin32ExitCode = 594 (dwStartType == SERVICE_DISABLED) ? ERROR_SERVICE_DISABLED : ERROR_SERVICE_NEVER_STARTED; 595 lpService->Status.dwServiceSpecificExitCode = 0; 596 lpService->Status.dwCheckPoint = 0; 597 lpService->Status.dwWaitHint = 598 (dwServiceType & SERVICE_DRIVER) ? 0 : 2000; /* 2 seconds */ 599 600 return ERROR_SUCCESS; 601 } 602 603 604 VOID 605 ScmDeleteServiceRecord(PSERVICE lpService) 606 { 607 DPRINT("Deleting Service %S\n", lpService->lpServiceName); 608 609 /* Delete the display name */ 610 if (lpService->lpDisplayName != NULL && 611 lpService->lpDisplayName != lpService->lpServiceName) 612 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); 613 614 /* Dereference the service image */ 615 if (lpService->lpImage) 616 { 617 lpService->lpImage->dwImageRunCount--; 618 619 if (lpService->lpImage->dwImageRunCount == 0) 620 { 621 ScmRemoveServiceImage(lpService->lpImage); 622 lpService->lpImage = NULL; 623 } 624 } 625 626 /* Decrement the group reference counter */ 627 ScmSetServiceGroup(lpService, NULL); 628 629 /* Release the SecurityDescriptor */ 630 if (lpService->pSecurityDescriptor != NULL) 631 HeapFree(GetProcessHeap(), 0, lpService->pSecurityDescriptor); 632 633 /* Remove the Service from the List */ 634 RemoveEntryList(&lpService->ServiceListEntry); 635 636 DPRINT("Deleted Service %S\n", lpService->lpServiceName); 637 638 /* Delete the service record */ 639 HeapFree(GetProcessHeap(), 0, lpService); 640 641 DPRINT("Done\n"); 642 } 643 644 645 static DWORD 646 CreateServiceListEntry(LPCWSTR lpServiceName, 647 HKEY hServiceKey) 648 { 649 PSERVICE lpService = NULL; 650 LPWSTR lpDisplayName = NULL; 651 LPWSTR lpGroup = NULL; 652 DWORD dwSize; 653 DWORD dwError; 654 DWORD dwServiceType; 655 DWORD dwStartType; 656 DWORD dwErrorControl; 657 DWORD dwTagId; 658 659 DPRINT("Service: '%S'\n", lpServiceName); 660 if (*lpServiceName == L'{') 661 return ERROR_SUCCESS; 662 663 dwSize = sizeof(DWORD); 664 dwError = RegQueryValueExW(hServiceKey, 665 L"Type", 666 NULL, 667 NULL, 668 (LPBYTE)&dwServiceType, 669 &dwSize); 670 if (dwError != ERROR_SUCCESS) 671 return ERROR_SUCCESS; 672 673 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && 674 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) && 675 (dwServiceType != SERVICE_KERNEL_DRIVER) && 676 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) 677 return ERROR_SUCCESS; 678 679 DPRINT("Service type: %lx\n", dwServiceType); 680 681 dwSize = sizeof(DWORD); 682 dwError = RegQueryValueExW(hServiceKey, 683 L"Start", 684 NULL, 685 NULL, 686 (LPBYTE)&dwStartType, 687 &dwSize); 688 if (dwError != ERROR_SUCCESS) 689 return ERROR_SUCCESS; 690 691 DPRINT("Start type: %lx\n", dwStartType); 692 693 dwSize = sizeof(DWORD); 694 dwError = RegQueryValueExW(hServiceKey, 695 L"ErrorControl", 696 NULL, 697 NULL, 698 (LPBYTE)&dwErrorControl, 699 &dwSize); 700 if (dwError != ERROR_SUCCESS) 701 return ERROR_SUCCESS; 702 703 DPRINT("Error control: %lx\n", dwErrorControl); 704 705 dwError = RegQueryValueExW(hServiceKey, 706 L"Tag", 707 NULL, 708 NULL, 709 (LPBYTE)&dwTagId, 710 &dwSize); 711 if (dwError != ERROR_SUCCESS) 712 dwTagId = 0; 713 714 DPRINT("Tag: %lx\n", dwTagId); 715 716 dwError = ScmReadString(hServiceKey, 717 L"Group", 718 &lpGroup); 719 if (dwError != ERROR_SUCCESS) 720 lpGroup = NULL; 721 722 DPRINT("Group: %S\n", lpGroup); 723 724 dwError = ScmReadString(hServiceKey, 725 L"DisplayName", 726 &lpDisplayName); 727 if (dwError != ERROR_SUCCESS) 728 lpDisplayName = NULL; 729 730 DPRINT("Display name: %S\n", lpDisplayName); 731 732 dwError = ScmCreateNewServiceRecord(lpServiceName, 733 &lpService, 734 dwServiceType, 735 dwStartType); 736 if (dwError != ERROR_SUCCESS) 737 goto done; 738 739 lpService->dwErrorControl = dwErrorControl; 740 lpService->dwTag = dwTagId; 741 742 if (lpGroup != NULL) 743 { 744 dwError = ScmSetServiceGroup(lpService, lpGroup); 745 if (dwError != ERROR_SUCCESS) 746 goto done; 747 } 748 749 if (lpDisplayName != NULL) 750 { 751 lpService->lpDisplayName = lpDisplayName; 752 lpDisplayName = NULL; 753 } 754 755 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName); 756 if (lpService->lpGroup != NULL) 757 { 758 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName); 759 } 760 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n", 761 lpService->dwStartType, 762 lpService->Status.dwServiceType, 763 lpService->dwTag, 764 lpService->dwErrorControl); 765 766 if (ScmIsDeleteFlagSet(hServiceKey)) 767 lpService->bDeleted = TRUE; 768 769 if (lpService->Status.dwServiceType & SERVICE_WIN32) 770 { 771 dwError = ScmReadSecurityDescriptor(hServiceKey, 772 &lpService->pSecurityDescriptor); 773 if (dwError != ERROR_SUCCESS) 774 goto done; 775 776 /* Assing the default security descriptor if the security descriptor cannot be read */ 777 if (lpService->pSecurityDescriptor == NULL) 778 { 779 DPRINT("No security descriptor found! Assign default security descriptor!\n"); 780 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor); 781 if (dwError != ERROR_SUCCESS) 782 goto done; 783 784 dwError = ScmWriteSecurityDescriptor(hServiceKey, 785 lpService->pSecurityDescriptor); 786 if (dwError != ERROR_SUCCESS) 787 goto done; 788 } 789 } 790 791 done: 792 if (lpGroup != NULL) 793 HeapFree(GetProcessHeap(), 0, lpGroup); 794 795 if (lpDisplayName != NULL) 796 HeapFree(GetProcessHeap(), 0, lpDisplayName); 797 798 if (lpService != NULL) 799 { 800 ASSERT(lpService->lpImage == NULL); 801 } 802 803 return dwError; 804 } 805 806 807 VOID 808 ScmDeleteMarkedServices(VOID) 809 { 810 PLIST_ENTRY ServiceEntry; 811 PSERVICE CurrentService; 812 HKEY hServicesKey; 813 DWORD dwError; 814 815 ServiceEntry = ServiceListHead.Flink; 816 while (ServiceEntry != &ServiceListHead) 817 { 818 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 819 820 ServiceEntry = ServiceEntry->Flink; 821 822 if (CurrentService->bDeleted != FALSE) 823 { 824 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 825 L"System\\CurrentControlSet\\Services", 826 0, 827 DELETE, 828 &hServicesKey); 829 if (dwError == ERROR_SUCCESS) 830 { 831 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName); 832 RegCloseKey(hServicesKey); 833 if (dwError == ERROR_SUCCESS) 834 { 835 RemoveEntryList(&CurrentService->ServiceListEntry); 836 HeapFree(GetProcessHeap(), 0, CurrentService); 837 } 838 } 839 840 if (dwError != ERROR_SUCCESS) 841 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName); 842 } 843 } 844 } 845 846 847 static 848 VOID 849 ScmGetNoInteractiveServicesValue(VOID) 850 { 851 HKEY hKey; 852 DWORD dwKeySize; 853 LONG lError; 854 855 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 856 L"SYSTEM\\CurrentControlSet\\Control\\Windows", 857 0, 858 KEY_READ, 859 &hKey); 860 if (lError == ERROR_SUCCESS) 861 { 862 dwKeySize = sizeof(NoInteractiveServices); 863 lError = RegQueryValueExW(hKey, 864 L"NoInteractiveServices", 865 0, 866 NULL, 867 (LPBYTE)&NoInteractiveServices, 868 &dwKeySize); 869 RegCloseKey(hKey); 870 } 871 } 872 873 874 DWORD 875 ScmCreateServiceDatabase(VOID) 876 { 877 WCHAR szSubKey[MAX_PATH]; 878 HKEY hServicesKey; 879 HKEY hServiceKey; 880 DWORD dwSubKey; 881 DWORD dwSubKeyLength; 882 FILETIME ftLastChanged; 883 DWORD dwError; 884 885 DPRINT("ScmCreateServiceDatabase() called\n"); 886 887 /* Retrieve the NoInteractiveServies value */ 888 ScmGetNoInteractiveServicesValue(); 889 890 /* Create the service group list */ 891 dwError = ScmCreateGroupList(); 892 if (dwError != ERROR_SUCCESS) 893 return dwError; 894 895 /* Initialize image and service lists */ 896 InitializeListHead(&ImageListHead); 897 InitializeListHead(&ServiceListHead); 898 899 /* Initialize the database lock */ 900 RtlInitializeResource(&DatabaseLock); 901 902 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 903 L"System\\CurrentControlSet\\Services", 904 0, 905 KEY_READ, 906 &hServicesKey); 907 if (dwError != ERROR_SUCCESS) 908 return dwError; 909 910 dwSubKey = 0; 911 for (;;) 912 { 913 dwSubKeyLength = MAX_PATH; 914 dwError = RegEnumKeyExW(hServicesKey, 915 dwSubKey, 916 szSubKey, 917 &dwSubKeyLength, 918 NULL, 919 NULL, 920 NULL, 921 &ftLastChanged); 922 if (dwError == ERROR_SUCCESS && 923 szSubKey[0] != L'{') 924 { 925 DPRINT("SubKeyName: '%S'\n", szSubKey); 926 927 dwError = RegOpenKeyExW(hServicesKey, 928 szSubKey, 929 0, 930 KEY_READ, 931 &hServiceKey); 932 if (dwError == ERROR_SUCCESS) 933 { 934 dwError = CreateServiceListEntry(szSubKey, 935 hServiceKey); 936 937 RegCloseKey(hServiceKey); 938 } 939 } 940 941 if (dwError != ERROR_SUCCESS) 942 break; 943 944 dwSubKey++; 945 } 946 947 RegCloseKey(hServicesKey); 948 949 /* Wait for the LSA server */ 950 ScmWaitForLsa(); 951 952 /* Delete services that are marked for delete */ 953 ScmDeleteMarkedServices(); 954 955 DPRINT("ScmCreateServiceDatabase() done\n"); 956 957 return ERROR_SUCCESS; 958 } 959 960 961 VOID 962 ScmShutdownServiceDatabase(VOID) 963 { 964 DPRINT("ScmShutdownServiceDatabase() called\n"); 965 966 ScmDeleteMarkedServices(); 967 RtlDeleteResource(&DatabaseLock); 968 969 DPRINT("ScmShutdownServiceDatabase() done\n"); 970 } 971 972 973 static NTSTATUS 974 ScmCheckDriver(PSERVICE Service) 975 { 976 OBJECT_ATTRIBUTES ObjectAttributes; 977 UNICODE_STRING DirName; 978 HANDLE DirHandle; 979 NTSTATUS Status; 980 POBJECT_DIRECTORY_INFORMATION DirInfo; 981 ULONG BufferLength; 982 ULONG DataLength; 983 ULONG Index; 984 985 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName); 986 987 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) 988 { 989 RtlInitUnicodeString(&DirName, L"\\Driver"); 990 } 991 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) 992 { 993 ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER); 994 RtlInitUnicodeString(&DirName, L"\\FileSystem"); 995 } 996 997 InitializeObjectAttributes(&ObjectAttributes, 998 &DirName, 999 0, 1000 NULL, 1001 NULL); 1002 1003 Status = NtOpenDirectoryObject(&DirHandle, 1004 DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 1005 &ObjectAttributes); 1006 if (!NT_SUCCESS(Status)) 1007 { 1008 return Status; 1009 } 1010 1011 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + 1012 2 * MAX_PATH * sizeof(WCHAR); 1013 DirInfo = HeapAlloc(GetProcessHeap(), 1014 HEAP_ZERO_MEMORY, 1015 BufferLength); 1016 1017 Index = 0; 1018 while (TRUE) 1019 { 1020 Status = NtQueryDirectoryObject(DirHandle, 1021 DirInfo, 1022 BufferLength, 1023 TRUE, 1024 FALSE, 1025 &Index, 1026 &DataLength); 1027 if (Status == STATUS_NO_MORE_ENTRIES) 1028 { 1029 /* FIXME: Add current service to 'failed service' list */ 1030 DPRINT("Service '%S' failed\n", Service->lpServiceName); 1031 break; 1032 } 1033 1034 if (!NT_SUCCESS(Status)) 1035 break; 1036 1037 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name); 1038 1039 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0) 1040 { 1041 DPRINT("Found: '%S' '%wZ'\n", 1042 Service->lpServiceName, &DirInfo->Name); 1043 1044 /* Mark service as 'running' */ 1045 Service->Status.dwCurrentState = SERVICE_RUNNING; 1046 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 1047 Service->Status.dwWin32ExitCode = ERROR_SUCCESS; 1048 Service->Status.dwServiceSpecificExitCode = 0; 1049 Service->Status.dwCheckPoint = 0; 1050 Service->Status.dwWaitHint = 0; 1051 1052 /* Mark the service group as 'running' */ 1053 if (Service->lpGroup != NULL) 1054 { 1055 Service->lpGroup->ServicesRunning = TRUE; 1056 } 1057 1058 break; 1059 } 1060 } 1061 1062 HeapFree(GetProcessHeap(), 1063 0, 1064 DirInfo); 1065 NtClose(DirHandle); 1066 1067 return STATUS_SUCCESS; 1068 } 1069 1070 1071 VOID 1072 ScmGetBootAndSystemDriverState(VOID) 1073 { 1074 PLIST_ENTRY ServiceEntry; 1075 PSERVICE CurrentService; 1076 1077 DPRINT("ScmGetBootAndSystemDriverState() called\n"); 1078 1079 ServiceEntry = ServiceListHead.Flink; 1080 while (ServiceEntry != &ServiceListHead) 1081 { 1082 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 1083 1084 if (CurrentService->dwStartType == SERVICE_BOOT_START || 1085 CurrentService->dwStartType == SERVICE_SYSTEM_START) 1086 { 1087 /* Check driver */ 1088 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName); 1089 1090 ScmCheckDriver(CurrentService); 1091 } 1092 1093 ServiceEntry = ServiceEntry->Flink; 1094 } 1095 1096 DPRINT("ScmGetBootAndSystemDriverState() done\n"); 1097 } 1098 1099 1100 DWORD 1101 ScmControlService(HANDLE hControlPipe, 1102 PWSTR pServiceName, 1103 SERVICE_STATUS_HANDLE hServiceStatus, 1104 DWORD dwControl) 1105 { 1106 PSCM_CONTROL_PACKET ControlPacket; 1107 SCM_REPLY_PACKET ReplyPacket; 1108 1109 DWORD dwWriteCount = 0; 1110 DWORD dwReadCount = 0; 1111 DWORD PacketSize; 1112 PWSTR Ptr; 1113 DWORD dwError = ERROR_SUCCESS; 1114 BOOL bResult; 1115 OVERLAPPED Overlapped = {0}; 1116 1117 DPRINT("ScmControlService() called\n"); 1118 1119 /* Acquire the service control critical section, to synchronize requests */ 1120 EnterCriticalSection(&ControlServiceCriticalSection); 1121 1122 /* Calculate the total length of the start command line */ 1123 PacketSize = sizeof(SCM_CONTROL_PACKET); 1124 PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR)); 1125 1126 ControlPacket = HeapAlloc(GetProcessHeap(), 1127 HEAP_ZERO_MEMORY, 1128 PacketSize); 1129 if (ControlPacket == NULL) 1130 { 1131 LeaveCriticalSection(&ControlServiceCriticalSection); 1132 return ERROR_NOT_ENOUGH_MEMORY; 1133 } 1134 1135 ControlPacket->dwSize = PacketSize; 1136 ControlPacket->dwControl = dwControl; 1137 ControlPacket->hServiceStatus = hServiceStatus; 1138 1139 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); 1140 1141 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 1142 wcscpy(Ptr, pServiceName); 1143 1144 ControlPacket->dwArgumentsCount = 0; 1145 ControlPacket->dwArgumentsOffset = 0; 1146 1147 bResult = WriteFile(hControlPipe, 1148 ControlPacket, 1149 PacketSize, 1150 &dwWriteCount, 1151 &Overlapped); 1152 if (bResult == FALSE) 1153 { 1154 DPRINT("WriteFile() returned FALSE\n"); 1155 1156 dwError = GetLastError(); 1157 if (dwError == ERROR_IO_PENDING) 1158 { 1159 DPRINT("dwError: ERROR_IO_PENDING\n"); 1160 1161 dwError = WaitForSingleObject(hControlPipe, 1162 PipeTimeout); 1163 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1164 1165 if (dwError == WAIT_TIMEOUT) 1166 { 1167 bResult = CancelIo(hControlPipe); 1168 if (bResult == FALSE) 1169 { 1170 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1171 } 1172 1173 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1174 goto Done; 1175 } 1176 else if (dwError == WAIT_OBJECT_0) 1177 { 1178 bResult = GetOverlappedResult(hControlPipe, 1179 &Overlapped, 1180 &dwWriteCount, 1181 TRUE); 1182 if (bResult == FALSE) 1183 { 1184 dwError = GetLastError(); 1185 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1186 1187 goto Done; 1188 } 1189 } 1190 } 1191 else 1192 { 1193 DPRINT1("WriteFile() failed (Error %lu)\n", dwError); 1194 goto Done; 1195 } 1196 } 1197 1198 /* Read the reply */ 1199 Overlapped.hEvent = (HANDLE) NULL; 1200 1201 bResult = ReadFile(hControlPipe, 1202 &ReplyPacket, 1203 sizeof(SCM_REPLY_PACKET), 1204 &dwReadCount, 1205 &Overlapped); 1206 if (bResult == FALSE) 1207 { 1208 DPRINT("ReadFile() returned FALSE\n"); 1209 1210 dwError = GetLastError(); 1211 if (dwError == ERROR_IO_PENDING) 1212 { 1213 DPRINT("dwError: ERROR_IO_PENDING\n"); 1214 1215 dwError = WaitForSingleObject(hControlPipe, 1216 PipeTimeout); 1217 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1218 1219 if (dwError == WAIT_TIMEOUT) 1220 { 1221 bResult = CancelIo(hControlPipe); 1222 if (bResult == FALSE) 1223 { 1224 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1225 } 1226 1227 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1228 goto Done; 1229 } 1230 else if (dwError == WAIT_OBJECT_0) 1231 { 1232 bResult = GetOverlappedResult(hControlPipe, 1233 &Overlapped, 1234 &dwReadCount, 1235 TRUE); 1236 if (bResult == FALSE) 1237 { 1238 dwError = GetLastError(); 1239 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1240 1241 goto Done; 1242 } 1243 } 1244 } 1245 else 1246 { 1247 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 1248 goto Done; 1249 } 1250 } 1251 1252 Done: 1253 /* Release the control packet */ 1254 HeapFree(GetProcessHeap(), 1255 0, 1256 ControlPacket); 1257 1258 if (dwReadCount == sizeof(SCM_REPLY_PACKET)) 1259 { 1260 dwError = ReplyPacket.dwError; 1261 } 1262 1263 LeaveCriticalSection(&ControlServiceCriticalSection); 1264 1265 DPRINT("ScmControlService() done\n"); 1266 1267 return dwError; 1268 } 1269 1270 1271 static DWORD 1272 ScmSendStartCommand(PSERVICE Service, 1273 DWORD argc, 1274 LPWSTR* argv) 1275 { 1276 DWORD dwError = ERROR_SUCCESS; 1277 PSCM_CONTROL_PACKET ControlPacket; 1278 SCM_REPLY_PACKET ReplyPacket; 1279 DWORD PacketSize; 1280 DWORD i; 1281 PWSTR Ptr; 1282 PWSTR *pOffPtr; 1283 PWSTR pArgPtr; 1284 BOOL bResult; 1285 DWORD dwWriteCount = 0; 1286 DWORD dwReadCount = 0; 1287 OVERLAPPED Overlapped = {0}; 1288 1289 DPRINT("ScmSendStartCommand() called\n"); 1290 1291 /* Calculate the total length of the start command line */ 1292 PacketSize = sizeof(SCM_CONTROL_PACKET); 1293 PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR)); 1294 1295 /* 1296 * Calculate the required packet size for the start argument vector 'argv', 1297 * composed of the list of pointer offsets, followed by UNICODE strings. 1298 * The strings are stored continuously after the vector of offsets, with 1299 * the offsets being relative to the beginning of the vector, as in the 1300 * following layout (with N == argc): 1301 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] . 1302 */ 1303 if (argc > 0 && argv != NULL) 1304 { 1305 PacketSize = ALIGN_UP(PacketSize, PWSTR); 1306 PacketSize += (argc * sizeof(PWSTR)); 1307 1308 DPRINT("Argc: %lu\n", argc); 1309 for (i = 0; i < argc; i++) 1310 { 1311 DPRINT("Argv[%lu]: %S\n", i, argv[i]); 1312 PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR)); 1313 } 1314 } 1315 1316 /* Allocate a control packet */ 1317 ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize); 1318 if (ControlPacket == NULL) 1319 return ERROR_NOT_ENOUGH_MEMORY; 1320 1321 ControlPacket->dwSize = PacketSize; 1322 ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS) 1323 ? SERVICE_CONTROL_START_OWN 1324 : SERVICE_CONTROL_START_SHARE; 1325 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; 1326 1327 /* Copy the start command line */ 1328 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); 1329 Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); 1330 wcscpy(Ptr, Service->lpServiceName); 1331 1332 ControlPacket->dwArgumentsCount = 0; 1333 ControlPacket->dwArgumentsOffset = 0; 1334 1335 /* Copy the argument vector */ 1336 if (argc > 0 && argv != NULL) 1337 { 1338 Ptr += wcslen(Service->lpServiceName) + 1; 1339 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR); 1340 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR)); 1341 1342 ControlPacket->dwArgumentsCount = argc; 1343 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket); 1344 1345 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); 1346 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset); 1347 1348 for (i = 0; i < argc; i++) 1349 { 1350 wcscpy(pArgPtr, argv[i]); 1351 pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr); 1352 DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]); 1353 pArgPtr += wcslen(argv[i]) + 1; 1354 } 1355 } 1356 1357 bResult = WriteFile(Service->lpImage->hControlPipe, 1358 ControlPacket, 1359 PacketSize, 1360 &dwWriteCount, 1361 &Overlapped); 1362 if (bResult == FALSE) 1363 { 1364 DPRINT("WriteFile() returned FALSE\n"); 1365 1366 dwError = GetLastError(); 1367 if (dwError == ERROR_IO_PENDING) 1368 { 1369 DPRINT("dwError: ERROR_IO_PENDING\n"); 1370 1371 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1372 PipeTimeout); 1373 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1374 1375 if (dwError == WAIT_TIMEOUT) 1376 { 1377 bResult = CancelIo(Service->lpImage->hControlPipe); 1378 if (bResult == FALSE) 1379 { 1380 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1381 } 1382 1383 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1384 goto Done; 1385 } 1386 else if (dwError == WAIT_OBJECT_0) 1387 { 1388 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1389 &Overlapped, 1390 &dwWriteCount, 1391 TRUE); 1392 if (bResult == FALSE) 1393 { 1394 dwError = GetLastError(); 1395 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1396 1397 goto Done; 1398 } 1399 } 1400 } 1401 else 1402 { 1403 DPRINT1("WriteFile() failed (Error %lu)\n", dwError); 1404 goto Done; 1405 } 1406 } 1407 1408 /* Read the reply */ 1409 Overlapped.hEvent = (HANDLE) NULL; 1410 1411 bResult = ReadFile(Service->lpImage->hControlPipe, 1412 &ReplyPacket, 1413 sizeof(SCM_REPLY_PACKET), 1414 &dwReadCount, 1415 &Overlapped); 1416 if (bResult == FALSE) 1417 { 1418 DPRINT("ReadFile() returned FALSE\n"); 1419 1420 dwError = GetLastError(); 1421 if (dwError == ERROR_IO_PENDING) 1422 { 1423 DPRINT("dwError: ERROR_IO_PENDING\n"); 1424 1425 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1426 PipeTimeout); 1427 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1428 1429 if (dwError == WAIT_TIMEOUT) 1430 { 1431 bResult = CancelIo(Service->lpImage->hControlPipe); 1432 if (bResult == FALSE) 1433 { 1434 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1435 } 1436 1437 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1438 goto Done; 1439 } 1440 else if (dwError == WAIT_OBJECT_0) 1441 { 1442 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1443 &Overlapped, 1444 &dwReadCount, 1445 TRUE); 1446 if (bResult == FALSE) 1447 { 1448 dwError = GetLastError(); 1449 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1450 1451 goto Done; 1452 } 1453 } 1454 } 1455 else 1456 { 1457 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 1458 goto Done; 1459 } 1460 } 1461 1462 Done: 1463 /* Release the control packet */ 1464 HeapFree(GetProcessHeap(), 1465 0, 1466 ControlPacket); 1467 1468 if (dwReadCount == sizeof(SCM_REPLY_PACKET)) 1469 { 1470 dwError = ReplyPacket.dwError; 1471 } 1472 1473 DPRINT("ScmSendStartCommand() done\n"); 1474 1475 return dwError; 1476 } 1477 1478 1479 static DWORD 1480 ScmWaitForServiceConnect(PSERVICE Service) 1481 { 1482 DWORD dwRead = 0; 1483 DWORD dwProcessId = 0; 1484 DWORD dwError = ERROR_SUCCESS; 1485 BOOL bResult; 1486 OVERLAPPED Overlapped = {0}; 1487 #if 0 1488 LPCWSTR lpLogStrings[3]; 1489 WCHAR szBuffer1[20]; 1490 WCHAR szBuffer2[20]; 1491 #endif 1492 1493 DPRINT("ScmWaitForServiceConnect()\n"); 1494 1495 Overlapped.hEvent = (HANDLE)NULL; 1496 1497 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, 1498 &Overlapped); 1499 if (bResult == FALSE) 1500 { 1501 DPRINT("ConnectNamedPipe() returned FALSE\n"); 1502 1503 dwError = GetLastError(); 1504 if (dwError == ERROR_IO_PENDING) 1505 { 1506 DPRINT("dwError: ERROR_IO_PENDING\n"); 1507 1508 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1509 PipeTimeout); 1510 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1511 1512 if (dwError == WAIT_TIMEOUT) 1513 { 1514 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); 1515 1516 bResult = CancelIo(Service->lpImage->hControlPipe); 1517 if (bResult == FALSE) 1518 { 1519 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1520 } 1521 1522 #if 0 1523 _ultow(PipeTimeout, szBuffer1, 10); 1524 lpLogStrings[0] = Service->lpDisplayName; 1525 lpLogStrings[1] = szBuffer1; 1526 1527 ScmLogEvent(EVENT_CONNECTION_TIMEOUT, 1528 EVENTLOG_ERROR_TYPE, 1529 2, 1530 lpLogStrings); 1531 #endif 1532 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName); 1533 1534 return ERROR_SERVICE_REQUEST_TIMEOUT; 1535 } 1536 else if (dwError == WAIT_OBJECT_0) 1537 { 1538 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1539 &Overlapped, 1540 &dwRead, 1541 TRUE); 1542 if (bResult == FALSE) 1543 { 1544 dwError = GetLastError(); 1545 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError); 1546 1547 return dwError; 1548 } 1549 } 1550 } 1551 else if (dwError != ERROR_PIPE_CONNECTED) 1552 { 1553 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError); 1554 return dwError; 1555 } 1556 } 1557 1558 DPRINT("Control pipe connected!\n"); 1559 1560 Overlapped.hEvent = (HANDLE) NULL; 1561 1562 /* Read the process id from pipe */ 1563 bResult = ReadFile(Service->lpImage->hControlPipe, 1564 (LPVOID)&dwProcessId, 1565 sizeof(DWORD), 1566 &dwRead, 1567 &Overlapped); 1568 if (bResult == FALSE) 1569 { 1570 DPRINT("ReadFile() returned FALSE\n"); 1571 1572 dwError = GetLastError(); 1573 if (dwError == ERROR_IO_PENDING) 1574 { 1575 DPRINT("dwError: ERROR_IO_PENDING\n"); 1576 1577 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1578 PipeTimeout); 1579 if (dwError == WAIT_TIMEOUT) 1580 { 1581 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); 1582 1583 bResult = CancelIo(Service->lpImage->hControlPipe); 1584 if (bResult == FALSE) 1585 { 1586 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1587 } 1588 1589 #if 0 1590 _ultow(PipeTimeout, szBuffer1, 10); 1591 lpLogStrings[0] = szBuffer1; 1592 1593 ScmLogEvent(EVENT_READFILE_TIMEOUT, 1594 EVENTLOG_ERROR_TYPE, 1595 1, 1596 lpLogStrings); 1597 #endif 1598 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName); 1599 1600 return ERROR_SERVICE_REQUEST_TIMEOUT; 1601 } 1602 else if (dwError == WAIT_OBJECT_0) 1603 { 1604 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n"); 1605 1606 DPRINT("Process Id: %lu\n", dwProcessId); 1607 1608 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1609 &Overlapped, 1610 &dwRead, 1611 TRUE); 1612 if (bResult == FALSE) 1613 { 1614 dwError = GetLastError(); 1615 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1616 1617 return dwError; 1618 } 1619 } 1620 else 1621 { 1622 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 1623 } 1624 } 1625 else 1626 { 1627 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 1628 return dwError; 1629 } 1630 } 1631 1632 if (dwProcessId != Service->lpImage->dwProcessId) 1633 { 1634 #if 0 1635 _ultow(Service->lpImage->dwProcessId, szBuffer1, 10); 1636 _ultow(dwProcessId, szBuffer2, 10); 1637 1638 lpLogStrings[0] = Service->lpDisplayName; 1639 lpLogStrings[1] = szBuffer1; 1640 lpLogStrings[2] = szBuffer2; 1641 1642 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED, 1643 EVENTLOG_WARNING_TYPE, 1644 3, 1645 lpLogStrings); 1646 #endif 1647 1648 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName); 1649 } 1650 1651 DPRINT("ScmWaitForServiceConnect() done\n"); 1652 1653 return ERROR_SUCCESS; 1654 } 1655 1656 1657 static DWORD 1658 ScmStartUserModeService(PSERVICE Service, 1659 DWORD argc, 1660 LPWSTR* argv) 1661 { 1662 PROCESS_INFORMATION ProcessInformation; 1663 STARTUPINFOW StartupInfo; 1664 LPVOID lpEnvironment; 1665 BOOL Result; 1666 DWORD dwError = ERROR_SUCCESS; 1667 1668 DPRINT("ScmStartUserModeService(%p)\n", Service); 1669 1670 /* If the image is already running ... */ 1671 if (Service->lpImage->dwImageRunCount > 1) 1672 { 1673 /* ... just send a start command */ 1674 return ScmSendStartCommand(Service, argc, argv); 1675 } 1676 1677 /* Otherwise start its process */ 1678 ZeroMemory(&StartupInfo, sizeof(StartupInfo)); 1679 StartupInfo.cb = sizeof(StartupInfo); 1680 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation)); 1681 1682 if (Service->lpImage->hToken) 1683 { 1684 /* User token: Run the service under the user account */ 1685 1686 if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE)) 1687 { 1688 /* We failed, run the service with the current environment */ 1689 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n", 1690 GetLastError(), Service->lpServiceName); 1691 lpEnvironment = NULL; 1692 } 1693 1694 /* Impersonate the new user */ 1695 Result = ImpersonateLoggedOnUser(Service->lpImage->hToken); 1696 if (Result) 1697 { 1698 /* Launch the process in the user's logon session */ 1699 Result = CreateProcessAsUserW(Service->lpImage->hToken, 1700 NULL, 1701 Service->lpImage->pszImagePath, 1702 NULL, 1703 NULL, 1704 FALSE, 1705 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, 1706 lpEnvironment, 1707 NULL, 1708 &StartupInfo, 1709 &ProcessInformation); 1710 if (!Result) 1711 dwError = GetLastError(); 1712 1713 /* Revert the impersonation */ 1714 RevertToSelf(); 1715 } 1716 else 1717 { 1718 dwError = GetLastError(); 1719 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError); 1720 } 1721 } 1722 else 1723 { 1724 /* No user token: Run the service under the LocalSystem account */ 1725 1726 if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE)) 1727 { 1728 /* We failed, run the service with the current environment */ 1729 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n", 1730 GetLastError(), Service->lpServiceName); 1731 lpEnvironment = NULL; 1732 } 1733 1734 /* Use the interactive desktop if the service is interactive */ 1735 if ((NoInteractiveServices == 0) && 1736 (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS)) 1737 { 1738 StartupInfo.dwFlags |= STARTF_INHERITDESKTOP; 1739 StartupInfo.lpDesktop = L"WinSta0\\Default"; 1740 } 1741 1742 Result = CreateProcessW(NULL, 1743 Service->lpImage->pszImagePath, 1744 NULL, 1745 NULL, 1746 FALSE, 1747 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, 1748 lpEnvironment, 1749 NULL, 1750 &StartupInfo, 1751 &ProcessInformation); 1752 if (!Result) 1753 dwError = GetLastError(); 1754 } 1755 1756 if (lpEnvironment) 1757 DestroyEnvironmentBlock(lpEnvironment); 1758 1759 if (!Result) 1760 { 1761 DPRINT1("Starting '%S' failed with error %d\n", 1762 Service->lpServiceName, dwError); 1763 return dwError; 1764 } 1765 1766 DPRINT("Process Id: %lu Handle %p\n", 1767 ProcessInformation.dwProcessId, 1768 ProcessInformation.hProcess); 1769 DPRINT("Thread Id: %lu Handle %p\n", 1770 ProcessInformation.dwThreadId, 1771 ProcessInformation.hThread); 1772 1773 /* Get the process handle and ID */ 1774 Service->lpImage->hProcess = ProcessInformation.hProcess; 1775 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; 1776 1777 /* Resume the main thread and close its handle */ 1778 ResumeThread(ProcessInformation.hThread); 1779 CloseHandle(ProcessInformation.hThread); 1780 1781 /* Connect control pipe */ 1782 dwError = ScmWaitForServiceConnect(Service); 1783 if (dwError != ERROR_SUCCESS) 1784 { 1785 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); 1786 Service->lpImage->dwProcessId = 0; 1787 return dwError; 1788 } 1789 1790 /* Send the start command */ 1791 return ScmSendStartCommand(Service, argc, argv); 1792 } 1793 1794 1795 static DWORD 1796 ScmLoadService(PSERVICE Service, 1797 DWORD argc, 1798 LPWSTR* argv) 1799 { 1800 PSERVICE_GROUP Group = Service->lpGroup; 1801 DWORD dwError = ERROR_SUCCESS; 1802 LPCWSTR lpLogStrings[2]; 1803 WCHAR szLogBuffer[80]; 1804 1805 DPRINT("ScmLoadService() called\n"); 1806 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 1807 1808 if (Service->Status.dwCurrentState != SERVICE_STOPPED) 1809 { 1810 DPRINT("Service %S is already running!\n", Service->lpServiceName); 1811 return ERROR_SERVICE_ALREADY_RUNNING; 1812 } 1813 1814 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType); 1815 1816 if (Service->Status.dwServiceType & SERVICE_DRIVER) 1817 { 1818 /* Start the driver */ 1819 dwError = ScmStartDriver(Service); 1820 } 1821 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS)) 1822 { 1823 /* Start user-mode service */ 1824 dwError = ScmCreateOrReferenceServiceImage(Service); 1825 if (dwError == ERROR_SUCCESS) 1826 { 1827 dwError = ScmStartUserModeService(Service, argc, argv); 1828 if (dwError == ERROR_SUCCESS) 1829 { 1830 Service->Status.dwCurrentState = SERVICE_START_PENDING; 1831 Service->Status.dwControlsAccepted = 0; 1832 } 1833 else 1834 { 1835 Service->lpImage->dwImageRunCount--; 1836 if (Service->lpImage->dwImageRunCount == 0) 1837 { 1838 ScmRemoveServiceImage(Service->lpImage); 1839 Service->lpImage = NULL; 1840 } 1841 } 1842 } 1843 } 1844 1845 DPRINT("ScmLoadService() done (Error %lu)\n", dwError); 1846 1847 if (dwError == ERROR_SUCCESS) 1848 { 1849 if (Group != NULL) 1850 { 1851 Group->ServicesRunning = TRUE; 1852 } 1853 1854 /* Log a successful service start */ 1855 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80); 1856 lpLogStrings[0] = Service->lpDisplayName; 1857 lpLogStrings[1] = szLogBuffer; 1858 1859 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS, 1860 EVENTLOG_INFORMATION_TYPE, 1861 2, 1862 lpLogStrings); 1863 } 1864 else 1865 { 1866 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) 1867 { 1868 /* Log a failed service start */ 1869 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer), 1870 L"%lu", dwError); 1871 lpLogStrings[0] = Service->lpServiceName; 1872 lpLogStrings[1] = szLogBuffer; 1873 ScmLogEvent(EVENT_SERVICE_START_FAILED, 1874 EVENTLOG_ERROR_TYPE, 1875 2, 1876 lpLogStrings); 1877 } 1878 1879 #if 0 1880 switch (Service->dwErrorControl) 1881 { 1882 case SERVICE_ERROR_SEVERE: 1883 if (IsLastKnownGood == FALSE) 1884 { 1885 /* FIXME: Boot last known good configuration */ 1886 } 1887 break; 1888 1889 case SERVICE_ERROR_CRITICAL: 1890 if (IsLastKnownGood == FALSE) 1891 { 1892 /* FIXME: Boot last known good configuration */ 1893 } 1894 else 1895 { 1896 /* FIXME: BSOD! */ 1897 } 1898 break; 1899 } 1900 #endif 1901 } 1902 1903 return dwError; 1904 } 1905 1906 1907 DWORD 1908 ScmStartService(PSERVICE Service, 1909 DWORD argc, 1910 LPWSTR* argv) 1911 { 1912 DWORD dwError = ERROR_SUCCESS; 1913 SC_RPC_LOCK Lock = NULL; 1914 1915 DPRINT("ScmStartService() called\n"); 1916 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 1917 1918 /* Acquire the service control critical section, to synchronize starts */ 1919 EnterCriticalSection(&ControlServiceCriticalSection); 1920 1921 /* 1922 * Acquire the user service start lock while the service is starting, if 1923 * needed (i.e. if we are not starting it during the initialization phase). 1924 * If we don't success, bail out. 1925 */ 1926 if (!ScmInitialize) 1927 { 1928 dwError = ScmAcquireServiceStartLock(TRUE, &Lock); 1929 if (dwError != ERROR_SUCCESS) goto done; 1930 } 1931 1932 /* Really start the service */ 1933 dwError = ScmLoadService(Service, argc, argv); 1934 1935 /* Release the service start lock, if needed, and the critical section */ 1936 if (Lock) ScmReleaseServiceStartLock(&Lock); 1937 1938 done: 1939 LeaveCriticalSection(&ControlServiceCriticalSection); 1940 1941 DPRINT("ScmStartService() done (Error %lu)\n", dwError); 1942 1943 return dwError; 1944 } 1945 1946 1947 VOID 1948 ScmAutoStartServices(VOID) 1949 { 1950 DWORD dwError; 1951 PLIST_ENTRY GroupEntry; 1952 PLIST_ENTRY ServiceEntry; 1953 PSERVICE_GROUP CurrentGroup; 1954 PSERVICE CurrentService; 1955 WCHAR szSafeBootServicePath[MAX_PATH]; 1956 DWORD SafeBootEnabled; 1957 HKEY hKey; 1958 DWORD dwKeySize; 1959 ULONG i; 1960 1961 /* 1962 * This function MUST be called ONLY at initialization time. 1963 * Therefore, no need to acquire the user service start lock. 1964 */ 1965 ASSERT(ScmInitialize); 1966 1967 /* Retrieve the SafeBoot parameter */ 1968 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1969 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option", 1970 0, 1971 KEY_READ, 1972 &hKey); 1973 if (dwError == ERROR_SUCCESS) 1974 { 1975 dwKeySize = sizeof(SafeBootEnabled); 1976 dwError = RegQueryValueExW(hKey, 1977 L"OptionValue", 1978 0, 1979 NULL, 1980 (LPBYTE)&SafeBootEnabled, 1981 &dwKeySize); 1982 RegCloseKey(hKey); 1983 } 1984 1985 /* Default to Normal boot if the value doesn't exist */ 1986 if (dwError != ERROR_SUCCESS) 1987 SafeBootEnabled = 0; 1988 1989 /* Acquire the service control critical section, to synchronize starts */ 1990 EnterCriticalSection(&ControlServiceCriticalSection); 1991 1992 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */ 1993 ServiceEntry = ServiceListHead.Flink; 1994 while (ServiceEntry != &ServiceListHead) 1995 { 1996 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 1997 1998 /* Build the safe boot path */ 1999 StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2000 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); 2001 2002 switch (SafeBootEnabled) 2003 { 2004 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ 2005 case 1: 2006 case 3: 2007 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2008 L"\\Minimal\\"); 2009 break; 2010 2011 case 2: 2012 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2013 L"\\Network\\"); 2014 break; 2015 } 2016 2017 if (SafeBootEnabled != 0) 2018 { 2019 /* If key does not exist then do not assume safe mode */ 2020 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2021 szSafeBootServicePath, 2022 0, 2023 KEY_READ, 2024 &hKey); 2025 if (dwError == ERROR_SUCCESS) 2026 { 2027 RegCloseKey(hKey); 2028 2029 /* Finish Safe Boot path off */ 2030 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2031 CurrentService->lpServiceName); 2032 2033 /* Check that the key is in the Safe Boot path */ 2034 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2035 szSafeBootServicePath, 2036 0, 2037 KEY_READ, 2038 &hKey); 2039 if (dwError != ERROR_SUCCESS) 2040 { 2041 /* Mark service as visited so it is not auto-started */ 2042 CurrentService->ServiceVisited = TRUE; 2043 } 2044 else 2045 { 2046 /* Must be auto-started in safe mode - mark as unvisited */ 2047 RegCloseKey(hKey); 2048 CurrentService->ServiceVisited = FALSE; 2049 } 2050 } 2051 else 2052 { 2053 DPRINT1("WARNING: Could not open the associated Safe Boot key!"); 2054 CurrentService->ServiceVisited = FALSE; 2055 } 2056 } 2057 2058 ServiceEntry = ServiceEntry->Flink; 2059 } 2060 2061 /* Start all services which are members of an existing group */ 2062 GroupEntry = GroupListHead.Flink; 2063 while (GroupEntry != &GroupListHead) 2064 { 2065 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); 2066 2067 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName); 2068 2069 /* Start all services witch have a valid tag */ 2070 for (i = 0; i < CurrentGroup->TagCount; i++) 2071 { 2072 ServiceEntry = ServiceListHead.Flink; 2073 while (ServiceEntry != &ServiceListHead) 2074 { 2075 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2076 2077 if ((CurrentService->lpGroup == CurrentGroup) && 2078 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2079 (CurrentService->ServiceVisited == FALSE) && 2080 (CurrentService->dwTag == CurrentGroup->TagArray[i])) 2081 { 2082 CurrentService->ServiceVisited = TRUE; 2083 ScmLoadService(CurrentService, 0, NULL); 2084 } 2085 2086 ServiceEntry = ServiceEntry->Flink; 2087 } 2088 } 2089 2090 /* Start all services which have an invalid tag or which do not have a tag */ 2091 ServiceEntry = ServiceListHead.Flink; 2092 while (ServiceEntry != &ServiceListHead) 2093 { 2094 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2095 2096 if ((CurrentService->lpGroup == CurrentGroup) && 2097 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2098 (CurrentService->ServiceVisited == FALSE)) 2099 { 2100 CurrentService->ServiceVisited = TRUE; 2101 ScmLoadService(CurrentService, 0, NULL); 2102 } 2103 2104 ServiceEntry = ServiceEntry->Flink; 2105 } 2106 2107 GroupEntry = GroupEntry->Flink; 2108 } 2109 2110 /* Start all services which are members of any non-existing group */ 2111 ServiceEntry = ServiceListHead.Flink; 2112 while (ServiceEntry != &ServiceListHead) 2113 { 2114 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2115 2116 if ((CurrentService->lpGroup != NULL) && 2117 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2118 (CurrentService->ServiceVisited == FALSE)) 2119 { 2120 CurrentService->ServiceVisited = TRUE; 2121 ScmLoadService(CurrentService, 0, NULL); 2122 } 2123 2124 ServiceEntry = ServiceEntry->Flink; 2125 } 2126 2127 /* Start all services which are not a member of any group */ 2128 ServiceEntry = ServiceListHead.Flink; 2129 while (ServiceEntry != &ServiceListHead) 2130 { 2131 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2132 2133 if ((CurrentService->lpGroup == NULL) && 2134 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2135 (CurrentService->ServiceVisited == FALSE)) 2136 { 2137 CurrentService->ServiceVisited = TRUE; 2138 ScmLoadService(CurrentService, 0, NULL); 2139 } 2140 2141 ServiceEntry = ServiceEntry->Flink; 2142 } 2143 2144 /* Clear 'ServiceVisited' flag again */ 2145 ServiceEntry = ServiceListHead.Flink; 2146 while (ServiceEntry != &ServiceListHead) 2147 { 2148 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2149 CurrentService->ServiceVisited = FALSE; 2150 ServiceEntry = ServiceEntry->Flink; 2151 } 2152 2153 /* Release the critical section */ 2154 LeaveCriticalSection(&ControlServiceCriticalSection); 2155 } 2156 2157 2158 VOID 2159 ScmAutoShutdownServices(VOID) 2160 { 2161 PLIST_ENTRY ServiceEntry; 2162 PSERVICE CurrentService; 2163 2164 DPRINT("ScmAutoShutdownServices() called\n"); 2165 2166 /* Lock the service database exclusively */ 2167 ScmLockDatabaseExclusive(); 2168 2169 ServiceEntry = ServiceListHead.Flink; 2170 while (ServiceEntry != &ServiceListHead) 2171 { 2172 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2173 2174 if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) && 2175 (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || 2176 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)) 2177 { 2178 /* Send the shutdown notification */ 2179 DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName); 2180 ScmControlService(CurrentService->lpImage->hControlPipe, 2181 CurrentService->lpServiceName, 2182 (SERVICE_STATUS_HANDLE)CurrentService, 2183 SERVICE_CONTROL_SHUTDOWN); 2184 } 2185 2186 ServiceEntry = ServiceEntry->Flink; 2187 } 2188 2189 /* Unlock the service database */ 2190 ScmUnlockDatabase(); 2191 2192 DPRINT("ScmAutoShutdownServices() done\n"); 2193 } 2194 2195 2196 BOOL 2197 ScmLockDatabaseExclusive(VOID) 2198 { 2199 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE); 2200 } 2201 2202 2203 BOOL 2204 ScmLockDatabaseShared(VOID) 2205 { 2206 return RtlAcquireResourceShared(&DatabaseLock, TRUE); 2207 } 2208 2209 2210 VOID 2211 ScmUnlockDatabase(VOID) 2212 { 2213 RtlReleaseResource(&DatabaseLock); 2214 } 2215 2216 2217 VOID 2218 ScmInitNamedPipeCriticalSection(VOID) 2219 { 2220 HKEY hKey; 2221 DWORD dwKeySize; 2222 DWORD dwError; 2223 2224 InitializeCriticalSection(&ControlServiceCriticalSection); 2225 2226 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2227 L"SYSTEM\\CurrentControlSet\\Control", 2228 0, 2229 KEY_READ, 2230 &hKey); 2231 if (dwError == ERROR_SUCCESS) 2232 { 2233 dwKeySize = sizeof(PipeTimeout); 2234 RegQueryValueExW(hKey, 2235 L"ServicesPipeTimeout", 2236 0, 2237 NULL, 2238 (LPBYTE)&PipeTimeout, 2239 &dwKeySize); 2240 RegCloseKey(hKey); 2241 } 2242 } 2243 2244 2245 VOID 2246 ScmDeleteNamedPipeCriticalSection(VOID) 2247 { 2248 DeleteCriticalSection(&ControlServiceCriticalSection); 2249 } 2250 2251 /* EOF */ 2252