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