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