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