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->dwTag == 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->dwTag = 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 856 static DWORD 857 CreateServiceListEntry(LPCWSTR lpServiceName, 858 HKEY hServiceKey) 859 { 860 PSERVICE lpService = NULL; 861 LPWSTR lpDisplayName = NULL; 862 LPWSTR lpGroup = NULL; 863 DWORD dwSize; 864 DWORD dwError; 865 DWORD dwServiceType; 866 DWORD dwStartType; 867 DWORD dwErrorControl; 868 DWORD dwTagId; 869 870 DPRINT("Service: '%S'\n", lpServiceName); 871 if (*lpServiceName == L'{') 872 return ERROR_SUCCESS; 873 874 dwSize = sizeof(DWORD); 875 dwError = RegQueryValueExW(hServiceKey, 876 L"Type", 877 NULL, 878 NULL, 879 (LPBYTE)&dwServiceType, 880 &dwSize); 881 if (dwError != ERROR_SUCCESS) 882 return ERROR_SUCCESS; 883 884 if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && 885 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) && 886 (dwServiceType != SERVICE_KERNEL_DRIVER) && 887 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) 888 return ERROR_SUCCESS; 889 890 DPRINT("Service type: %lx\n", dwServiceType); 891 892 dwSize = sizeof(DWORD); 893 dwError = RegQueryValueExW(hServiceKey, 894 L"Start", 895 NULL, 896 NULL, 897 (LPBYTE)&dwStartType, 898 &dwSize); 899 if (dwError != ERROR_SUCCESS) 900 return ERROR_SUCCESS; 901 902 DPRINT("Start type: %lx\n", dwStartType); 903 904 dwSize = sizeof(DWORD); 905 dwError = RegQueryValueExW(hServiceKey, 906 L"ErrorControl", 907 NULL, 908 NULL, 909 (LPBYTE)&dwErrorControl, 910 &dwSize); 911 if (dwError != ERROR_SUCCESS) 912 return ERROR_SUCCESS; 913 914 DPRINT("Error control: %lx\n", dwErrorControl); 915 916 dwError = RegQueryValueExW(hServiceKey, 917 L"Tag", 918 NULL, 919 NULL, 920 (LPBYTE)&dwTagId, 921 &dwSize); 922 if (dwError != ERROR_SUCCESS) 923 dwTagId = 0; 924 925 DPRINT("Tag: %lx\n", dwTagId); 926 927 dwError = ScmReadString(hServiceKey, 928 L"Group", 929 &lpGroup); 930 if (dwError != ERROR_SUCCESS) 931 lpGroup = NULL; 932 933 DPRINT("Group: %S\n", lpGroup); 934 935 dwError = ScmReadString(hServiceKey, 936 L"DisplayName", 937 &lpDisplayName); 938 if (dwError != ERROR_SUCCESS) 939 lpDisplayName = NULL; 940 941 DPRINT("Display name: %S\n", lpDisplayName); 942 943 dwError = ScmCreateNewServiceRecord(lpServiceName, 944 &lpService, 945 dwServiceType, 946 dwStartType); 947 if (dwError != ERROR_SUCCESS) 948 goto done; 949 950 lpService->dwErrorControl = dwErrorControl; 951 lpService->dwTag = dwTagId; 952 953 if (lpGroup != NULL) 954 { 955 dwError = ScmSetServiceGroup(lpService, lpGroup); 956 if (dwError != ERROR_SUCCESS) 957 goto done; 958 } 959 960 if (lpDisplayName != NULL) 961 { 962 lpService->lpDisplayName = lpDisplayName; 963 lpDisplayName = NULL; 964 } 965 966 DPRINT("ServiceName: '%S'\n", lpService->lpServiceName); 967 if (lpService->lpGroup != NULL) 968 { 969 DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName); 970 } 971 DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n", 972 lpService->dwStartType, 973 lpService->Status.dwServiceType, 974 lpService->dwTag, 975 lpService->dwErrorControl); 976 977 if (ScmIsDeleteFlagSet(hServiceKey)) 978 lpService->bDeleted = TRUE; 979 else 980 ScmGenerateServiceTag(lpService); 981 982 if (lpService->Status.dwServiceType & SERVICE_WIN32) 983 { 984 dwError = ScmReadSecurityDescriptor(hServiceKey, 985 &lpService->pSecurityDescriptor); 986 if (dwError != ERROR_SUCCESS) 987 goto done; 988 989 /* Assing the default security descriptor if the security descriptor cannot be read */ 990 if (lpService->pSecurityDescriptor == NULL) 991 { 992 DPRINT("No security descriptor found! Assign default security descriptor\n"); 993 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor); 994 if (dwError != ERROR_SUCCESS) 995 goto done; 996 997 dwError = ScmWriteSecurityDescriptor(hServiceKey, 998 lpService->pSecurityDescriptor); 999 if (dwError != ERROR_SUCCESS) 1000 goto done; 1001 } 1002 } 1003 1004 done: 1005 if (lpGroup != NULL) 1006 HeapFree(GetProcessHeap(), 0, lpGroup); 1007 1008 if (lpDisplayName != NULL) 1009 HeapFree(GetProcessHeap(), 0, lpDisplayName); 1010 1011 if (lpService != NULL) 1012 { 1013 ASSERT(lpService->lpImage == NULL); 1014 } 1015 1016 return dwError; 1017 } 1018 1019 1020 VOID 1021 ScmDeleteMarkedServices(VOID) 1022 { 1023 PLIST_ENTRY ServiceEntry; 1024 PSERVICE CurrentService; 1025 HKEY hServicesKey; 1026 DWORD dwError; 1027 1028 ServiceEntry = ServiceListHead.Flink; 1029 while (ServiceEntry != &ServiceListHead) 1030 { 1031 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 1032 1033 ServiceEntry = ServiceEntry->Flink; 1034 1035 if (CurrentService->bDeleted != FALSE) 1036 { 1037 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1038 L"System\\CurrentControlSet\\Services", 1039 0, 1040 DELETE, 1041 &hServicesKey); 1042 if (dwError == ERROR_SUCCESS) 1043 { 1044 dwError = ScmDeleteRegKey(hServicesKey, CurrentService->lpServiceName); 1045 RegCloseKey(hServicesKey); 1046 if (dwError == ERROR_SUCCESS) 1047 { 1048 RemoveEntryList(&CurrentService->ServiceListEntry); 1049 HeapFree(GetProcessHeap(), 0, CurrentService); 1050 } 1051 } 1052 1053 if (dwError != ERROR_SUCCESS) 1054 DPRINT1("Delete service failed: %S\n", CurrentService->lpServiceName); 1055 } 1056 } 1057 } 1058 1059 1060 static 1061 VOID 1062 ScmGetNoInteractiveServicesValue(VOID) 1063 { 1064 HKEY hKey; 1065 DWORD dwKeySize; 1066 LONG lError; 1067 1068 lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1069 L"SYSTEM\\CurrentControlSet\\Control\\Windows", 1070 0, 1071 KEY_READ, 1072 &hKey); 1073 if (lError == ERROR_SUCCESS) 1074 { 1075 dwKeySize = sizeof(NoInteractiveServices); 1076 lError = RegQueryValueExW(hKey, 1077 L"NoInteractiveServices", 1078 0, 1079 NULL, 1080 (LPBYTE)&NoInteractiveServices, 1081 &dwKeySize); 1082 RegCloseKey(hKey); 1083 } 1084 } 1085 1086 1087 DWORD 1088 ScmCreateServiceDatabase(VOID) 1089 { 1090 WCHAR szSubKey[MAX_PATH]; 1091 HKEY hServicesKey; 1092 HKEY hServiceKey; 1093 DWORD dwSubKey; 1094 DWORD dwSubKeyLength; 1095 FILETIME ftLastChanged; 1096 DWORD dwError; 1097 1098 DPRINT("ScmCreateServiceDatabase() called\n"); 1099 1100 /* Retrieve the NoInteractiveServies value */ 1101 ScmGetNoInteractiveServicesValue(); 1102 1103 /* Create the service group list */ 1104 dwError = ScmCreateGroupList(); 1105 if (dwError != ERROR_SUCCESS) 1106 return dwError; 1107 1108 /* Initialize image and service lists */ 1109 InitializeListHead(&ImageListHead); 1110 InitializeListHead(&ServiceListHead); 1111 1112 /* Initialize the database lock */ 1113 RtlInitializeResource(&DatabaseLock); 1114 1115 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1116 L"System\\CurrentControlSet\\Services", 1117 0, 1118 KEY_READ, 1119 &hServicesKey); 1120 if (dwError != ERROR_SUCCESS) 1121 return dwError; 1122 1123 dwSubKey = 0; 1124 for (;;) 1125 { 1126 dwSubKeyLength = MAX_PATH; 1127 dwError = RegEnumKeyExW(hServicesKey, 1128 dwSubKey, 1129 szSubKey, 1130 &dwSubKeyLength, 1131 NULL, 1132 NULL, 1133 NULL, 1134 &ftLastChanged); 1135 if (dwError == ERROR_SUCCESS && 1136 szSubKey[0] != L'{') 1137 { 1138 DPRINT("SubKeyName: '%S'\n", szSubKey); 1139 1140 dwError = RegOpenKeyExW(hServicesKey, 1141 szSubKey, 1142 0, 1143 KEY_READ, 1144 &hServiceKey); 1145 if (dwError == ERROR_SUCCESS) 1146 { 1147 dwError = CreateServiceListEntry(szSubKey, 1148 hServiceKey); 1149 1150 RegCloseKey(hServiceKey); 1151 } 1152 } 1153 1154 if (dwError != ERROR_SUCCESS) 1155 break; 1156 1157 dwSubKey++; 1158 } 1159 1160 RegCloseKey(hServicesKey); 1161 1162 /* Wait for the LSA server */ 1163 ScmWaitForLsa(); 1164 1165 /* Delete services that are marked for delete */ 1166 ScmDeleteMarkedServices(); 1167 1168 DPRINT("ScmCreateServiceDatabase() done\n"); 1169 1170 return ERROR_SUCCESS; 1171 } 1172 1173 1174 VOID 1175 ScmShutdownServiceDatabase(VOID) 1176 { 1177 DPRINT("ScmShutdownServiceDatabase() called\n"); 1178 1179 ScmDeleteMarkedServices(); 1180 RtlDeleteResource(&DatabaseLock); 1181 1182 DPRINT("ScmShutdownServiceDatabase() done\n"); 1183 } 1184 1185 1186 static NTSTATUS 1187 ScmCheckDriver(PSERVICE Service) 1188 { 1189 OBJECT_ATTRIBUTES ObjectAttributes; 1190 UNICODE_STRING DirName; 1191 HANDLE DirHandle; 1192 NTSTATUS Status; 1193 POBJECT_DIRECTORY_INFORMATION DirInfo; 1194 ULONG BufferLength; 1195 ULONG DataLength; 1196 ULONG Index; 1197 1198 DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName); 1199 1200 if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER) 1201 { 1202 RtlInitUnicodeString(&DirName, L"\\Driver"); 1203 } 1204 else // if (Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER) 1205 { 1206 ASSERT(Service->Status.dwServiceType == SERVICE_FILE_SYSTEM_DRIVER); 1207 RtlInitUnicodeString(&DirName, L"\\FileSystem"); 1208 } 1209 1210 InitializeObjectAttributes(&ObjectAttributes, 1211 &DirName, 1212 0, 1213 NULL, 1214 NULL); 1215 1216 Status = NtOpenDirectoryObject(&DirHandle, 1217 DIRECTORY_QUERY | DIRECTORY_TRAVERSE, 1218 &ObjectAttributes); 1219 if (!NT_SUCCESS(Status)) 1220 { 1221 return Status; 1222 } 1223 1224 BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) + 1225 2 * MAX_PATH * sizeof(WCHAR); 1226 DirInfo = HeapAlloc(GetProcessHeap(), 1227 HEAP_ZERO_MEMORY, 1228 BufferLength); 1229 1230 Index = 0; 1231 while (TRUE) 1232 { 1233 Status = NtQueryDirectoryObject(DirHandle, 1234 DirInfo, 1235 BufferLength, 1236 TRUE, 1237 FALSE, 1238 &Index, 1239 &DataLength); 1240 if (Status == STATUS_NO_MORE_ENTRIES) 1241 { 1242 /* FIXME: Add current service to 'failed service' list */ 1243 DPRINT("Service '%S' failed\n", Service->lpServiceName); 1244 break; 1245 } 1246 1247 if (!NT_SUCCESS(Status)) 1248 break; 1249 1250 DPRINT("Comparing: '%S' '%wZ'\n", Service->lpServiceName, &DirInfo->Name); 1251 1252 if (_wcsicmp(Service->lpServiceName, DirInfo->Name.Buffer) == 0) 1253 { 1254 DPRINT("Found: '%S' '%wZ'\n", 1255 Service->lpServiceName, &DirInfo->Name); 1256 1257 /* Mark service as 'running' */ 1258 Service->Status.dwCurrentState = SERVICE_RUNNING; 1259 Service->Status.dwControlsAccepted = SERVICE_ACCEPT_STOP; 1260 Service->Status.dwWin32ExitCode = ERROR_SUCCESS; 1261 Service->Status.dwServiceSpecificExitCode = 0; 1262 Service->Status.dwCheckPoint = 0; 1263 Service->Status.dwWaitHint = 0; 1264 1265 /* Mark the service group as 'running' */ 1266 if (Service->lpGroup != NULL) 1267 { 1268 Service->lpGroup->ServicesRunning = TRUE; 1269 } 1270 1271 break; 1272 } 1273 } 1274 1275 HeapFree(GetProcessHeap(), 1276 0, 1277 DirInfo); 1278 NtClose(DirHandle); 1279 1280 return STATUS_SUCCESS; 1281 } 1282 1283 1284 VOID 1285 ScmGetBootAndSystemDriverState(VOID) 1286 { 1287 PLIST_ENTRY ServiceEntry; 1288 PSERVICE CurrentService; 1289 1290 DPRINT("ScmGetBootAndSystemDriverState() called\n"); 1291 1292 ServiceEntry = ServiceListHead.Flink; 1293 while (ServiceEntry != &ServiceListHead) 1294 { 1295 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 1296 1297 if (CurrentService->dwStartType == SERVICE_BOOT_START || 1298 CurrentService->dwStartType == SERVICE_SYSTEM_START) 1299 { 1300 /* Check driver */ 1301 DPRINT(" Checking service: %S\n", CurrentService->lpServiceName); 1302 1303 ScmCheckDriver(CurrentService); 1304 } 1305 1306 ServiceEntry = ServiceEntry->Flink; 1307 } 1308 1309 DPRINT("ScmGetBootAndSystemDriverState() done\n"); 1310 } 1311 1312 1313 DWORD 1314 ScmControlService(HANDLE hControlPipe, 1315 PWSTR pServiceName, 1316 SERVICE_STATUS_HANDLE hServiceStatus, 1317 DWORD dwControl) 1318 { 1319 PSCM_CONTROL_PACKET ControlPacket; 1320 SCM_REPLY_PACKET ReplyPacket; 1321 1322 DWORD dwWriteCount = 0; 1323 DWORD dwReadCount = 0; 1324 DWORD PacketSize; 1325 PWSTR Ptr; 1326 DWORD dwError = ERROR_SUCCESS; 1327 BOOL bResult; 1328 OVERLAPPED Overlapped = {0}; 1329 1330 DPRINT("ScmControlService() called\n"); 1331 1332 /* Acquire the service control critical section, to synchronize requests */ 1333 EnterCriticalSection(&ControlServiceCriticalSection); 1334 1335 /* Calculate the total length of the start command line */ 1336 PacketSize = sizeof(SCM_CONTROL_PACKET); 1337 PacketSize += (DWORD)((wcslen(pServiceName) + 1) * sizeof(WCHAR)); 1338 1339 ControlPacket = HeapAlloc(GetProcessHeap(), 1340 HEAP_ZERO_MEMORY, 1341 PacketSize); 1342 if (ControlPacket == NULL) 1343 { 1344 LeaveCriticalSection(&ControlServiceCriticalSection); 1345 return ERROR_NOT_ENOUGH_MEMORY; 1346 } 1347 1348 ControlPacket->dwSize = PacketSize; 1349 ControlPacket->dwControl = dwControl; 1350 ControlPacket->hServiceStatus = hServiceStatus; 1351 1352 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); 1353 1354 Ptr = (PWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 1355 wcscpy(Ptr, pServiceName); 1356 1357 ControlPacket->dwArgumentsCount = 0; 1358 ControlPacket->dwArgumentsOffset = 0; 1359 1360 bResult = WriteFile(hControlPipe, 1361 ControlPacket, 1362 PacketSize, 1363 &dwWriteCount, 1364 &Overlapped); 1365 if (bResult == FALSE) 1366 { 1367 DPRINT("WriteFile() returned FALSE\n"); 1368 1369 dwError = GetLastError(); 1370 if (dwError == ERROR_IO_PENDING) 1371 { 1372 DPRINT("dwError: ERROR_IO_PENDING\n"); 1373 1374 dwError = WaitForSingleObject(hControlPipe, 1375 PipeTimeout); 1376 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1377 1378 if (dwError == WAIT_TIMEOUT) 1379 { 1380 bResult = CancelIo(hControlPipe); 1381 if (bResult == FALSE) 1382 { 1383 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1384 } 1385 1386 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1387 goto Done; 1388 } 1389 else if (dwError == WAIT_OBJECT_0) 1390 { 1391 bResult = GetOverlappedResult(hControlPipe, 1392 &Overlapped, 1393 &dwWriteCount, 1394 TRUE); 1395 if (bResult == FALSE) 1396 { 1397 dwError = GetLastError(); 1398 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1399 1400 goto Done; 1401 } 1402 } 1403 } 1404 else 1405 { 1406 DPRINT1("WriteFile() failed (Error %lu)\n", dwError); 1407 goto Done; 1408 } 1409 } 1410 1411 /* Read the reply */ 1412 Overlapped.hEvent = (HANDLE) NULL; 1413 1414 bResult = ReadFile(hControlPipe, 1415 &ReplyPacket, 1416 sizeof(SCM_REPLY_PACKET), 1417 &dwReadCount, 1418 &Overlapped); 1419 if (bResult == FALSE) 1420 { 1421 DPRINT("ReadFile() returned FALSE\n"); 1422 1423 dwError = GetLastError(); 1424 if (dwError == ERROR_IO_PENDING) 1425 { 1426 DPRINT("dwError: ERROR_IO_PENDING\n"); 1427 1428 dwError = WaitForSingleObject(hControlPipe, 1429 PipeTimeout); 1430 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1431 1432 if (dwError == WAIT_TIMEOUT) 1433 { 1434 bResult = CancelIo(hControlPipe); 1435 if (bResult == FALSE) 1436 { 1437 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1438 } 1439 1440 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1441 goto Done; 1442 } 1443 else if (dwError == WAIT_OBJECT_0) 1444 { 1445 bResult = GetOverlappedResult(hControlPipe, 1446 &Overlapped, 1447 &dwReadCount, 1448 TRUE); 1449 if (bResult == FALSE) 1450 { 1451 dwError = GetLastError(); 1452 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1453 1454 goto Done; 1455 } 1456 } 1457 } 1458 else 1459 { 1460 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 1461 goto Done; 1462 } 1463 } 1464 1465 Done: 1466 /* Release the control packet */ 1467 HeapFree(GetProcessHeap(), 1468 0, 1469 ControlPacket); 1470 1471 if (dwReadCount == sizeof(SCM_REPLY_PACKET)) 1472 { 1473 dwError = ReplyPacket.dwError; 1474 } 1475 1476 LeaveCriticalSection(&ControlServiceCriticalSection); 1477 1478 DPRINT("ScmControlService() done\n"); 1479 1480 return dwError; 1481 } 1482 1483 1484 static DWORD 1485 ScmSendStartCommand(PSERVICE Service, 1486 DWORD argc, 1487 LPWSTR* argv) 1488 { 1489 DWORD dwError = ERROR_SUCCESS; 1490 PSCM_CONTROL_PACKET ControlPacket; 1491 SCM_REPLY_PACKET ReplyPacket; 1492 DWORD PacketSize; 1493 DWORD i; 1494 PWSTR Ptr; 1495 PWSTR *pOffPtr; 1496 PWSTR pArgPtr; 1497 BOOL bResult; 1498 DWORD dwWriteCount = 0; 1499 DWORD dwReadCount = 0; 1500 OVERLAPPED Overlapped = {0}; 1501 1502 DPRINT("ScmSendStartCommand() called\n"); 1503 1504 /* Calculate the total length of the start command line */ 1505 PacketSize = sizeof(SCM_CONTROL_PACKET); 1506 PacketSize += (DWORD)((wcslen(Service->lpServiceName) + 1) * sizeof(WCHAR)); 1507 1508 /* 1509 * Calculate the required packet size for the start argument vector 'argv', 1510 * composed of the list of pointer offsets, followed by UNICODE strings. 1511 * The strings are stored continuously after the vector of offsets, with 1512 * the offsets being relative to the beginning of the vector, as in the 1513 * following layout (with N == argc): 1514 * [argOff(0)]...[argOff(N-1)][str(0)]...[str(N-1)] . 1515 */ 1516 if (argc > 0 && argv != NULL) 1517 { 1518 PacketSize = ALIGN_UP(PacketSize, PWSTR); 1519 PacketSize += (argc * sizeof(PWSTR)); 1520 1521 DPRINT("Argc: %lu\n", argc); 1522 for (i = 0; i < argc; i++) 1523 { 1524 DPRINT("Argv[%lu]: %S\n", i, argv[i]); 1525 PacketSize += (DWORD)((wcslen(argv[i]) + 1) * sizeof(WCHAR)); 1526 } 1527 } 1528 1529 /* Allocate a control packet */ 1530 ControlPacket = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, PacketSize); 1531 if (ControlPacket == NULL) 1532 return ERROR_NOT_ENOUGH_MEMORY; 1533 1534 ControlPacket->dwSize = PacketSize; 1535 ControlPacket->dwControl = (Service->Status.dwServiceType & SERVICE_WIN32_OWN_PROCESS) 1536 ? SERVICE_CONTROL_START_OWN 1537 : SERVICE_CONTROL_START_SHARE; 1538 ControlPacket->hServiceStatus = (SERVICE_STATUS_HANDLE)Service; 1539 ControlPacket->dwServiceTag = Service->dwTag; 1540 1541 /* Copy the start command line */ 1542 ControlPacket->dwServiceNameOffset = sizeof(SCM_CONTROL_PACKET); 1543 Ptr = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); 1544 wcscpy(Ptr, Service->lpServiceName); 1545 1546 ControlPacket->dwArgumentsCount = 0; 1547 ControlPacket->dwArgumentsOffset = 0; 1548 1549 /* Copy the argument vector */ 1550 if (argc > 0 && argv != NULL) 1551 { 1552 Ptr += wcslen(Service->lpServiceName) + 1; 1553 pOffPtr = (PWSTR*)ALIGN_UP_POINTER(Ptr, PWSTR); 1554 pArgPtr = (PWSTR)((ULONG_PTR)pOffPtr + argc * sizeof(PWSTR)); 1555 1556 ControlPacket->dwArgumentsCount = argc; 1557 ControlPacket->dwArgumentsOffset = (DWORD)((ULONG_PTR)pOffPtr - (ULONG_PTR)ControlPacket); 1558 1559 DPRINT("dwArgumentsCount: %lu\n", ControlPacket->dwArgumentsCount); 1560 DPRINT("dwArgumentsOffset: %lu\n", ControlPacket->dwArgumentsOffset); 1561 1562 for (i = 0; i < argc; i++) 1563 { 1564 wcscpy(pArgPtr, argv[i]); 1565 pOffPtr[i] = (PWSTR)((ULONG_PTR)pArgPtr - (ULONG_PTR)pOffPtr); 1566 DPRINT("offset[%lu]: %p\n", i, pOffPtr[i]); 1567 pArgPtr += wcslen(argv[i]) + 1; 1568 } 1569 } 1570 1571 bResult = WriteFile(Service->lpImage->hControlPipe, 1572 ControlPacket, 1573 PacketSize, 1574 &dwWriteCount, 1575 &Overlapped); 1576 if (bResult == FALSE) 1577 { 1578 DPRINT("WriteFile() returned FALSE\n"); 1579 1580 dwError = GetLastError(); 1581 if (dwError == ERROR_IO_PENDING) 1582 { 1583 DPRINT("dwError: ERROR_IO_PENDING\n"); 1584 1585 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1586 PipeTimeout); 1587 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1588 1589 if (dwError == WAIT_TIMEOUT) 1590 { 1591 bResult = CancelIo(Service->lpImage->hControlPipe); 1592 if (bResult == FALSE) 1593 { 1594 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1595 } 1596 1597 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1598 goto Done; 1599 } 1600 else if (dwError == WAIT_OBJECT_0) 1601 { 1602 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1603 &Overlapped, 1604 &dwWriteCount, 1605 TRUE); 1606 if (bResult == FALSE) 1607 { 1608 dwError = GetLastError(); 1609 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1610 1611 goto Done; 1612 } 1613 } 1614 } 1615 else 1616 { 1617 DPRINT1("WriteFile() failed (Error %lu)\n", dwError); 1618 goto Done; 1619 } 1620 } 1621 1622 /* Read the reply */ 1623 Overlapped.hEvent = (HANDLE) NULL; 1624 1625 bResult = ReadFile(Service->lpImage->hControlPipe, 1626 &ReplyPacket, 1627 sizeof(SCM_REPLY_PACKET), 1628 &dwReadCount, 1629 &Overlapped); 1630 if (bResult == FALSE) 1631 { 1632 DPRINT("ReadFile() returned FALSE\n"); 1633 1634 dwError = GetLastError(); 1635 if (dwError == ERROR_IO_PENDING) 1636 { 1637 DPRINT("dwError: ERROR_IO_PENDING\n"); 1638 1639 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1640 PipeTimeout); 1641 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1642 1643 if (dwError == WAIT_TIMEOUT) 1644 { 1645 bResult = CancelIo(Service->lpImage->hControlPipe); 1646 if (bResult == FALSE) 1647 { 1648 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1649 } 1650 1651 dwError = ERROR_SERVICE_REQUEST_TIMEOUT; 1652 goto Done; 1653 } 1654 else if (dwError == WAIT_OBJECT_0) 1655 { 1656 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1657 &Overlapped, 1658 &dwReadCount, 1659 TRUE); 1660 if (bResult == FALSE) 1661 { 1662 dwError = GetLastError(); 1663 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1664 1665 goto Done; 1666 } 1667 } 1668 } 1669 else 1670 { 1671 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 1672 goto Done; 1673 } 1674 } 1675 1676 Done: 1677 /* Release the control packet */ 1678 HeapFree(GetProcessHeap(), 1679 0, 1680 ControlPacket); 1681 1682 if (dwReadCount == sizeof(SCM_REPLY_PACKET)) 1683 { 1684 dwError = ReplyPacket.dwError; 1685 } 1686 1687 DPRINT("ScmSendStartCommand() done\n"); 1688 1689 return dwError; 1690 } 1691 1692 1693 static DWORD 1694 ScmWaitForServiceConnect(PSERVICE Service) 1695 { 1696 DWORD dwRead = 0; 1697 DWORD dwProcessId = 0; 1698 DWORD dwError = ERROR_SUCCESS; 1699 BOOL bResult; 1700 OVERLAPPED Overlapped = {0}; 1701 #if 0 1702 LPCWSTR lpLogStrings[3]; 1703 WCHAR szBuffer1[20]; 1704 WCHAR szBuffer2[20]; 1705 #endif 1706 1707 DPRINT("ScmWaitForServiceConnect()\n"); 1708 1709 Overlapped.hEvent = (HANDLE)NULL; 1710 1711 bResult = ConnectNamedPipe(Service->lpImage->hControlPipe, 1712 &Overlapped); 1713 if (bResult == FALSE) 1714 { 1715 DPRINT("ConnectNamedPipe() returned FALSE\n"); 1716 1717 dwError = GetLastError(); 1718 if (dwError == ERROR_IO_PENDING) 1719 { 1720 DPRINT("dwError: ERROR_IO_PENDING\n"); 1721 1722 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1723 PipeTimeout); 1724 DPRINT("WaitForSingleObject() returned %lu\n", dwError); 1725 1726 if (dwError == WAIT_TIMEOUT) 1727 { 1728 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); 1729 1730 bResult = CancelIo(Service->lpImage->hControlPipe); 1731 if (bResult == FALSE) 1732 { 1733 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1734 } 1735 1736 #if 0 1737 _ultow(PipeTimeout, szBuffer1, 10); 1738 lpLogStrings[0] = Service->lpDisplayName; 1739 lpLogStrings[1] = szBuffer1; 1740 1741 ScmLogEvent(EVENT_CONNECTION_TIMEOUT, 1742 EVENTLOG_ERROR_TYPE, 1743 2, 1744 lpLogStrings); 1745 #endif 1746 DPRINT1("Log EVENT_CONNECTION_TIMEOUT by %S\n", Service->lpDisplayName); 1747 1748 return ERROR_SERVICE_REQUEST_TIMEOUT; 1749 } 1750 else if (dwError == WAIT_OBJECT_0) 1751 { 1752 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1753 &Overlapped, 1754 &dwRead, 1755 TRUE); 1756 if (bResult == FALSE) 1757 { 1758 dwError = GetLastError(); 1759 DPRINT1("GetOverlappedResult failed (Error %lu)\n", dwError); 1760 1761 return dwError; 1762 } 1763 } 1764 } 1765 else if (dwError != ERROR_PIPE_CONNECTED) 1766 { 1767 DPRINT1("ConnectNamedPipe failed (Error %lu)\n", dwError); 1768 return dwError; 1769 } 1770 } 1771 1772 DPRINT("Control pipe connected\n"); 1773 1774 Overlapped.hEvent = (HANDLE) NULL; 1775 1776 /* Read the process id from pipe */ 1777 bResult = ReadFile(Service->lpImage->hControlPipe, 1778 (LPVOID)&dwProcessId, 1779 sizeof(DWORD), 1780 &dwRead, 1781 &Overlapped); 1782 if (bResult == FALSE) 1783 { 1784 DPRINT("ReadFile() returned FALSE\n"); 1785 1786 dwError = GetLastError(); 1787 if (dwError == ERROR_IO_PENDING) 1788 { 1789 DPRINT("dwError: ERROR_IO_PENDING\n"); 1790 1791 dwError = WaitForSingleObject(Service->lpImage->hControlPipe, 1792 PipeTimeout); 1793 if (dwError == WAIT_TIMEOUT) 1794 { 1795 DPRINT("WaitForSingleObject() returned WAIT_TIMEOUT\n"); 1796 1797 bResult = CancelIo(Service->lpImage->hControlPipe); 1798 if (bResult == FALSE) 1799 { 1800 DPRINT1("CancelIo() failed (Error: %lu)\n", GetLastError()); 1801 } 1802 1803 #if 0 1804 _ultow(PipeTimeout, szBuffer1, 10); 1805 lpLogStrings[0] = szBuffer1; 1806 1807 ScmLogEvent(EVENT_READFILE_TIMEOUT, 1808 EVENTLOG_ERROR_TYPE, 1809 1, 1810 lpLogStrings); 1811 #endif 1812 DPRINT1("Log EVENT_READFILE_TIMEOUT by %S\n", Service->lpDisplayName); 1813 1814 return ERROR_SERVICE_REQUEST_TIMEOUT; 1815 } 1816 else if (dwError == WAIT_OBJECT_0) 1817 { 1818 DPRINT("WaitForSingleObject() returned WAIT_OBJECT_0\n"); 1819 1820 DPRINT("Process Id: %lu\n", dwProcessId); 1821 1822 bResult = GetOverlappedResult(Service->lpImage->hControlPipe, 1823 &Overlapped, 1824 &dwRead, 1825 TRUE); 1826 if (bResult == FALSE) 1827 { 1828 dwError = GetLastError(); 1829 DPRINT1("GetOverlappedResult() failed (Error %lu)\n", dwError); 1830 1831 return dwError; 1832 } 1833 } 1834 else 1835 { 1836 DPRINT1("WaitForSingleObject() returned %lu\n", dwError); 1837 } 1838 } 1839 else 1840 { 1841 DPRINT1("ReadFile() failed (Error %lu)\n", dwError); 1842 return dwError; 1843 } 1844 } 1845 1846 if ((ScmIsSecurityService(Service->lpImage) == FALSE)&& 1847 (dwProcessId != Service->lpImage->dwProcessId)) 1848 { 1849 #if 0 1850 _ultow(Service->lpImage->dwProcessId, szBuffer1, 10); 1851 _ultow(dwProcessId, szBuffer2, 10); 1852 1853 lpLogStrings[0] = Service->lpDisplayName; 1854 lpLogStrings[1] = szBuffer1; 1855 lpLogStrings[2] = szBuffer2; 1856 1857 ScmLogEvent(EVENT_SERVICE_DIFFERENT_PID_CONNECTED, 1858 EVENTLOG_WARNING_TYPE, 1859 3, 1860 lpLogStrings); 1861 #endif 1862 1863 DPRINT1("Log EVENT_SERVICE_DIFFERENT_PID_CONNECTED by %S\n", Service->lpDisplayName); 1864 } 1865 1866 DPRINT("ScmWaitForServiceConnect() done\n"); 1867 1868 return ERROR_SUCCESS; 1869 } 1870 1871 1872 static DWORD 1873 ScmStartUserModeService(PSERVICE Service, 1874 DWORD argc, 1875 LPWSTR* argv) 1876 { 1877 PROCESS_INFORMATION ProcessInformation; 1878 STARTUPINFOW StartupInfo; 1879 LPVOID lpEnvironment; 1880 BOOL Result; 1881 DWORD dwError = ERROR_SUCCESS; 1882 1883 DPRINT("ScmStartUserModeService(%p)\n", Service); 1884 1885 /* If the image is already running ... */ 1886 if (Service->lpImage->dwImageRunCount > 1) 1887 { 1888 /* ... just send a start command */ 1889 return ScmSendStartCommand(Service, argc, argv); 1890 } 1891 1892 /* Otherwise start its process */ 1893 ZeroMemory(&StartupInfo, sizeof(StartupInfo)); 1894 StartupInfo.cb = sizeof(StartupInfo); 1895 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation)); 1896 1897 if (Service->lpImage->hToken) 1898 { 1899 /* User token: Run the service under the user account */ 1900 1901 if (!CreateEnvironmentBlock(&lpEnvironment, Service->lpImage->hToken, FALSE)) 1902 { 1903 /* We failed, run the service with the current environment */ 1904 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with current environment\n", 1905 GetLastError(), Service->lpServiceName); 1906 lpEnvironment = NULL; 1907 } 1908 1909 /* Impersonate the new user */ 1910 Result = ImpersonateLoggedOnUser(Service->lpImage->hToken); 1911 if (Result) 1912 { 1913 /* Launch the process in the user's logon session */ 1914 Result = CreateProcessAsUserW(Service->lpImage->hToken, 1915 NULL, 1916 Service->lpImage->pszImagePath, 1917 NULL, 1918 NULL, 1919 FALSE, 1920 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, 1921 lpEnvironment, 1922 NULL, 1923 &StartupInfo, 1924 &ProcessInformation); 1925 if (!Result) 1926 dwError = GetLastError(); 1927 1928 /* Revert the impersonation */ 1929 RevertToSelf(); 1930 } 1931 else 1932 { 1933 dwError = GetLastError(); 1934 DPRINT1("ImpersonateLoggedOnUser() failed with error %d\n", dwError); 1935 } 1936 } 1937 else 1938 { 1939 /* No user token: Run the service under the LocalSystem account */ 1940 1941 if (!CreateEnvironmentBlock(&lpEnvironment, NULL, TRUE)) 1942 { 1943 /* We failed, run the service with the current environment */ 1944 DPRINT1("CreateEnvironmentBlock() failed with error %d; service '%S' will run with current environment\n", 1945 GetLastError(), Service->lpServiceName); 1946 lpEnvironment = NULL; 1947 } 1948 1949 /* Use the interactive desktop if the service is interactive */ 1950 if ((NoInteractiveServices == 0) && 1951 (Service->Status.dwServiceType & SERVICE_INTERACTIVE_PROCESS)) 1952 { 1953 StartupInfo.dwFlags |= STARTF_INHERITDESKTOP; 1954 StartupInfo.lpDesktop = L"WinSta0\\Default"; 1955 } 1956 1957 if (!ScmIsSecurityService(Service->lpImage)) 1958 { 1959 Result = CreateProcessW(NULL, 1960 Service->lpImage->pszImagePath, 1961 NULL, 1962 NULL, 1963 FALSE, 1964 CREATE_UNICODE_ENVIRONMENT | DETACHED_PROCESS | CREATE_SUSPENDED, 1965 lpEnvironment, 1966 NULL, 1967 &StartupInfo, 1968 &ProcessInformation); 1969 if (!Result) 1970 dwError = GetLastError(); 1971 } 1972 else 1973 { 1974 Result = TRUE; 1975 dwError = ERROR_SUCCESS; 1976 } 1977 } 1978 1979 if (lpEnvironment) 1980 DestroyEnvironmentBlock(lpEnvironment); 1981 1982 if (!Result) 1983 { 1984 DPRINT1("Starting '%S' failed with error %d\n", 1985 Service->lpServiceName, dwError); 1986 return dwError; 1987 } 1988 1989 DPRINT("Process Id: %lu Handle %p\n", 1990 ProcessInformation.dwProcessId, 1991 ProcessInformation.hProcess); 1992 DPRINT("Thread Id: %lu Handle %p\n", 1993 ProcessInformation.dwThreadId, 1994 ProcessInformation.hThread); 1995 1996 /* Get the process handle and ID */ 1997 Service->lpImage->hProcess = ProcessInformation.hProcess; 1998 Service->lpImage->dwProcessId = ProcessInformation.dwProcessId; 1999 2000 /* Resume the main thread and close its handle */ 2001 ResumeThread(ProcessInformation.hThread); 2002 CloseHandle(ProcessInformation.hThread); 2003 2004 /* Connect control pipe */ 2005 dwError = ScmWaitForServiceConnect(Service); 2006 if (dwError != ERROR_SUCCESS) 2007 { 2008 DPRINT1("Connecting control pipe failed! (Error %lu)\n", dwError); 2009 Service->lpImage->dwProcessId = 0; 2010 return dwError; 2011 } 2012 2013 /* Send the start command */ 2014 return ScmSendStartCommand(Service, argc, argv); 2015 } 2016 2017 2018 static DWORD 2019 ScmLoadService(PSERVICE Service, 2020 DWORD argc, 2021 LPWSTR* argv) 2022 { 2023 PSERVICE_GROUP Group = Service->lpGroup; 2024 DWORD dwError = ERROR_SUCCESS; 2025 LPCWSTR lpLogStrings[2]; 2026 WCHAR szLogBuffer[80]; 2027 2028 DPRINT("ScmLoadService() called\n"); 2029 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 2030 2031 if (Service->Status.dwCurrentState != SERVICE_STOPPED) 2032 { 2033 DPRINT("Service %S is already running\n", Service->lpServiceName); 2034 return ERROR_SERVICE_ALREADY_RUNNING; 2035 } 2036 2037 DPRINT("Service->Type: %lu\n", Service->Status.dwServiceType); 2038 2039 if (Service->Status.dwServiceType & SERVICE_DRIVER) 2040 { 2041 /* Start the driver */ 2042 dwError = ScmStartDriver(Service); 2043 } 2044 else // if (Service->Status.dwServiceType & (SERVICE_WIN32 | SERVICE_INTERACTIVE_PROCESS)) 2045 { 2046 /* Start user-mode service */ 2047 dwError = ScmCreateOrReferenceServiceImage(Service); 2048 if (dwError == ERROR_SUCCESS) 2049 { 2050 dwError = ScmStartUserModeService(Service, argc, argv); 2051 if (dwError == ERROR_SUCCESS) 2052 { 2053 Service->Status.dwCurrentState = SERVICE_START_PENDING; 2054 Service->Status.dwControlsAccepted = 0; 2055 } 2056 else 2057 { 2058 Service->lpImage->dwImageRunCount--; 2059 if (Service->lpImage->dwImageRunCount == 0) 2060 { 2061 ScmRemoveServiceImage(Service->lpImage); 2062 Service->lpImage = NULL; 2063 } 2064 } 2065 } 2066 } 2067 2068 DPRINT("ScmLoadService() done (Error %lu)\n", dwError); 2069 2070 if (dwError == ERROR_SUCCESS) 2071 { 2072 if (Group != NULL) 2073 { 2074 Group->ServicesRunning = TRUE; 2075 } 2076 2077 /* Log a successful service start */ 2078 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_START, szLogBuffer, 80); 2079 lpLogStrings[0] = Service->lpDisplayName; 2080 lpLogStrings[1] = szLogBuffer; 2081 2082 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS, 2083 EVENTLOG_INFORMATION_TYPE, 2084 2, 2085 lpLogStrings); 2086 } 2087 else 2088 { 2089 if (Service->dwErrorControl != SERVICE_ERROR_IGNORE) 2090 { 2091 /* Log a failed service start */ 2092 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer), 2093 L"%lu", dwError); 2094 lpLogStrings[0] = Service->lpServiceName; 2095 lpLogStrings[1] = szLogBuffer; 2096 ScmLogEvent(EVENT_SERVICE_START_FAILED, 2097 EVENTLOG_ERROR_TYPE, 2098 2, 2099 lpLogStrings); 2100 } 2101 2102 #if 0 2103 switch (Service->dwErrorControl) 2104 { 2105 case SERVICE_ERROR_SEVERE: 2106 if (IsLastKnownGood == FALSE) 2107 { 2108 /* FIXME: Boot last known good configuration */ 2109 } 2110 break; 2111 2112 case SERVICE_ERROR_CRITICAL: 2113 if (IsLastKnownGood == FALSE) 2114 { 2115 /* FIXME: Boot last known good configuration */ 2116 } 2117 else 2118 { 2119 /* FIXME: BSOD! */ 2120 } 2121 break; 2122 } 2123 #endif 2124 } 2125 2126 return dwError; 2127 } 2128 2129 2130 DWORD 2131 ScmStartService(PSERVICE Service, 2132 DWORD argc, 2133 LPWSTR* argv) 2134 { 2135 DWORD dwError = ERROR_SUCCESS; 2136 SC_RPC_LOCK Lock = NULL; 2137 2138 DPRINT("ScmStartService() called\n"); 2139 DPRINT("Start Service %p (%S)\n", Service, Service->lpServiceName); 2140 2141 /* Acquire the service control critical section, to synchronize starts */ 2142 EnterCriticalSection(&ControlServiceCriticalSection); 2143 2144 /* 2145 * Acquire the user service start lock while the service is starting, if 2146 * needed (i.e. if we are not starting it during the initialization phase). 2147 * If we don't success, bail out. 2148 */ 2149 if (!ScmInitialize) 2150 { 2151 dwError = ScmAcquireServiceStartLock(TRUE, &Lock); 2152 if (dwError != ERROR_SUCCESS) goto done; 2153 } 2154 2155 /* Really start the service */ 2156 dwError = ScmLoadService(Service, argc, argv); 2157 2158 /* Release the service start lock, if needed, and the critical section */ 2159 if (Lock) ScmReleaseServiceStartLock(&Lock); 2160 2161 done: 2162 LeaveCriticalSection(&ControlServiceCriticalSection); 2163 2164 DPRINT("ScmStartService() done (Error %lu)\n", dwError); 2165 2166 return dwError; 2167 } 2168 2169 2170 VOID 2171 ScmAutoStartServices(VOID) 2172 { 2173 DWORD dwError; 2174 PLIST_ENTRY GroupEntry; 2175 PLIST_ENTRY ServiceEntry; 2176 PSERVICE_GROUP CurrentGroup; 2177 PSERVICE CurrentService; 2178 WCHAR szSafeBootServicePath[MAX_PATH]; 2179 DWORD SafeBootEnabled; 2180 HKEY hKey; 2181 DWORD dwKeySize; 2182 ULONG i; 2183 2184 /* 2185 * This function MUST be called ONLY at initialization time. 2186 * Therefore, no need to acquire the user service start lock. 2187 */ 2188 ASSERT(ScmInitialize); 2189 2190 /* Retrieve the SafeBoot parameter */ 2191 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2192 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot\\Option", 2193 0, 2194 KEY_READ, 2195 &hKey); 2196 if (dwError == ERROR_SUCCESS) 2197 { 2198 dwKeySize = sizeof(SafeBootEnabled); 2199 dwError = RegQueryValueExW(hKey, 2200 L"OptionValue", 2201 0, 2202 NULL, 2203 (LPBYTE)&SafeBootEnabled, 2204 &dwKeySize); 2205 RegCloseKey(hKey); 2206 } 2207 2208 /* Default to Normal boot if the value doesn't exist */ 2209 if (dwError != ERROR_SUCCESS) 2210 SafeBootEnabled = 0; 2211 2212 /* Acquire the service control critical section, to synchronize starts */ 2213 EnterCriticalSection(&ControlServiceCriticalSection); 2214 2215 /* Clear 'ServiceVisited' flag (or set if not to start in Safe Mode) */ 2216 ServiceEntry = ServiceListHead.Flink; 2217 while (ServiceEntry != &ServiceListHead) 2218 { 2219 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2220 2221 /* Build the safe boot path */ 2222 StringCchCopyW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2223 L"SYSTEM\\CurrentControlSet\\Control\\SafeBoot"); 2224 2225 switch (SafeBootEnabled) 2226 { 2227 /* NOTE: Assumes MINIMAL (1) and DSREPAIR (3) load same items */ 2228 case 1: 2229 case 3: 2230 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2231 L"\\Minimal\\"); 2232 break; 2233 2234 case 2: 2235 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2236 L"\\Network\\"); 2237 break; 2238 } 2239 2240 if (SafeBootEnabled != 0) 2241 { 2242 /* If key does not exist then do not assume safe mode */ 2243 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2244 szSafeBootServicePath, 2245 0, 2246 KEY_READ, 2247 &hKey); 2248 if (dwError == ERROR_SUCCESS) 2249 { 2250 RegCloseKey(hKey); 2251 2252 /* Finish Safe Boot path off */ 2253 StringCchCatW(szSafeBootServicePath, ARRAYSIZE(szSafeBootServicePath), 2254 CurrentService->lpServiceName); 2255 2256 /* Check that the key is in the Safe Boot path */ 2257 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2258 szSafeBootServicePath, 2259 0, 2260 KEY_READ, 2261 &hKey); 2262 if (dwError != ERROR_SUCCESS) 2263 { 2264 /* Mark service as visited so it is not auto-started */ 2265 CurrentService->ServiceVisited = TRUE; 2266 } 2267 else 2268 { 2269 /* Must be auto-started in safe mode - mark as unvisited */ 2270 RegCloseKey(hKey); 2271 CurrentService->ServiceVisited = FALSE; 2272 } 2273 } 2274 else 2275 { 2276 DPRINT1("WARNING: Could not open the associated Safe Boot key"); 2277 CurrentService->ServiceVisited = FALSE; 2278 } 2279 } 2280 2281 ServiceEntry = ServiceEntry->Flink; 2282 } 2283 2284 /* Start all services which are members of an existing group */ 2285 GroupEntry = GroupListHead.Flink; 2286 while (GroupEntry != &GroupListHead) 2287 { 2288 CurrentGroup = CONTAINING_RECORD(GroupEntry, SERVICE_GROUP, GroupListEntry); 2289 2290 DPRINT("Group '%S'\n", CurrentGroup->lpGroupName); 2291 2292 /* Start all services witch have a valid tag */ 2293 for (i = 0; i < CurrentGroup->TagCount; i++) 2294 { 2295 ServiceEntry = ServiceListHead.Flink; 2296 while (ServiceEntry != &ServiceListHead) 2297 { 2298 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2299 2300 if ((CurrentService->lpGroup == CurrentGroup) && 2301 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2302 (CurrentService->ServiceVisited == FALSE) && 2303 (CurrentService->dwTag == CurrentGroup->TagArray[i])) 2304 { 2305 CurrentService->ServiceVisited = TRUE; 2306 ScmLoadService(CurrentService, 0, NULL); 2307 } 2308 2309 ServiceEntry = ServiceEntry->Flink; 2310 } 2311 } 2312 2313 /* Start all services which have an invalid tag or which do not have a tag */ 2314 ServiceEntry = ServiceListHead.Flink; 2315 while (ServiceEntry != &ServiceListHead) 2316 { 2317 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2318 2319 if ((CurrentService->lpGroup == CurrentGroup) && 2320 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2321 (CurrentService->ServiceVisited == FALSE)) 2322 { 2323 CurrentService->ServiceVisited = TRUE; 2324 ScmLoadService(CurrentService, 0, NULL); 2325 } 2326 2327 ServiceEntry = ServiceEntry->Flink; 2328 } 2329 2330 GroupEntry = GroupEntry->Flink; 2331 } 2332 2333 /* Start all services which are members of any non-existing group */ 2334 ServiceEntry = ServiceListHead.Flink; 2335 while (ServiceEntry != &ServiceListHead) 2336 { 2337 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2338 2339 if ((CurrentService->lpGroup != NULL) && 2340 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2341 (CurrentService->ServiceVisited == FALSE)) 2342 { 2343 CurrentService->ServiceVisited = TRUE; 2344 ScmLoadService(CurrentService, 0, NULL); 2345 } 2346 2347 ServiceEntry = ServiceEntry->Flink; 2348 } 2349 2350 /* Start all services which are not a member of any group */ 2351 ServiceEntry = ServiceListHead.Flink; 2352 while (ServiceEntry != &ServiceListHead) 2353 { 2354 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2355 2356 if ((CurrentService->lpGroup == NULL) && 2357 (CurrentService->dwStartType == SERVICE_AUTO_START) && 2358 (CurrentService->ServiceVisited == FALSE)) 2359 { 2360 CurrentService->ServiceVisited = TRUE; 2361 ScmLoadService(CurrentService, 0, NULL); 2362 } 2363 2364 ServiceEntry = ServiceEntry->Flink; 2365 } 2366 2367 /* Clear 'ServiceVisited' flag again */ 2368 ServiceEntry = ServiceListHead.Flink; 2369 while (ServiceEntry != &ServiceListHead) 2370 { 2371 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2372 CurrentService->ServiceVisited = FALSE; 2373 ServiceEntry = ServiceEntry->Flink; 2374 } 2375 2376 /* Release the critical section */ 2377 LeaveCriticalSection(&ControlServiceCriticalSection); 2378 } 2379 2380 2381 VOID 2382 ScmAutoShutdownServices(VOID) 2383 { 2384 PLIST_ENTRY ServiceEntry; 2385 PSERVICE CurrentService; 2386 2387 DPRINT("ScmAutoShutdownServices() called\n"); 2388 2389 /* Lock the service database exclusively */ 2390 ScmLockDatabaseExclusive(); 2391 2392 ServiceEntry = ServiceListHead.Flink; 2393 while (ServiceEntry != &ServiceListHead) 2394 { 2395 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 2396 2397 if ((CurrentService->Status.dwControlsAccepted & SERVICE_ACCEPT_SHUTDOWN) && 2398 (CurrentService->Status.dwCurrentState == SERVICE_RUNNING || 2399 CurrentService->Status.dwCurrentState == SERVICE_START_PENDING)) 2400 { 2401 /* Send the shutdown notification */ 2402 DPRINT("Shutdown service: %S\n", CurrentService->lpServiceName); 2403 ScmControlService(CurrentService->lpImage->hControlPipe, 2404 CurrentService->lpServiceName, 2405 (SERVICE_STATUS_HANDLE)CurrentService, 2406 SERVICE_CONTROL_SHUTDOWN); 2407 } 2408 2409 ServiceEntry = ServiceEntry->Flink; 2410 } 2411 2412 /* Unlock the service database */ 2413 ScmUnlockDatabase(); 2414 2415 DPRINT("ScmAutoShutdownServices() done\n"); 2416 } 2417 2418 2419 BOOL 2420 ScmLockDatabaseExclusive(VOID) 2421 { 2422 return RtlAcquireResourceExclusive(&DatabaseLock, TRUE); 2423 } 2424 2425 2426 BOOL 2427 ScmLockDatabaseShared(VOID) 2428 { 2429 return RtlAcquireResourceShared(&DatabaseLock, TRUE); 2430 } 2431 2432 2433 VOID 2434 ScmUnlockDatabase(VOID) 2435 { 2436 RtlReleaseResource(&DatabaseLock); 2437 } 2438 2439 2440 VOID 2441 ScmInitNamedPipeCriticalSection(VOID) 2442 { 2443 HKEY hKey; 2444 DWORD dwKeySize; 2445 DWORD dwError; 2446 2447 InitializeCriticalSection(&ControlServiceCriticalSection); 2448 2449 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2450 L"SYSTEM\\CurrentControlSet\\Control", 2451 0, 2452 KEY_READ, 2453 &hKey); 2454 if (dwError == ERROR_SUCCESS) 2455 { 2456 dwKeySize = sizeof(PipeTimeout); 2457 RegQueryValueExW(hKey, 2458 L"ServicesPipeTimeout", 2459 0, 2460 NULL, 2461 (LPBYTE)&PipeTimeout, 2462 &dwKeySize); 2463 RegCloseKey(hKey); 2464 } 2465 } 2466 2467 2468 VOID 2469 ScmDeleteNamedPipeCriticalSection(VOID) 2470 { 2471 DeleteCriticalSection(&ControlServiceCriticalSection); 2472 } 2473 2474 /* EOF */ 2475