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 #if 0 188 PROFILEINFOW ProfileInfo; 189 PWSTR pszUserName = NULL; 190 PWSTR pszDomainName = NULL; 191 PWSTR pszPassword = NULL; 192 PWSTR ptr; 193 DWORD dwError = ERROR_SUCCESS; 194 #endif 195 196 DPRINT("ScmLogonService(%p %p)\n", pService, pImage); 197 198 DPRINT("Service %S\n", pService->lpServiceName); 199 200 if (ScmIsLocalSystemAccount(pImage->pszAccountName)) 201 return ERROR_SUCCESS; 202 203 // FIXME: Always assume LocalSystem 204 return ERROR_SUCCESS; 205 206 #if 0 207 /* Get the user and domain names */ 208 ptr = wcschr(pImage->pszAccountName, L'\\'); 209 if (ptr != NULL) 210 { 211 *ptr = L'\0'; 212 213 pszUserName = ptr + 1; 214 pszDomainName = pImage->pszAccountName; 215 } 216 else 217 { 218 pszUserName = pImage->pszAccountName; 219 pszDomainName = NULL; 220 } 221 222 /* Build the service 'password' */ 223 pszPassword = HeapAlloc(GetProcessHeap(), 224 HEAP_ZERO_MEMORY, 225 (wcslen(pService->lpServiceName) + 5) * sizeof(WCHAR)); 226 if (pszPassword == NULL) 227 { 228 dwError = ERROR_NOT_ENOUGH_MEMORY; 229 goto done; 230 } 231 232 wcscpy(pszPassword, L"_SC_"); 233 wcscat(pszPassword, pService->lpServiceName); 234 235 DPRINT("Domain: %S User: %S Password: %S\n", pszDomainName, pszUserName, pszPassword); 236 237 /* Service logon */ 238 if (!LogonUserW(pszUserName, 239 pszDomainName, 240 pszPassword, 241 LOGON32_LOGON_SERVICE, 242 LOGON32_PROVIDER_DEFAULT, 243 &pImage->hToken)) 244 { 245 dwError = GetLastError(); 246 DPRINT1("LogonUserW() failed (Error %lu)\n", dwError); 247 goto done; 248 } 249 250 // FIXME: Call LoadUserProfileW to be able to initialize a per-user 251 // environment block, with user-specific environment variables as 252 // %USERNAME%, %USERPROFILE%, and %ALLUSERSPROFILE% correctly initialized!! 253 254 /* Load the user profile, so that the per-user environment variables can be initialized */ 255 ZeroMemory(&ProfileInfo, sizeof(ProfileInfo)); 256 ProfileInfo.dwSize = sizeof(ProfileInfo); 257 ProfileInfo.dwFlags = PI_NOUI; 258 ProfileInfo.lpUserName = pszUserName; 259 // ProfileInfo.lpProfilePath = NULL; 260 // ProfileInfo.lpDefaultPath = NULL; 261 // ProfileInfo.lpServerName = NULL; 262 // ProfileInfo.lpPolicyPath = NULL; 263 // ProfileInfo.hProfile = NULL; 264 265 if (!LoadUserProfileW(pImage->hToken, &ProfileInfo)) 266 { 267 dwError = GetLastError(); 268 DPRINT1("LoadUserProfileW() failed (Error %lu)\n", dwError); 269 goto done; 270 } 271 272 pImage->hProfile = ProfileInfo.hProfile; 273 274 done: 275 if (pszPassword != NULL) 276 HeapFree(GetProcessHeap(), 0, pszPassword); 277 278 if (ptr != NULL) 279 *ptr = L'\\'; 280 281 return dwError; 282 #endif 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 /* Use the interactive desktop if the service is interactive */ 1683 if ((NoInteractiveServices == 0) && 1684 (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS)) 1685 StartupInfo.lpDesktop = L"WinSta0\\Default"; 1686 1687 if (Service->lpImage->hToken) 1688 { 1689 /* User token: Run the service under the user account */ 1690 1691 if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE)) 1692 { 1693 /* We failed, run the service with the current environment */ 1694 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n", 1695 GetLastError(), Service->lpServiceName); 1696 lpEnvironment = NULL; 1697 } 1698 1699 /* Impersonate the new user */ 1700 Result = ImpersonateLoggedOnUser(Service->lpImage->hToken); 1701 if (Result) 1702 { 1703 /* Launch the process in the user's logon session */ 1704 Result = CreateProcessAsUserW(Service->lpImage->hToken, 1705 NULL, 1706 Service->lpImage->pszImagePath, 1707 NULL, 1708 NULL, 1709 FALSE, 1710 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, 1711 lpEnvironment, 1712 NULL, 1713 &StartupInfo, 1714 &ProcessInformation); 1715 if (!Result) 1716 dwError = GetLastError(); 1717 1718 /* Revert the impersonation */ 1719 RevertToSelf(); 1720 } 1721 else 1722 { 1723 dwError = GetLastError(); 1724 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError); 1725 } 1726 } 1727 else 1728 { 1729 /* No user token: Run the service under the LocalSystem account */ 1730 1731 if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE)) 1732 { 1733 /* We failed, run the service with the current environment */ 1734 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with the current environment.\n", 1735 GetLastError(), Service->lpServiceName); 1736 lpEnvironment = NULL; 1737 } 1738 1739 Result = CreateProcessW(NULL, 1740 Service->lpImage->pszImagePath, 1741 NULL, 1742 NULL, 1743 FALSE, 1744 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, 1745 lpEnvironment, 1746 NULL, 1747 &StartupInfo, 1748 &ProcessInformation); 1749 if (!Result) 1750 dwError = GetLastError(); 1751 } 1752 1753 if (lpEnvironment) 1754 DestroyEnvironmentBlock(lpEnvironment); 1755 1756 if (!Result) 1757 { 1758 DPRINT1("Starting '%S' failed with error %d\n", 1759 Service->lpServiceName, dwError); 1760 return dwError; 1761 } 1762 1763 DPRINT("Process Id: %lu Handle %p\n", 1764 ProcessInformation.dwProcessId, 1765 ProcessInformation.hProcess); 1766 DPRINT("Thread Id: %lu Handle %p\n", 1767 ProcessInformation.dwThreadId, 1768 ProcessInformation.hThread); 1769 1770 /* Get the process handle and ID */ 1771 Service->lpImage->hProcess = ProcessInformation.hProcess; 1772 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; 1773 1774 /* Resume the main thread and close its handle */ 1775 ResumeThread(ProcessInformation.hThread); 1776 CloseHandle(ProcessInformation.hThread); 1777 1778 /* Connect control pipe */ 1779 dwError = ScmWaitForServiceConnect(Service); 1780 if (dwError != ERROR_SUCCESS) 1781 { 1782 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); 1783 Service->lpImage->dwProcessId = 0; 1784 return dwError; 1785 } 1786 1787 /* Send the start command */ 1788 return ScmSendStartCommand(Service, argc, argv); 1789 } 1790 1791 1792 static DWORD 1793 ScmLoadService(PSERVICE Service, 1794 DWORD argc, 1795 LPWSTR* argv) 1796 { 1797 PSERVICE_GROUP Group = Service->lpGroup; 1798 DWORD dwError = ERROR_SUCCESS; 1799 LPCWSTR lpLogStrings[2]; 1800 WCHAR szLogBuffer[80]; 1801 1802 DPRINT("ScmLoadService() called\n"); 1803 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 1804 1805 if (Service->Status.dwCurrentState != SERVICE_STOPPED) 1806 { 1807 DPRINT("Service %S is already running!\n", Service->lpServiceName); 1808 return ERROR_SERVICE_ALREADY_RUNNING; 1809 } 1810 1811 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType); 1812 1813 if (Service->Status.dwServiceType & SERVICE_DRIVER) 1814 { 1815 /* Start the driver */ 1816 dwError = ScmStartDriver(Service); 1817 } 1818 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS)) 1819 { 1820 /* Start user-mode service */ 1821 dwError = ScmCreateOrReferenceServiceImage(Service); 1822 if (dwError == ERROR_SUCCESS) 1823 { 1824 dwError = ScmStartUserModeService(Service, argc, argv); 1825 if (dwError == ERROR_SUCCESS) 1826 { 1827 Service->Status.dwCurrentState = SERVICE_START_PENDING; 1828 Service->Status.dwControlsAccepted = 0; 1829 } 1830 else 1831 { 1832 Service->lpImage->dwImageRunCount--; 1833 if (Service->lpImage->dwImageRunCount == 0) 1834 { 1835 ScmRemoveServiceImage(Service->lpImage); 1836 Service->lpImage = NULL; 1837 } 1838 } 1839 } 1840 } 1841 1842 DPRINT("ScmLoadService() done (Error %lu)\n", dwError); 1843 1844 if (dwError == ERROR_SUCCESS) 1845 { 1846 if (Group != NULL) 1847 { 1848 Group->ServicesRunning = TRUE; 1849 } 1850 1851 /* Log a successful service start */ 1852 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80); 1853 lpLogStrings[0] = Service->lpDisplayName; 1854 lpLogStrings[1] = szLogBuffer; 1855 1856 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS, 1857 EVENTLOG_INFORMATION_TYPE, 1858 2, 1859 lpLogStrings); 1860 } 1861 else 1862 { 1863 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) 1864 { 1865 /* Log a failed service start */ 1866 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer), 1867 L"%lu", dwError); 1868 lpLogStrings[0] = Service->lpServiceName; 1869 lpLogStrings[1] = szLogBuffer; 1870 ScmLogEvent(EVENT_SERVICE_START_FAILED, 1871 EVENTLOG_ERROR_TYPE, 1872 2, 1873 lpLogStrings); 1874 } 1875 1876 #if 0 1877 switch (Service->dwErrorControl) 1878 { 1879 case SERVICE_ERROR_SEVERE: 1880 if (IsLastKnownGood == FALSE) 1881 { 1882 /* FIXME: Boot last known good configuration */ 1883 } 1884 break; 1885 1886 case SERVICE_ERROR_CRITICAL: 1887 if (IsLastKnownGood == FALSE) 1888 { 1889 /* FIXME: Boot last known good configuration */ 1890 } 1891 else 1892 { 1893 /* FIXME: BSOD! */ 1894 } 1895 break; 1896 } 1897 #endif 1898 } 1899 1900 return dwError; 1901 } 1902 1903 1904 DWORD 1905 ScmStartService(PSERVICE Service, 1906 DWORD argc, 1907 LPWSTR* argv) 1908 { 1909 DWORD dwError = ERROR_SUCCESS; 1910 SC_RPC_LOCK Lock = NULL; 1911 1912 DPRINT("ScmStartService() called\n"); 1913 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 1914 1915 /* Acquire the service control critical section, to synchronize starts */ 1916 EnterCriticalSection(&ControlServiceCriticalSection); 1917 1918 /* 1919 * Acquire the user service start lock while the service is starting, if 1920 * needed (i.e. if we are not starting it during the initialization phase). 1921 * If we don't success, bail out. 1922 */ 1923 if (!ScmInitialize) 1924 { 1925 dwError = ScmAcquireServiceStartLock(TRUE, &Lock); 1926 if (dwError != ERROR_SUCCESS) goto done; 1927 } 1928 1929 /* Really start the service */ 1930 dwError = ScmLoadService(Service, argc, argv); 1931 1932 /* Release the service start lock, if needed, and the critical section */ 1933 if (Lock) ScmReleaseServiceStartLock(&Lock); 1934 1935 done: 1936 LeaveCriticalSection(&ControlServiceCriticalSection); 1937 1938 DPRINT("ScmStartService() done (Error %lu)\n", dwError); 1939 1940 return dwError; 1941 } 1942 1943 1944 VOID 1945 ScmAutoStartServices(VOID) 1946 { 1947 DWORD dwError; 1948 PLIST_ENTRY GroupEntry; 1949 PLIST_ENTRY ServiceEntry; 1950 PSERVICE_GROUP CurrentGroup; 1951 PSERVICE CurrentService; 1952 WCHAR szSafeBootServicePath[MAX_PATH]; 1953 DWORD SafeBootEnabled; 1954 HKEY hKey; 1955 DWORD dwKeySize; 1956 ULONG i; 1957 1958 /* 1959 * This function MUST be called ONLY at initialization time. 1960 * Therefore, no need to acquire the user service start lock. 1961 */ 1962 ASSERT(ScmInitialize); 1963 1964 /* Retrieve the SafeBoot parameter */ 1965 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1966 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option", 1967 0, 1968 KEY_READ, 1969 &hKey); 1970 if (dwError == ERROR_SUCCESS) 1971 { 1972 dwKeySize = sizeof(SafeBootEnabled); 1973 dwError = RegQueryValueExW(hKey, 1974 L"OptionValue", 1975 0, 1976 NULL, 1977 (LPBYTE)&SafeBootEnabled, 1978 &dwKeySize); 1979 RegCloseKey(hKey); 1980 } 1981 1982 /* Default to Normal boot if the value doesn't exist */ 1983 if (dwError != ERROR_SUCCESS) 1984 SafeBootEnabled = 0; 1985 1986 /* Acquire the service control critical section, to synchronize starts */ 1987 EnterCriticalSection(&ControlServiceCriticalSection); 1988 1989 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */ 1990 ServiceEntry = ServiceListHead.Flink; 1991 while (ServiceEntry != &ServiceListHead) 1992 { 1993 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 1994 1995 /* Build the safe boot path */ 1996 StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 1997 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); 1998 1999 switch (SafeBootEnabled) 2000 { 2001 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ 2002 case 1: 2003 case 3: 2004 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2005 L"\\Minimal\\"); 2006 break; 2007 2008 case 2: 2009 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2010 L"\\Network\\"); 2011 break; 2012 } 2013 2014 if (SafeBootEnabled != 0) 2015 { 2016 /* If key does not exist then do not assume safe mode */ 2017 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2018 szSafeBootServicePath, 2019 0, 2020 KEY_READ, 2021 &hKey); 2022 if (dwError == ERROR_SUCCESS) 2023 { 2024 RegCloseKey(hKey); 2025 2026 /* Finish Safe Boot path off */ 2027 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2028 CurrentService->lpServiceName); 2029 2030 /* Check that the key is in the Safe Boot path */ 2031 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2032 szSafeBootServicePath, 2033 0, 2034 KEY_READ, 2035 &hKey); 2036 if (dwError != ERROR_SUCCESS) 2037 { 2038 /* Mark service as visited so it is not auto-started */ 2039 CurrentService->ServiceVisited = TRUE; 2040 } 2041 else 2042 { 2043 /* Must be auto-started in safe mode - mark as unvisited */ 2044 RegCloseKey(hKey); 2045 CurrentService->ServiceVisited = FALSE; 2046 } 2047 } 2048 else 2049 { 2050 DPRINT1("WARNING: Could not open the associated Safe Boot key!"); 2051 CurrentService->ServiceVisited = FALSE; 2052 } 2053 } 2054 2055 ServiceEntry = ServiceEntry->Flink; 2056 } 2057 2058 /* Start all services which are members of an existing group */ 2059 GroupEntry = GroupListHead.Flink; 2060 while (GroupEntry != &GroupListHead) 2061 { 2062 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); 2063 2064 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName); 2065 2066 /* Start all services witch have a valid tag */ 2067 for (i = 0; i < CurrentGroup->TagCount; i++) 2068 { 2069 ServiceEntry = ServiceListHead.Flink; 2070 while (ServiceEntry != &ServiceListHead) 2071 { 2072 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2073 2074 if ((CurrentService->lpGroup == CurrentGroup) && 2075 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2076 (CurrentService->ServiceVisited == FALSE) && 2077 (CurrentService->dwTag == CurrentGroup->TagArray[i])) 2078 { 2079 CurrentService->ServiceVisited = TRUE; 2080 ScmLoadService(CurrentService, 0, NULL); 2081 } 2082 2083 ServiceEntry = ServiceEntry->Flink; 2084 } 2085 } 2086 2087 /* Start all services which have an invalid tag or which do not have a tag */ 2088 ServiceEntry = ServiceListHead.Flink; 2089 while (ServiceEntry != &ServiceListHead) 2090 { 2091 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2092 2093 if ((CurrentService->lpGroup == CurrentGroup) && 2094 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2095 (CurrentService->ServiceVisited == FALSE)) 2096 { 2097 CurrentService->ServiceVisited = TRUE; 2098 ScmLoadService(CurrentService, 0, NULL); 2099 } 2100 2101 ServiceEntry = ServiceEntry->Flink; 2102 } 2103 2104 GroupEntry = GroupEntry->Flink; 2105 } 2106 2107 /* Start all services which are members of any non-existing group */ 2108 ServiceEntry = ServiceListHead.Flink; 2109 while (ServiceEntry != &ServiceListHead) 2110 { 2111 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2112 2113 if ((CurrentService->lpGroup != NULL) && 2114 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2115 (CurrentService->ServiceVisited == FALSE)) 2116 { 2117 CurrentService->ServiceVisited = TRUE; 2118 ScmLoadService(CurrentService, 0, NULL); 2119 } 2120 2121 ServiceEntry = ServiceEntry->Flink; 2122 } 2123 2124 /* Start all services which are not a member of any group */ 2125 ServiceEntry = ServiceListHead.Flink; 2126 while (ServiceEntry != &ServiceListHead) 2127 { 2128 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2129 2130 if ((CurrentService->lpGroup == NULL) && 2131 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2132 (CurrentService->ServiceVisited == FALSE)) 2133 { 2134 CurrentService->ServiceVisited = TRUE; 2135 ScmLoadService(CurrentService, 0, NULL); 2136 } 2137 2138 ServiceEntry = ServiceEntry->Flink; 2139 } 2140 2141 /* Clear 'ServiceVisited' flag again */ 2142 ServiceEntry = ServiceListHead.Flink; 2143 while (ServiceEntry != &ServiceListHead) 2144 { 2145 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2146 CurrentService->ServiceVisited = FALSE; 2147 ServiceEntry = ServiceEntry->Flink; 2148 } 2149 2150 /* Release the critical section */ 2151 LeaveCriticalSection(&ControlServiceCriticalSection); 2152 } 2153 2154 2155 VOID 2156 ScmAutoShutdownServices(VOID) 2157 { 2158 PLIST_ENTRY ServiceEntry; 2159 PSERVICE CurrentService; 2160 2161 DPRINT("ScmAutoShutdownServices() called\n"); 2162 2163 /* Lock the service database exclusively */ 2164 ScmLockDatabaseExclusive(); 2165 2166 ServiceEntry = ServiceListHead.Flink; 2167 while (ServiceEntry != &ServiceListHead) 2168 { 2169 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2170 2171 if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) && 2172 (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || 2173 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)) 2174 { 2175 /* Send the shutdown notification */ 2176 DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName); 2177 ScmControlService(CurrentService->lpImage->hControlPipe, 2178 CurrentService->lpServiceName, 2179 (SERVICE_STATUS_HANDLE)CurrentService, 2180 SERVICE_CONTROL_SHUTDOWN); 2181 } 2182 2183 ServiceEntry = ServiceEntry->Flink; 2184 } 2185 2186 /* Unlock the service database */ 2187 ScmUnlockDatabase(); 2188 2189 DPRINT("ScmAutoShutdownServices() done\n"); 2190 } 2191 2192 2193 BOOL 2194 ScmLockDatabaseExclusive(VOID) 2195 { 2196 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE); 2197 } 2198 2199 2200 BOOL 2201 ScmLockDatabaseShared(VOID) 2202 { 2203 return RtlAcquireResourceShared(&DatabaseLock, TRUE); 2204 } 2205 2206 2207 VOID 2208 ScmUnlockDatabase(VOID) 2209 { 2210 RtlReleaseResource(&DatabaseLock); 2211 } 2212 2213 2214 VOID 2215 ScmInitNamedPipeCriticalSection(VOID) 2216 { 2217 HKEY hKey; 2218 DWORD dwKeySize; 2219 DWORD dwError; 2220 2221 InitializeCriticalSection(&ControlServiceCriticalSection); 2222 2223 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2224 L"SYSTEM\\CurrentControlSet\\Control", 2225 0, 2226 KEY_READ, 2227 &hKey); 2228 if (dwError == ERROR_SUCCESS) 2229 { 2230 dwKeySize = sizeof(PipeTimeout); 2231 RegQueryValueExW(hKey, 2232 L"ServicesPipeTimeout", 2233 0, 2234 NULL, 2235 (LPBYTE)&PipeTimeout, 2236 &dwKeySize); 2237 RegCloseKey(hKey); 2238 } 2239 } 2240 2241 2242 VOID 2243 ScmDeleteNamedPipeCriticalSection(VOID) 2244 { 2245 DeleteCriticalSection(&ControlServiceCriticalSection); 2246 } 2247 2248 /* EOF */ 2249