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