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