1 /* 2 * PROJECT: ReactOS Service Control Manager 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/system/services/rpcserver.c 5 * PURPOSE: RPC server interface for the advapi32 calls 6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl 7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org> 8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 9 */ 10 11 /* INCLUDES ****************************************************************/ 12 13 #include "services.h" 14 15 #include <winnls.h> 16 #include <strsafe.h> 17 18 #include <pseh/pseh2.h> 19 20 #define NDEBUG 21 #include <debug.h> 22 23 /* GLOBALS *****************************************************************/ 24 25 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */ 26 #define SERVICE_TAG 0x63765368 /* 'hSvc' */ 27 #define INVALID_TAG 0xAABBCCDD 28 29 typedef struct _SCMGR_HANDLE 30 { 31 DWORD Tag; 32 DWORD DesiredAccess; 33 } SCMGR_HANDLE; 34 35 36 typedef struct _MANAGER_HANDLE 37 { 38 SCMGR_HANDLE Handle; 39 WCHAR DatabaseName[1]; 40 } MANAGER_HANDLE, *PMANAGER_HANDLE; 41 42 43 typedef struct _SERVICE_HANDLE 44 { 45 SCMGR_HANDLE Handle; 46 PSERVICE ServiceEntry; 47 } SERVICE_HANDLE, *PSERVICE_HANDLE; 48 49 50 #define SC_MANAGER_READ \ 51 (STANDARD_RIGHTS_READ | \ 52 SC_MANAGER_QUERY_LOCK_STATUS | \ 53 SC_MANAGER_ENUMERATE_SERVICE) 54 55 #define SC_MANAGER_WRITE \ 56 (STANDARD_RIGHTS_WRITE | \ 57 SC_MANAGER_MODIFY_BOOT_CONFIG | \ 58 SC_MANAGER_CREATE_SERVICE) 59 60 #define SC_MANAGER_EXECUTE \ 61 (STANDARD_RIGHTS_EXECUTE | \ 62 SC_MANAGER_LOCK | \ 63 SC_MANAGER_ENUMERATE_SERVICE | \ 64 SC_MANAGER_CONNECT | \ 65 SC_MANAGER_CREATE_SERVICE) 66 67 68 #define SERVICE_READ \ 69 (STANDARD_RIGHTS_READ | \ 70 SERVICE_INTERROGATE | \ 71 SERVICE_ENUMERATE_DEPENDENTS | \ 72 SERVICE_QUERY_STATUS | \ 73 SERVICE_QUERY_CONFIG) 74 75 #define SERVICE_WRITE \ 76 (STANDARD_RIGHTS_WRITE | \ 77 SERVICE_CHANGE_CONFIG) 78 79 #define SERVICE_EXECUTE \ 80 (STANDARD_RIGHTS_EXECUTE | \ 81 SERVICE_USER_DEFINED_CONTROL | \ 82 SERVICE_PAUSE_CONTINUE | \ 83 SERVICE_STOP | \ 84 SERVICE_START) 85 86 #define TAG_ARRAY_SIZE 32 87 88 /* VARIABLES ***************************************************************/ 89 90 static GENERIC_MAPPING 91 ScmManagerMapping = {SC_MANAGER_READ, 92 SC_MANAGER_WRITE, 93 SC_MANAGER_EXECUTE, 94 SC_MANAGER_ALL_ACCESS}; 95 96 static GENERIC_MAPPING 97 ScmServiceMapping = {SERVICE_READ, 98 SERVICE_WRITE, 99 SERVICE_EXECUTE, 100 SERVICE_ALL_ACCESS}; 101 102 DWORD g_dwServiceBits = 0; 103 104 /* FUNCTIONS ***************************************************************/ 105 106 VOID 107 ScmStartRpcServer(VOID) 108 { 109 RPC_STATUS Status; 110 111 DPRINT("ScmStartRpcServer() called\n"); 112 113 Status = RpcServerUseProtseqEpW(L"ncacn_np", 114 10, 115 L"\\pipe\\ntsvcs", 116 NULL); 117 if (Status != RPC_S_OK) 118 { 119 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status); 120 return; 121 } 122 123 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec, 124 NULL, 125 NULL); 126 if (Status != RPC_S_OK) 127 { 128 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status); 129 return; 130 } 131 132 Status = RpcServerListen(1, 20, TRUE); 133 if (Status != RPC_S_OK) 134 { 135 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status); 136 return; 137 } 138 139 DPRINT("ScmStartRpcServer() done\n"); 140 } 141 142 143 static DWORD 144 ScmCreateManagerHandle(LPWSTR lpDatabaseName, 145 SC_HANDLE *Handle) 146 { 147 PMANAGER_HANDLE Ptr; 148 149 if (lpDatabaseName == NULL) 150 lpDatabaseName = SERVICES_ACTIVE_DATABASEW; 151 152 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0) 153 { 154 DPRINT("Database %S, does not exist\n", lpDatabaseName); 155 return ERROR_DATABASE_DOES_NOT_EXIST; 156 } 157 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0) 158 { 159 DPRINT("Invalid Database name %S\n", lpDatabaseName); 160 return ERROR_INVALID_NAME; 161 } 162 163 Ptr = HeapAlloc(GetProcessHeap(), 164 HEAP_ZERO_MEMORY, 165 FIELD_OFFSET(MANAGER_HANDLE, DatabaseName[wcslen(lpDatabaseName) + 1])); 166 if (Ptr == NULL) 167 return ERROR_NOT_ENOUGH_MEMORY; 168 169 Ptr->Handle.Tag = MANAGER_TAG; 170 171 wcscpy(Ptr->DatabaseName, lpDatabaseName); 172 173 *Handle = (SC_HANDLE)Ptr; 174 175 return ERROR_SUCCESS; 176 } 177 178 179 static DWORD 180 ScmCreateServiceHandle(PSERVICE lpServiceEntry, 181 SC_HANDLE *Handle) 182 { 183 PSERVICE_HANDLE Ptr; 184 185 Ptr = HeapAlloc(GetProcessHeap(), 186 HEAP_ZERO_MEMORY, 187 sizeof(SERVICE_HANDLE)); 188 if (Ptr == NULL) 189 return ERROR_NOT_ENOUGH_MEMORY; 190 191 Ptr->Handle.Tag = SERVICE_TAG; 192 193 Ptr->ServiceEntry = lpServiceEntry; 194 195 *Handle = (SC_HANDLE)Ptr; 196 197 return ERROR_SUCCESS; 198 } 199 200 201 static PMANAGER_HANDLE 202 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle) 203 { 204 PMANAGER_HANDLE pManager = NULL; 205 206 _SEH2_TRY 207 { 208 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG) 209 pManager = (PMANAGER_HANDLE)Handle; 210 } 211 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 212 { 213 DPRINT1("Exception: Invalid Service Manager handle\n"); 214 } 215 _SEH2_END; 216 217 return pManager; 218 } 219 220 221 static PSERVICE_HANDLE 222 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle) 223 { 224 PSERVICE_HANDLE pService = NULL; 225 226 _SEH2_TRY 227 { 228 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG) 229 pService = (PSERVICE_HANDLE)Handle; 230 } 231 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 232 { 233 DPRINT1("Exception: Invalid Service handle\n"); 234 } 235 _SEH2_END; 236 237 return pService; 238 } 239 240 241 static DWORD 242 ScmCheckAccess(SC_HANDLE Handle, 243 DWORD dwDesiredAccess) 244 { 245 PMANAGER_HANDLE hMgr; 246 247 hMgr = (PMANAGER_HANDLE)Handle; 248 if (hMgr->Handle.Tag == MANAGER_TAG) 249 { 250 RtlMapGenericMask(&dwDesiredAccess, 251 &ScmManagerMapping); 252 253 hMgr->Handle.DesiredAccess = dwDesiredAccess; 254 255 return ERROR_SUCCESS; 256 } 257 else if (hMgr->Handle.Tag == SERVICE_TAG) 258 { 259 RtlMapGenericMask(&dwDesiredAccess, 260 &ScmServiceMapping); 261 262 hMgr->Handle.DesiredAccess = dwDesiredAccess; 263 264 return ERROR_SUCCESS; 265 } 266 267 return ERROR_INVALID_HANDLE; 268 } 269 270 271 DWORD 272 ScmAssignNewTag(PSERVICE lpService) 273 { 274 HKEY hKey = NULL; 275 DWORD dwError; 276 DWORD dwGroupTagCount = 0; 277 PDWORD pdwGroupTags = NULL; 278 DWORD dwFreeTag = 0; 279 DWORD dwTagUsedBase = 1; 280 BOOLEAN TagUsed[TAG_ARRAY_SIZE]; 281 INT nTagOffset; 282 DWORD i; 283 DWORD cbDataSize; 284 PLIST_ENTRY ServiceEntry; 285 PSERVICE CurrentService; 286 287 ASSERT(lpService != NULL); 288 ASSERT(lpService->lpGroup != NULL); 289 290 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 291 L"System\\CurrentControlSet\\Control\\GroupOrderList", 292 0, 293 KEY_READ, 294 &hKey); 295 296 if (dwError != ERROR_SUCCESS) 297 goto findFreeTag; 298 299 /* query value length */ 300 cbDataSize = 0; 301 dwError = RegQueryValueExW(hKey, 302 lpService->lpGroup->szGroupName, 303 NULL, 304 NULL, 305 NULL, 306 &cbDataSize); 307 308 if (dwError != ERROR_SUCCESS && dwError != ERROR_MORE_DATA) 309 goto findFreeTag; 310 311 pdwGroupTags = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbDataSize); 312 if (!pdwGroupTags) 313 { 314 dwError = ERROR_NOT_ENOUGH_MEMORY; 315 goto cleanup; 316 } 317 318 dwError = RegQueryValueExW(hKey, 319 lpService->lpGroup->szGroupName, 320 NULL, 321 NULL, 322 (LPBYTE)pdwGroupTags, 323 &cbDataSize); 324 325 if (dwError != ERROR_SUCCESS) 326 goto findFreeTag; 327 328 if (cbDataSize < sizeof(pdwGroupTags[0])) 329 goto findFreeTag; 330 331 dwGroupTagCount = min(pdwGroupTags[0], cbDataSize / sizeof(pdwGroupTags[0]) - 1); 332 333 findFreeTag: 334 do 335 { 336 /* mark all tags as unused */ 337 for (i = 0; i < TAG_ARRAY_SIZE; i++) 338 TagUsed[i] = FALSE; 339 340 /* mark tags in GroupOrderList as used */ 341 for (i = 1; i <= dwGroupTagCount; i++) 342 { 343 nTagOffset = pdwGroupTags[i] - dwTagUsedBase; 344 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE) 345 TagUsed[nTagOffset] = TRUE; 346 } 347 348 /* mark tags in service list as used */ 349 ServiceEntry = lpService->ServiceListEntry.Flink; 350 while (ServiceEntry != &lpService->ServiceListEntry) 351 { 352 ASSERT(ServiceEntry != NULL); 353 CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry); 354 if (CurrentService->lpGroup == lpService->lpGroup) 355 { 356 nTagOffset = CurrentService->dwTag - dwTagUsedBase; 357 if (nTagOffset >= 0 && nTagOffset < TAG_ARRAY_SIZE) 358 TagUsed[nTagOffset] = TRUE; 359 } 360 361 ServiceEntry = ServiceEntry->Flink; 362 } 363 364 /* find unused tag, if any */ 365 for (i = 0; i < TAG_ARRAY_SIZE; i++) 366 { 367 if (!TagUsed[i]) 368 { 369 dwFreeTag = dwTagUsedBase + i; 370 break; 371 } 372 } 373 374 dwTagUsedBase += TAG_ARRAY_SIZE; 375 } while (!dwFreeTag); 376 377 cleanup: 378 if (pdwGroupTags) 379 HeapFree(GetProcessHeap(), 0, pdwGroupTags); 380 381 if (hKey) 382 RegCloseKey(hKey); 383 384 if (dwFreeTag) 385 { 386 lpService->dwTag = dwFreeTag; 387 DPRINT("Assigning new tag %lu to service %S in group %S\n", 388 lpService->dwTag, lpService->lpServiceName, lpService->lpGroup->szGroupName); 389 dwError = ERROR_SUCCESS; 390 } 391 else 392 { 393 DPRINT1("Failed to assign new tag to service %S, error=%lu\n", 394 lpService->lpServiceName, dwError); 395 } 396 397 return dwError; 398 } 399 400 401 /* Create a path suitable for the bootloader out of the full path */ 402 DWORD 403 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName) 404 { 405 SIZE_T ServiceNameLen, ExpandedLen; 406 DWORD BufferSize; 407 WCHAR Dest; 408 WCHAR *Expanded; 409 UNICODE_STRING NtPathName, SystemRoot, LinkTarget; 410 OBJECT_ATTRIBUTES ObjectAttributes; 411 NTSTATUS Status; 412 HANDLE SymbolicLinkHandle; 413 414 DPRINT("ScmConvertToBootPathName %S\n", CanonName); 415 416 if (!RelativeName) 417 return ERROR_INVALID_PARAMETER; 418 419 *RelativeName = NULL; 420 421 ServiceNameLen = wcslen(CanonName); 422 423 /* First check, if it's already good */ 424 if (ServiceNameLen > 12 && 425 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12)) 426 { 427 *RelativeName = HeapAlloc(GetProcessHeap(), 428 HEAP_ZERO_MEMORY, 429 (ServiceNameLen + 1) * sizeof(WCHAR)); 430 if (*RelativeName == NULL) 431 { 432 DPRINT("Error allocating memory for boot driver name\n"); 433 return ERROR_NOT_ENOUGH_MEMORY; 434 } 435 436 /* Copy it */ 437 wcscpy(*RelativeName, CanonName); 438 439 DPRINT("Bootdriver name %S\n", *RelativeName); 440 return ERROR_SUCCESS; 441 } 442 443 /* If it has %SystemRoot% prefix, substitute it to \System*/ 444 if (ServiceNameLen > 13 && 445 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13)) 446 { 447 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */ 448 *RelativeName = HeapAlloc(GetProcessHeap(), 449 HEAP_ZERO_MEMORY, 450 ServiceNameLen * sizeof(WCHAR)); 451 452 if (*RelativeName == NULL) 453 { 454 DPRINT("Error allocating memory for boot driver name\n"); 455 return ERROR_NOT_ENOUGH_MEMORY; 456 } 457 458 /* Copy it */ 459 wcscpy(*RelativeName, L"\\SystemRoot\\"); 460 wcscat(*RelativeName, CanonName + 13); 461 462 DPRINT("Bootdriver name %S\n", *RelativeName); 463 return ERROR_SUCCESS; 464 } 465 466 /* Get buffer size needed for expanding env strings */ 467 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1); 468 if (BufferSize <= 1) 469 { 470 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n"); 471 return ERROR_INVALID_ENVIRONMENT; 472 } 473 474 /* Allocate memory, since the size is known now */ 475 Expanded = HeapAlloc(GetProcessHeap(), 476 HEAP_ZERO_MEMORY, 477 (BufferSize + 1) * sizeof(WCHAR)); 478 if (!Expanded) 479 { 480 DPRINT("Error allocating memory for boot driver name\n"); 481 return ERROR_NOT_ENOUGH_MEMORY; 482 } 483 484 /* Expand it */ 485 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) > 486 BufferSize) 487 { 488 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n"); 489 HeapFree(GetProcessHeap(), 0, Expanded); 490 return ERROR_NOT_ENOUGH_MEMORY; 491 } 492 493 /* Convert to NT-style path */ 494 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL)) 495 { 496 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n"); 497 return ERROR_INVALID_ENVIRONMENT; 498 } 499 500 DPRINT("Converted to NT-style %wZ\n", &NtPathName); 501 502 /* No need to keep the dos-path anymore */ 503 HeapFree(GetProcessHeap(), 0, Expanded); 504 505 /* Copy it to the allocated place */ 506 Expanded = HeapAlloc(GetProcessHeap(), 507 HEAP_ZERO_MEMORY, 508 NtPathName.Length + sizeof(UNICODE_NULL)); 509 if (!Expanded) 510 { 511 DPRINT("Error allocating memory for boot driver name\n"); 512 RtlFreeUnicodeString(&NtPathName); 513 return ERROR_NOT_ENOUGH_MEMORY; 514 } 515 516 ExpandedLen = NtPathName.Length / sizeof(WCHAR); 517 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen); 518 Expanded[ExpandedLen] = UNICODE_NULL; 519 RtlFreeUnicodeString(&NtPathName); 520 521 if (ServiceNameLen > ExpandedLen && 522 !_wcsnicmp(Expanded, CanonName, ExpandedLen)) 523 { 524 HeapFree(GetProcessHeap(), 0, Expanded); 525 526 /* Only \SystemRoot\ is missing */ 527 *RelativeName = HeapAlloc(GetProcessHeap(), 528 HEAP_ZERO_MEMORY, 529 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR)); 530 if (*RelativeName == NULL) 531 { 532 DPRINT("Error allocating memory for boot driver name\n"); 533 return ERROR_NOT_ENOUGH_MEMORY; 534 } 535 536 wcscpy(*RelativeName, L"\\SystemRoot\\"); 537 wcscat(*RelativeName, CanonName + ExpandedLen); 538 539 return ERROR_SUCCESS; 540 } 541 542 /* No longer need this */ 543 HeapFree(GetProcessHeap(), 0, Expanded); 544 545 /* The most complex case starts here */ 546 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot"); 547 InitializeObjectAttributes(&ObjectAttributes, 548 &SystemRoot, 549 OBJ_CASE_INSENSITIVE, 550 NULL, 551 NULL); 552 553 /* Open this symlink */ 554 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes); 555 if (NT_SUCCESS(Status)) 556 { 557 DPRINT("Opened symbolic link object\n"); 558 559 RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0); 560 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize); 561 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL) 562 { 563 /* Check if required buffer size is sane */ 564 if (BufferSize > UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL)) 565 { 566 DPRINT("Too large buffer required\n"); 567 568 NtClose(SymbolicLinkHandle); 569 return ERROR_NOT_ENOUGH_MEMORY; 570 } 571 572 /* Alloc the string */ 573 LinkTarget.Length = (USHORT)BufferSize; 574 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL); 575 LinkTarget.Buffer = HeapAlloc(GetProcessHeap(), 576 HEAP_ZERO_MEMORY, 577 LinkTarget.MaximumLength); 578 if (!LinkTarget.Buffer) 579 { 580 DPRINT("Unable to alloc buffer\n"); 581 NtClose(SymbolicLinkHandle); 582 return ERROR_NOT_ENOUGH_MEMORY; 583 } 584 585 /* Do a real query now */ 586 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize); 587 NtClose(SymbolicLinkHandle); 588 if (NT_SUCCESS(Status)) 589 { 590 DPRINT("LinkTarget: %wZ\n", &LinkTarget); 591 592 ExpandedLen = LinkTarget.Length / sizeof(WCHAR); 593 if ((ServiceNameLen > ExpandedLen) && 594 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen)) 595 { 596 *RelativeName = HeapAlloc(GetProcessHeap(), 597 HEAP_ZERO_MEMORY, 598 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR)); 599 600 if (*RelativeName == NULL) 601 { 602 DPRINT("Unable to alloc buffer\n"); 603 return ERROR_NOT_ENOUGH_MEMORY; 604 } 605 606 /* Copy it over, substituting the first part 607 with SystemRoot */ 608 wcscpy(*RelativeName, L"\\SystemRoot\\"); 609 wcscat(*RelativeName, CanonName+ExpandedLen+1); 610 611 /* Return success */ 612 return ERROR_SUCCESS; 613 } 614 else 615 { 616 return ERROR_INVALID_PARAMETER; 617 } 618 } 619 else 620 { 621 DPRINT("Error, Status = %08X\n", Status); 622 return ERROR_INVALID_PARAMETER; 623 } 624 } 625 else 626 { 627 DPRINT("Error, Status = %08X\n", Status); 628 NtClose(SymbolicLinkHandle); 629 return ERROR_INVALID_PARAMETER; 630 } 631 } 632 else 633 { 634 /* Failure */ 635 DPRINT("Error, Status = %08X\n", Status); 636 return ERROR_INVALID_PARAMETER; 637 } 638 } 639 640 641 DWORD 642 ScmCanonDriverImagePath(DWORD dwStartType, 643 const wchar_t *lpServiceName, 644 wchar_t **lpCanonName) 645 { 646 DWORD Result; 647 SIZE_T ServiceNameLen; 648 UNICODE_STRING NtServiceName; 649 WCHAR *RelativeName; 650 const WCHAR *SourceName = lpServiceName; 651 652 /* Calculate the length of the service's name */ 653 ServiceNameLen = wcslen(lpServiceName); 654 655 /* 12 is wcslen(L"\\SystemRoot\\") */ 656 if (ServiceNameLen > 12 && 657 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12)) 658 { 659 /* SystemRoot prefix is already included */ 660 *lpCanonName = HeapAlloc(GetProcessHeap(), 661 HEAP_ZERO_MEMORY, 662 (ServiceNameLen + 1) * sizeof(WCHAR)); 663 664 if (*lpCanonName == NULL) 665 { 666 DPRINT("Error allocating memory for canonized service name\n"); 667 return ERROR_NOT_ENOUGH_MEMORY; 668 } 669 670 /* If it's a boot-time driver, it must be systemroot relative */ 671 if (dwStartType == SERVICE_BOOT_START) 672 SourceName += 12; 673 674 /* Copy it */ 675 wcscpy(*lpCanonName, SourceName); 676 677 DPRINT("Canonicalized name %S\n", *lpCanonName); 678 return NO_ERROR; 679 } 680 681 /* Check if it has %SystemRoot% (len=13) */ 682 if (ServiceNameLen > 13 && 683 !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13)) 684 { 685 /* Substitute %SystemRoot% with \\SystemRoot\\ */ 686 *lpCanonName = HeapAlloc(GetProcessHeap(), 687 HEAP_ZERO_MEMORY, 688 (ServiceNameLen + 1) * sizeof(WCHAR)); 689 690 if (*lpCanonName == NULL) 691 { 692 DPRINT("Error allocating memory for canonized service name\n"); 693 return ERROR_NOT_ENOUGH_MEMORY; 694 } 695 696 /* If it's a boot-time driver, it must be systemroot relative */ 697 if (dwStartType == SERVICE_BOOT_START) 698 wcscpy(*lpCanonName, L"\\SystemRoot\\"); 699 700 wcscat(*lpCanonName, lpServiceName + 13); 701 702 DPRINT("Canonicalized name %S\n", *lpCanonName); 703 return NO_ERROR; 704 } 705 706 /* Check if it's a relative path name */ 707 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':') 708 { 709 *lpCanonName = HeapAlloc(GetProcessHeap(), 710 HEAP_ZERO_MEMORY, 711 (ServiceNameLen + 1) * sizeof(WCHAR)); 712 713 if (*lpCanonName == NULL) 714 { 715 DPRINT("Error allocating memory for canonized service name\n"); 716 return ERROR_NOT_ENOUGH_MEMORY; 717 } 718 719 /* Just copy it over without changing */ 720 wcscpy(*lpCanonName, lpServiceName); 721 722 return NO_ERROR; 723 } 724 725 /* It seems to be a DOS path, convert it */ 726 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL)) 727 { 728 DPRINT("RtlDosPathNameToNtPathName_U() failed\n"); 729 return ERROR_INVALID_PARAMETER; 730 } 731 732 *lpCanonName = HeapAlloc(GetProcessHeap(), 733 HEAP_ZERO_MEMORY, 734 NtServiceName.Length + sizeof(WCHAR)); 735 736 if (*lpCanonName == NULL) 737 { 738 DPRINT("Error allocating memory for canonized service name\n"); 739 RtlFreeUnicodeString(&NtServiceName); 740 return ERROR_NOT_ENOUGH_MEMORY; 741 } 742 743 /* Copy the string */ 744 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR)); 745 746 /* The unicode string is not needed anymore */ 747 RtlFreeUnicodeString(&NtServiceName); 748 749 if (dwStartType != SERVICE_BOOT_START) 750 { 751 DPRINT("Canonicalized name %S\n", *lpCanonName); 752 return NO_ERROR; 753 } 754 755 /* The service is boot-started, so must be relative */ 756 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName); 757 if (Result) 758 { 759 /* There is a problem, free name and return */ 760 HeapFree(GetProcessHeap(), 0, *lpCanonName); 761 DPRINT("Error converting named\n"); 762 return Result; 763 } 764 765 ASSERT(RelativeName); 766 767 /* Copy that string */ 768 wcscpy(*lpCanonName, RelativeName + 12); 769 770 /* Free the allocated buffer */ 771 HeapFree(GetProcessHeap(), 0, RelativeName); 772 773 DPRINT("Canonicalized name %S\n", *lpCanonName); 774 775 /* Success */ 776 return NO_ERROR; 777 } 778 779 780 /* Recursively search for every dependency on every service */ 781 DWORD 782 Int_EnumDependentServicesW(HKEY hServicesKey, 783 PSERVICE lpService, 784 DWORD dwServiceState, 785 PSERVICE *lpServices, 786 LPDWORD pcbBytesNeeded, 787 LPDWORD lpServicesReturned) 788 { 789 DWORD dwError = ERROR_SUCCESS; 790 WCHAR szNameBuf[MAX_PATH]; 791 WCHAR szValueBuf[MAX_PATH]; 792 WCHAR *lpszNameBuf = szNameBuf; 793 WCHAR *lpszValueBuf = szValueBuf; 794 DWORD dwSize; 795 DWORD dwNumSubKeys; 796 DWORD dwIteration; 797 PSERVICE lpCurrentService; 798 HKEY hServiceEnumKey; 799 DWORD dwCurrentServiceState = SERVICE_ACTIVE; 800 DWORD dwDependServiceStrPtr = 0; 801 DWORD dwRequiredSize = 0; 802 803 /* Get the number of service keys */ 804 dwError = RegQueryInfoKeyW(hServicesKey, 805 NULL, 806 NULL, 807 NULL, 808 &dwNumSubKeys, 809 NULL, 810 NULL, 811 NULL, 812 NULL, 813 NULL, 814 NULL, 815 NULL); 816 if (dwError != ERROR_SUCCESS) 817 { 818 DPRINT("ERROR! Unable to get number of services keys\n"); 819 return dwError; 820 } 821 822 /* Iterate the service keys to see if another service depends on the this service */ 823 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++) 824 { 825 dwSize = MAX_PATH; 826 dwError = RegEnumKeyExW(hServicesKey, 827 dwIteration, 828 lpszNameBuf, 829 &dwSize, 830 NULL, 831 NULL, 832 NULL, 833 NULL); 834 if (dwError != ERROR_SUCCESS) 835 return dwError; 836 837 /* Open the Service key */ 838 dwError = RegOpenKeyExW(hServicesKey, 839 lpszNameBuf, 840 0, 841 KEY_READ, 842 &hServiceEnumKey); 843 if (dwError != ERROR_SUCCESS) 844 return dwError; 845 846 dwSize = MAX_PATH * sizeof(WCHAR); 847 848 /* Check for the DependOnService Value */ 849 dwError = RegQueryValueExW(hServiceEnumKey, 850 L"DependOnService", 851 NULL, 852 NULL, 853 (LPBYTE)lpszValueBuf, 854 &dwSize); 855 856 /* FIXME: Handle load order. */ 857 858 /* If the service found has a DependOnService value */ 859 if (dwError == ERROR_SUCCESS) 860 { 861 dwDependServiceStrPtr = 0; 862 863 /* Can be more than one Dependencies in the DependOnService string */ 864 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0) 865 { 866 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0) 867 { 868 /* Get the current enumed service pointer */ 869 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf); 870 871 /* Check for valid Service */ 872 if (!lpCurrentService) 873 { 874 /* This should never happen! */ 875 DPRINT("This should not happen at this point, report to Developer\n"); 876 return ERROR_NOT_FOUND; 877 } 878 879 /* Determine state the service is in */ 880 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED) 881 dwCurrentServiceState = SERVICE_INACTIVE; 882 883 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */ 884 if ((dwCurrentServiceState == dwServiceState) || 885 (dwServiceState == SERVICE_STATE_ALL)) 886 { 887 /* Calculate the required size */ 888 dwRequiredSize += sizeof(SERVICE_STATUS); 889 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR)); 890 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); 891 892 /* Add the size for service name and display name pointers */ 893 dwRequiredSize += (2 * sizeof(PVOID)); 894 895 /* increase the BytesNeeded size */ 896 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize; 897 898 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency 899 comes first */ 900 901 /* Recursive call to check for its dependencies */ 902 Int_EnumDependentServicesW(hServicesKey, 903 lpCurrentService, 904 dwServiceState, 905 lpServices, 906 pcbBytesNeeded, 907 lpServicesReturned); 908 909 /* If the lpServices is valid set the service pointer */ 910 if (lpServices) 911 lpServices[*lpServicesReturned] = lpCurrentService; 912 913 *lpServicesReturned = *lpServicesReturned + 1; 914 } 915 } 916 917 dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1); 918 } 919 } 920 else if (*pcbBytesNeeded) 921 { 922 dwError = ERROR_SUCCESS; 923 } 924 925 RegCloseKey(hServiceEnumKey); 926 } 927 928 return dwError; 929 } 930 931 932 /* Function 0 */ 933 DWORD 934 WINAPI 935 RCloseServiceHandle( 936 LPSC_RPC_HANDLE hSCObject) 937 { 938 PMANAGER_HANDLE hManager; 939 PSERVICE_HANDLE hService; 940 PSERVICE lpService; 941 942 DPRINT("RCloseServiceHandle() called\n"); 943 944 DPRINT("hSCObject = %p\n", *hSCObject); 945 946 if (*hSCObject == 0) 947 return ERROR_INVALID_HANDLE; 948 949 hManager = ScmGetServiceManagerFromHandle(*hSCObject); 950 hService = ScmGetServiceFromHandle(*hSCObject); 951 952 if (hManager != NULL) 953 { 954 DPRINT("Found manager handle\n"); 955 956 /* Make sure we don't access stale memory if someone tries to use this handle again. */ 957 hManager->Handle.Tag = INVALID_TAG; 958 959 HeapFree(GetProcessHeap(), 0, hManager); 960 hManager = NULL; 961 962 *hSCObject = NULL; 963 964 DPRINT("RCloseServiceHandle() done\n"); 965 return ERROR_SUCCESS; 966 } 967 else if (hService != NULL) 968 { 969 DPRINT("Found service handle\n"); 970 971 /* Lock the service database exclusively */ 972 ScmLockDatabaseExclusive(); 973 974 /* Get the pointer to the service record */ 975 lpService = hService->ServiceEntry; 976 977 /* Make sure we don't access stale memory if someone tries to use this handle again. */ 978 hService->Handle.Tag = INVALID_TAG; 979 980 /* Free the handle */ 981 HeapFree(GetProcessHeap(), 0, hService); 982 hService = NULL; 983 984 985 DPRINT("Closing service %S with %d references\n", lpService->lpServiceName, lpService->RefCount); 986 ScmDereferenceService(lpService); 987 988 ScmUnlockDatabase(); 989 990 *hSCObject = NULL; 991 992 DPRINT("RCloseServiceHandle() done\n"); 993 return ERROR_SUCCESS; 994 } 995 996 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag); 997 998 return ERROR_INVALID_HANDLE; 999 } 1000 1001 1002 /* Function 1 */ 1003 DWORD 1004 WINAPI 1005 RControlService( 1006 SC_RPC_HANDLE hService, 1007 DWORD dwControl, 1008 LPSERVICE_STATUS lpServiceStatus) 1009 { 1010 PSERVICE_HANDLE hSvc; 1011 PSERVICE lpService; 1012 ACCESS_MASK DesiredAccess; 1013 DWORD dwError = ERROR_SUCCESS; 1014 DWORD pcbBytesNeeded = 0; 1015 DWORD dwServicesReturned = 0; 1016 DWORD dwControlsAccepted; 1017 DWORD dwCurrentState; 1018 HKEY hServicesKey = NULL; 1019 LPCWSTR lpLogStrings[2]; 1020 WCHAR szLogBuffer[80]; 1021 UINT uID; 1022 1023 DPRINT("RControlService() called\n"); 1024 1025 if (ScmShutdown) 1026 return ERROR_SHUTDOWN_IN_PROGRESS; 1027 1028 /* Check the service handle */ 1029 hSvc = ScmGetServiceFromHandle(hService); 1030 if (hSvc == NULL) 1031 { 1032 DPRINT1("Invalid service handle\n"); 1033 return ERROR_INVALID_HANDLE; 1034 } 1035 1036 /* Check the service entry point */ 1037 lpService = hSvc->ServiceEntry; 1038 if (lpService == NULL) 1039 { 1040 DPRINT1("lpService == NULL\n"); 1041 return ERROR_INVALID_HANDLE; 1042 } 1043 1044 /* Check access rights */ 1045 switch (dwControl) 1046 { 1047 case SERVICE_CONTROL_STOP: 1048 DesiredAccess = SERVICE_STOP; 1049 break; 1050 1051 case SERVICE_CONTROL_PAUSE: 1052 case SERVICE_CONTROL_CONTINUE: 1053 case SERVICE_CONTROL_PARAMCHANGE: 1054 case SERVICE_CONTROL_NETBINDADD: 1055 case SERVICE_CONTROL_NETBINDREMOVE: 1056 case SERVICE_CONTROL_NETBINDENABLE: 1057 case SERVICE_CONTROL_NETBINDDISABLE: 1058 DesiredAccess = SERVICE_PAUSE_CONTINUE; 1059 break; 1060 1061 case SERVICE_CONTROL_INTERROGATE: 1062 DesiredAccess = SERVICE_INTERROGATE; 1063 break; 1064 1065 default: 1066 if (dwControl >= 128 && dwControl <= 255) 1067 DesiredAccess = SERVICE_USER_DEFINED_CONTROL; 1068 else 1069 return ERROR_INVALID_PARAMETER; 1070 break; 1071 } 1072 1073 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 1074 DesiredAccess)) 1075 return ERROR_ACCESS_DENIED; 1076 1077 /* Return the current service status information */ 1078 RtlCopyMemory(lpServiceStatus, 1079 &lpService->Status, 1080 sizeof(SERVICE_STATUS)); 1081 1082 if (dwControl == SERVICE_CONTROL_STOP) 1083 { 1084 /* Check if the service has dependencies running as windows 1085 doesn't stop a service that does */ 1086 1087 /* Open the Services Reg key */ 1088 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 1089 L"System\\CurrentControlSet\\Services", 1090 0, 1091 KEY_READ, 1092 &hServicesKey); 1093 if (dwError != ERROR_SUCCESS) 1094 { 1095 DPRINT("Failed to open services key\n"); 1096 return dwError; 1097 } 1098 1099 /* Call the internal function with NULL, just to get bytes we need */ 1100 Int_EnumDependentServicesW(hServicesKey, 1101 lpService, 1102 SERVICE_ACTIVE, 1103 NULL, 1104 &pcbBytesNeeded, 1105 &dwServicesReturned); 1106 1107 RegCloseKey(hServicesKey); 1108 1109 /* If pcbBytesNeeded is not zero then there are services running that 1110 are dependent on this service */ 1111 if (pcbBytesNeeded != 0) 1112 { 1113 DPRINT("Service has running dependencies. Failed to stop service\n"); 1114 return ERROR_DEPENDENT_SERVICES_RUNNING; 1115 } 1116 } 1117 1118 if (lpService->Status.dwServiceType & SERVICE_DRIVER) 1119 { 1120 /* Send control code to the driver */ 1121 dwError = ScmControlDriver(lpService, 1122 dwControl, 1123 lpServiceStatus); 1124 } 1125 else 1126 { 1127 dwControlsAccepted = lpService->Status.dwControlsAccepted; 1128 dwCurrentState = lpService->Status.dwCurrentState; 1129 1130 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */ 1131 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED) 1132 return ERROR_SERVICE_NOT_ACTIVE; 1133 1134 /* Check the current state before sending a control request */ 1135 switch (dwCurrentState) 1136 { 1137 case SERVICE_STOP_PENDING: 1138 case SERVICE_STOPPED: 1139 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL; 1140 1141 case SERVICE_START_PENDING: 1142 switch (dwControl) 1143 { 1144 case SERVICE_CONTROL_STOP: 1145 break; 1146 1147 case SERVICE_CONTROL_INTERROGATE: 1148 RtlCopyMemory(lpServiceStatus, 1149 &lpService->Status, 1150 sizeof(SERVICE_STATUS)); 1151 return ERROR_SUCCESS; 1152 1153 default: 1154 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL; 1155 } 1156 break; 1157 } 1158 1159 /* Check if the control code is acceptable to the service */ 1160 switch (dwControl) 1161 { 1162 case SERVICE_CONTROL_STOP: 1163 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0) 1164 return ERROR_INVALID_SERVICE_CONTROL; 1165 break; 1166 1167 case SERVICE_CONTROL_PAUSE: 1168 case SERVICE_CONTROL_CONTINUE: 1169 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0) 1170 return ERROR_INVALID_SERVICE_CONTROL; 1171 break; 1172 1173 case SERVICE_CONTROL_PARAMCHANGE: 1174 if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0) 1175 return ERROR_INVALID_SERVICE_CONTROL; 1176 break; 1177 1178 case SERVICE_CONTROL_NETBINDADD: 1179 case SERVICE_CONTROL_NETBINDREMOVE: 1180 case SERVICE_CONTROL_NETBINDENABLE: 1181 case SERVICE_CONTROL_NETBINDDISABLE: 1182 if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0) 1183 return ERROR_INVALID_SERVICE_CONTROL; 1184 break; 1185 } 1186 1187 /* Send control code to the service */ 1188 dwError = ScmControlService(lpService->lpImage->hControlPipe, 1189 lpService->lpServiceName, 1190 dwControl, 1191 (SERVICE_STATUS_HANDLE)lpService); 1192 1193 /* Return service status information */ 1194 RtlCopyMemory(lpServiceStatus, 1195 &lpService->Status, 1196 sizeof(SERVICE_STATUS)); 1197 } 1198 1199 if (dwError == ERROR_SUCCESS) 1200 { 1201 if (dwControl == SERVICE_CONTROL_STOP || 1202 dwControl == SERVICE_CONTROL_PAUSE || 1203 dwControl == SERVICE_CONTROL_CONTINUE) 1204 { 1205 /* Log a successful send control */ 1206 1207 switch (dwControl) 1208 { 1209 case SERVICE_CONTROL_STOP: 1210 uID = IDS_SERVICE_STOP; 1211 break; 1212 1213 case SERVICE_CONTROL_PAUSE: 1214 uID = IDS_SERVICE_PAUSE; 1215 break; 1216 1217 case SERVICE_CONTROL_CONTINUE: 1218 uID = IDS_SERVICE_RESUME; 1219 break; 1220 } 1221 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer)); 1222 1223 lpLogStrings[0] = lpService->lpDisplayName; 1224 lpLogStrings[1] = szLogBuffer; 1225 1226 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS, 1227 EVENTLOG_INFORMATION_TYPE, 1228 2, 1229 lpLogStrings); 1230 } 1231 } 1232 1233 return dwError; 1234 } 1235 1236 1237 /* Function 2 */ 1238 DWORD 1239 WINAPI 1240 RDeleteService( 1241 SC_RPC_HANDLE hService) 1242 { 1243 PSERVICE_HANDLE hSvc; 1244 PSERVICE lpService; 1245 DWORD dwError; 1246 1247 DPRINT("RDeleteService() called\n"); 1248 1249 if (ScmShutdown) 1250 return ERROR_SHUTDOWN_IN_PROGRESS; 1251 1252 hSvc = ScmGetServiceFromHandle(hService); 1253 if (hSvc == NULL) 1254 { 1255 DPRINT1("Invalid service handle\n"); 1256 return ERROR_INVALID_HANDLE; 1257 } 1258 1259 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 1260 DELETE)) 1261 return ERROR_ACCESS_DENIED; 1262 1263 lpService = hSvc->ServiceEntry; 1264 if (lpService == NULL) 1265 { 1266 DPRINT("lpService == NULL\n"); 1267 return ERROR_INVALID_HANDLE; 1268 } 1269 1270 /* Lock the service database exclusively */ 1271 ScmLockDatabaseExclusive(); 1272 1273 if (lpService->bDeleted) 1274 { 1275 DPRINT("Service has already been marked for delete\n"); 1276 dwError = ERROR_SERVICE_MARKED_FOR_DELETE; 1277 goto Done; 1278 } 1279 1280 /* Mark service for delete */ 1281 lpService->bDeleted = TRUE; 1282 1283 dwError = ScmMarkServiceForDelete(lpService); 1284 1285 Done: 1286 /* Unlock the service database */ 1287 ScmUnlockDatabase(); 1288 1289 DPRINT("RDeleteService() done\n"); 1290 1291 return dwError; 1292 } 1293 1294 1295 /* Function 3 */ 1296 DWORD 1297 WINAPI 1298 RLockServiceDatabase( 1299 SC_RPC_HANDLE hSCManager, 1300 LPSC_RPC_LOCK lpLock) 1301 { 1302 PMANAGER_HANDLE hMgr; 1303 1304 DPRINT("RLockServiceDatabase() called\n"); 1305 1306 *lpLock = NULL; 1307 1308 hMgr = ScmGetServiceManagerFromHandle(hSCManager); 1309 if (hMgr == NULL) 1310 { 1311 DPRINT1("Invalid service manager handle\n"); 1312 return ERROR_INVALID_HANDLE; 1313 } 1314 1315 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, 1316 SC_MANAGER_LOCK)) 1317 return ERROR_ACCESS_DENIED; 1318 1319 return ScmAcquireServiceStartLock(FALSE, lpLock); 1320 } 1321 1322 1323 /* Function 4 */ 1324 DWORD 1325 WINAPI 1326 RQueryServiceObjectSecurity( 1327 SC_RPC_HANDLE hService, 1328 SECURITY_INFORMATION dwSecurityInformation, 1329 LPBYTE lpSecurityDescriptor, 1330 DWORD cbBufSize, 1331 LPBOUNDED_DWORD_256K pcbBytesNeeded) 1332 { 1333 PSERVICE_HANDLE hSvc; 1334 PSERVICE lpService; 1335 ULONG DesiredAccess = 0; 1336 NTSTATUS Status; 1337 DWORD dwBytesNeeded; 1338 DWORD dwError; 1339 1340 DPRINT("RQueryServiceObjectSecurity() called\n"); 1341 1342 hSvc = ScmGetServiceFromHandle(hService); 1343 if (hSvc == NULL) 1344 { 1345 DPRINT1("Invalid service handle\n"); 1346 return ERROR_INVALID_HANDLE; 1347 } 1348 1349 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION | 1350 GROUP_SECURITY_INFORMATION | 1351 OWNER_SECURITY_INFORMATION)) 1352 DesiredAccess |= READ_CONTROL; 1353 1354 if (dwSecurityInformation & SACL_SECURITY_INFORMATION) 1355 DesiredAccess |= ACCESS_SYSTEM_SECURITY; 1356 1357 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 1358 DesiredAccess)) 1359 { 1360 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 1361 return ERROR_ACCESS_DENIED; 1362 } 1363 1364 lpService = hSvc->ServiceEntry; 1365 if (lpService == NULL) 1366 { 1367 DPRINT("lpService == NULL\n"); 1368 return ERROR_INVALID_HANDLE; 1369 } 1370 1371 /* Lock the service database */ 1372 ScmLockDatabaseShared(); 1373 1374 /* Retrieve the security descriptor */ 1375 Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor, 1376 dwSecurityInformation, 1377 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor, 1378 cbBufSize, 1379 &dwBytesNeeded); 1380 1381 /* Unlock the service database */ 1382 ScmUnlockDatabase(); 1383 1384 if (NT_SUCCESS(Status)) 1385 { 1386 *pcbBytesNeeded = dwBytesNeeded; 1387 dwError = STATUS_SUCCESS; 1388 } 1389 else if (Status == STATUS_BUFFER_TOO_SMALL) 1390 { 1391 *pcbBytesNeeded = dwBytesNeeded; 1392 dwError = ERROR_INSUFFICIENT_BUFFER; 1393 } 1394 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT) 1395 { 1396 dwError = ERROR_GEN_FAILURE; 1397 } 1398 else 1399 { 1400 dwError = RtlNtStatusToDosError(Status); 1401 } 1402 1403 return dwError; 1404 } 1405 1406 1407 /* Function 5 */ 1408 DWORD 1409 WINAPI 1410 RSetServiceObjectSecurity( 1411 SC_RPC_HANDLE hService, 1412 DWORD dwSecurityInformation, 1413 LPBYTE lpSecurityDescriptor, 1414 DWORD dwSecurityDescriptorSize) 1415 { 1416 PSERVICE_HANDLE hSvc; 1417 PSERVICE lpService; 1418 ACCESS_MASK DesiredAccess = 0; 1419 HANDLE hToken = NULL; 1420 HKEY hServiceKey = NULL; 1421 BOOL bDatabaseLocked = FALSE; 1422 NTSTATUS Status; 1423 DWORD dwError; 1424 1425 DPRINT("RSetServiceObjectSecurity() called\n"); 1426 1427 hSvc = ScmGetServiceFromHandle(hService); 1428 if (hSvc == NULL) 1429 { 1430 DPRINT1("Invalid service handle\n"); 1431 return ERROR_INVALID_HANDLE; 1432 } 1433 1434 if (dwSecurityInformation == 0 || 1435 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION 1436 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION)) 1437 { 1438 return ERROR_INVALID_PARAMETER; 1439 } 1440 1441 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)) 1442 return ERROR_INVALID_PARAMETER; 1443 1444 if (dwSecurityInformation & SACL_SECURITY_INFORMATION) 1445 DesiredAccess |= ACCESS_SYSTEM_SECURITY; 1446 1447 if (dwSecurityInformation & DACL_SECURITY_INFORMATION) 1448 DesiredAccess |= WRITE_DAC; 1449 1450 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION)) 1451 DesiredAccess |= WRITE_OWNER; 1452 1453 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) && 1454 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL)) 1455 { 1456 return ERROR_INVALID_PARAMETER; 1457 } 1458 1459 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) && 1460 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL)) 1461 { 1462 return ERROR_INVALID_PARAMETER; 1463 } 1464 1465 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 1466 DesiredAccess)) 1467 { 1468 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 1469 return ERROR_ACCESS_DENIED; 1470 } 1471 1472 lpService = hSvc->ServiceEntry; 1473 if (lpService == NULL) 1474 { 1475 DPRINT1("lpService == NULL\n"); 1476 return ERROR_INVALID_HANDLE; 1477 } 1478 1479 if (lpService->bDeleted) 1480 return ERROR_SERVICE_MARKED_FOR_DELETE; 1481 1482 #if 0 1483 RpcImpersonateClient(NULL); 1484 1485 Status = NtOpenThreadToken(NtCurrentThread(), 1486 8, 1487 TRUE, 1488 &hToken); 1489 if (!NT_SUCCESS(Status)) 1490 return RtlNtStatusToDosError(Status); 1491 1492 RpcRevertToSelf(); 1493 #endif 1494 1495 /* Build the new security descriptor */ 1496 Status = RtlSetSecurityObject(dwSecurityInformation, 1497 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor, 1498 &lpService->pSecurityDescriptor, 1499 &ScmServiceMapping, 1500 hToken); 1501 if (!NT_SUCCESS(Status)) 1502 { 1503 dwError = RtlNtStatusToDosError(Status); 1504 goto Done; 1505 } 1506 1507 /* Lock the service database exclusive */ 1508 ScmLockDatabaseExclusive(); 1509 bDatabaseLocked = TRUE; 1510 1511 /* Open the service key */ 1512 dwError = ScmOpenServiceKey(lpService->lpServiceName, 1513 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE, 1514 &hServiceKey); 1515 if (dwError != ERROR_SUCCESS) 1516 goto Done; 1517 1518 /* Store the new security descriptor */ 1519 dwError = ScmWriteSecurityDescriptor(hServiceKey, 1520 lpService->pSecurityDescriptor); 1521 1522 RegFlushKey(hServiceKey); 1523 1524 Done: 1525 if (hServiceKey != NULL) 1526 RegCloseKey(hServiceKey); 1527 1528 /* Unlock service database */ 1529 if (bDatabaseLocked == TRUE) 1530 ScmUnlockDatabase(); 1531 1532 if (hToken != NULL) 1533 NtClose(hToken); 1534 1535 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError); 1536 1537 return dwError; 1538 } 1539 1540 1541 /* Function 6 */ 1542 DWORD 1543 WINAPI 1544 RQueryServiceStatus( 1545 SC_RPC_HANDLE hService, 1546 LPSERVICE_STATUS lpServiceStatus) 1547 { 1548 PSERVICE_HANDLE hSvc; 1549 PSERVICE lpService; 1550 1551 DPRINT("RQueryServiceStatus() called\n"); 1552 1553 if (ScmShutdown) 1554 return ERROR_SHUTDOWN_IN_PROGRESS; 1555 1556 hSvc = ScmGetServiceFromHandle(hService); 1557 if (hSvc == NULL) 1558 { 1559 DPRINT1("Invalid service handle\n"); 1560 return ERROR_INVALID_HANDLE; 1561 } 1562 1563 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 1564 SERVICE_QUERY_STATUS)) 1565 { 1566 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 1567 return ERROR_ACCESS_DENIED; 1568 } 1569 1570 lpService = hSvc->ServiceEntry; 1571 if (lpService == NULL) 1572 { 1573 DPRINT("lpService == NULL\n"); 1574 return ERROR_INVALID_HANDLE; 1575 } 1576 1577 /* Lock the service database shared */ 1578 ScmLockDatabaseShared(); 1579 1580 /* Return service status information */ 1581 RtlCopyMemory(lpServiceStatus, 1582 &lpService->Status, 1583 sizeof(SERVICE_STATUS)); 1584 1585 /* Unlock the service database */ 1586 ScmUnlockDatabase(); 1587 1588 return ERROR_SUCCESS; 1589 } 1590 1591 1592 static BOOL 1593 ScmIsValidServiceState(DWORD dwCurrentState) 1594 { 1595 switch (dwCurrentState) 1596 { 1597 case SERVICE_STOPPED: 1598 case SERVICE_START_PENDING: 1599 case SERVICE_STOP_PENDING: 1600 case SERVICE_RUNNING: 1601 case SERVICE_CONTINUE_PENDING: 1602 case SERVICE_PAUSE_PENDING: 1603 case SERVICE_PAUSED: 1604 return TRUE; 1605 1606 default: 1607 return FALSE; 1608 } 1609 } 1610 1611 static 1612 DWORD 1613 WINAPI 1614 ScmStopThread(PVOID pParam) 1615 { 1616 PSERVICE lpService = (PSERVICE)pParam; 1617 WCHAR szLogBuffer[80]; 1618 LPCWSTR lpLogStrings[2]; 1619 1620 /* Check if we are about to stop this service */ 1621 if (lpService->lpImage->dwImageRunCount == 1) 1622 { 1623 /* Stop the dispatcher thread. 1624 * We must not send a control message while holding the database lock, otherwise it can cause timeouts 1625 * We are sure that the service won't be deleted in the meantime because we still have a reference to it. */ 1626 DPRINT("Stopping the dispatcher thread for service %S\n", lpService->lpServiceName); 1627 ScmControlService(lpService->lpImage->hControlPipe, 1628 L"", 1629 SERVICE_CONTROL_STOP, 1630 (SERVICE_STATUS_HANDLE)lpService); 1631 } 1632 1633 /* Lock the service database exclusively */ 1634 ScmLockDatabaseExclusive(); 1635 1636 DPRINT("Service %S image count:%d\n", lpService->lpServiceName, lpService->lpImage->dwImageRunCount); 1637 1638 /* Decrement the image run counter */ 1639 lpService->lpImage->dwImageRunCount--; 1640 1641 /* If we just stopped the last running service... */ 1642 if (lpService->lpImage->dwImageRunCount == 0) 1643 { 1644 /* Remove the service image */ 1645 DPRINT("Removing service image for %S\n", lpService->lpServiceName); 1646 ScmRemoveServiceImage(lpService->lpImage); 1647 lpService->lpImage = NULL; 1648 } 1649 1650 /* Report the results of the status change here */ 1651 if (lpService->Status.dwWin32ExitCode != ERROR_SUCCESS) 1652 { 1653 /* Log a failed service stop */ 1654 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer), 1655 L"%lu", lpService->Status.dwWin32ExitCode); 1656 lpLogStrings[0] = lpService->lpDisplayName; 1657 lpLogStrings[1] = szLogBuffer; 1658 1659 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED, 1660 EVENTLOG_ERROR_TYPE, 1661 ARRAYSIZE(lpLogStrings), 1662 lpLogStrings); 1663 } 1664 else 1665 { 1666 /* Log a successful service status change */ 1667 LoadStringW(GetModuleHandle(NULL), IDS_SERVICE_STOPPED, szLogBuffer, ARRAYSIZE(szLogBuffer)); 1668 lpLogStrings[0] = lpService->lpDisplayName; 1669 lpLogStrings[1] = szLogBuffer; 1670 1671 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS, 1672 EVENTLOG_INFORMATION_TYPE, 1673 ARRAYSIZE(lpLogStrings), 1674 lpLogStrings); 1675 } 1676 1677 /* Remove the reference that was added when the service started */ 1678 DPRINT("Service %S has %d references while stoping\n", lpService->lpServiceName, lpService->RefCount); 1679 ScmDereferenceService(lpService); 1680 1681 /* Unlock the service database */ 1682 ScmUnlockDatabase(); 1683 1684 return 0; 1685 } 1686 1687 /* Function 7 */ 1688 DWORD 1689 WINAPI 1690 RSetServiceStatus( 1691 RPC_SERVICE_STATUS_HANDLE hServiceStatus, 1692 LPSERVICE_STATUS lpServiceStatus) 1693 { 1694 PSERVICE lpService; 1695 DWORD dwPreviousState; 1696 DWORD dwPreviousType; 1697 LPCWSTR lpLogStrings[2]; 1698 WCHAR szLogBuffer[80]; 1699 UINT uID; 1700 1701 DPRINT("RSetServiceStatus() called\n"); 1702 DPRINT("hServiceStatus = %lu\n", hServiceStatus); 1703 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType); 1704 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState); 1705 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted); 1706 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode); 1707 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode); 1708 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint); 1709 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint); 1710 1711 if (hServiceStatus == 0) 1712 { 1713 DPRINT("hServiceStatus == NULL\n"); 1714 return ERROR_INVALID_HANDLE; 1715 } 1716 1717 lpService = (PSERVICE)hServiceStatus; 1718 1719 /* Check current state */ 1720 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState)) 1721 { 1722 DPRINT("Invalid service state\n"); 1723 return ERROR_INVALID_DATA; 1724 } 1725 1726 /* Check service type */ 1727 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) && 1728 (lpServiceStatus->dwServiceType & SERVICE_DRIVER)) 1729 { 1730 DPRINT("Invalid service type\n"); 1731 return ERROR_INVALID_DATA; 1732 } 1733 1734 /* Check accepted controls */ 1735 if (lpServiceStatus->dwControlsAccepted & ~0xFF) 1736 { 1737 DPRINT("Invalid controls accepted\n"); 1738 return ERROR_INVALID_DATA; 1739 } 1740 1741 /* Set the wait hint and check point only if the service is in a pending state, 1742 otherwise they should be 0 */ 1743 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED || 1744 lpServiceStatus->dwCurrentState == SERVICE_PAUSED || 1745 lpServiceStatus->dwCurrentState == SERVICE_RUNNING) 1746 { 1747 lpServiceStatus->dwWaitHint = 0; 1748 lpServiceStatus->dwCheckPoint = 0; 1749 } 1750 1751 /* Lock the service database exclusively */ 1752 ScmLockDatabaseExclusive(); 1753 1754 /* Save the current service state */ 1755 dwPreviousState = lpService->Status.dwCurrentState; 1756 1757 /* Save the current service type */ 1758 dwPreviousType = lpService->Status.dwServiceType; 1759 1760 /* Update the service status */ 1761 RtlCopyMemory(&lpService->Status, 1762 lpServiceStatus, 1763 sizeof(SERVICE_STATUS)); 1764 1765 /* Restore the previous service type */ 1766 lpService->Status.dwServiceType = dwPreviousType; 1767 1768 DPRINT("Service %S changed state %d to %d\n", lpService->lpServiceName, dwPreviousState, lpServiceStatus->dwCurrentState); 1769 1770 if (lpServiceStatus->dwCurrentState != SERVICE_STOPPED && 1771 dwPreviousState == SERVICE_STOPPED) 1772 { 1773 /* Keep a reference on all non stopped services */ 1774 ScmReferenceService(lpService); 1775 DPRINT("Service %S has %d references after starting\n", lpService->lpServiceName, lpService->RefCount); 1776 } 1777 1778 /* Check if the service just stopped */ 1779 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED && 1780 dwPreviousState != SERVICE_STOPPED) 1781 { 1782 HANDLE hStopThread; 1783 DWORD dwStopThreadId; 1784 DPRINT("Service %S, currentstate: %d, prev: %d\n", lpService->lpServiceName, lpServiceStatus->dwCurrentState, dwPreviousState); 1785 1786 /* 1787 * The service just changed its status to stopped. 1788 * Create a thread that will complete the stop sequence. 1789 * This thread will remove the reference that was added when the service started. 1790 * This will ensure that the service will remain valid as long as this reference is still held. 1791 */ 1792 hStopThread = CreateThread(NULL, 1793 0, 1794 ScmStopThread, 1795 (LPVOID)lpService, 1796 0, 1797 &dwStopThreadId); 1798 if (hStopThread == NULL) 1799 { 1800 DPRINT1("Failed to create thread to complete service stop\n"); 1801 /* We can't leave without releasing the reference. 1802 * We also can't remove it without holding the lock. */ 1803 ScmDereferenceService(lpService); 1804 DPRINT1("Service %S has %d references after stop\n", lpService->lpServiceName, lpService->RefCount); 1805 } 1806 else 1807 { 1808 CloseHandle(hStopThread); 1809 } 1810 } 1811 1812 /* Unlock the service database */ 1813 ScmUnlockDatabase(); 1814 1815 /* Don't log any events here regarding a service stop as it can become invalid at any time */ 1816 1817 if (lpServiceStatus->dwCurrentState != dwPreviousState && 1818 (lpServiceStatus->dwCurrentState == SERVICE_RUNNING || 1819 lpServiceStatus->dwCurrentState == SERVICE_PAUSED)) 1820 { 1821 /* Log a successful service status change */ 1822 switch(lpServiceStatus->dwCurrentState) 1823 { 1824 case SERVICE_RUNNING: 1825 uID = IDS_SERVICE_RUNNING; 1826 break; 1827 1828 case SERVICE_PAUSED: 1829 uID = IDS_SERVICE_PAUSED; 1830 break; 1831 } 1832 1833 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer)); 1834 lpLogStrings[0] = lpService->lpDisplayName; 1835 lpLogStrings[1] = szLogBuffer; 1836 1837 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS, 1838 EVENTLOG_INFORMATION_TYPE, 1839 2, 1840 lpLogStrings); 1841 } 1842 1843 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState); 1844 DPRINT("RSetServiceStatus() done\n"); 1845 1846 return ERROR_SUCCESS; 1847 } 1848 1849 1850 /* Function 8 */ 1851 DWORD 1852 WINAPI 1853 RUnlockServiceDatabase( 1854 LPSC_RPC_LOCK Lock) 1855 { 1856 DPRINT("RUnlockServiceDatabase(%p)\n", Lock); 1857 return ScmReleaseServiceStartLock(Lock); 1858 } 1859 1860 1861 /* Function 9 */ 1862 DWORD 1863 WINAPI 1864 RNotifyBootConfigStatus( 1865 SVCCTL_HANDLEW lpMachineName, 1866 DWORD BootAcceptable) 1867 { 1868 DPRINT("RNotifyBootConfigStatus(%p %lu)\n", 1869 lpMachineName, BootAcceptable); 1870 1871 if (BootAcceptable) 1872 return ScmAcceptBoot(); 1873 1874 return ScmRunLastKnownGood(); 1875 } 1876 1877 1878 /* Function 10 */ 1879 DWORD 1880 WINAPI 1881 RI_ScSetServiceBitsW( 1882 RPC_SERVICE_STATUS_HANDLE hServiceStatus, 1883 DWORD dwServiceBits, 1884 int bSetBitsOn, 1885 int bUpdateImmediately, 1886 wchar_t *lpString) 1887 { 1888 PSERVICE pService; 1889 1890 DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n", 1891 hServiceStatus, dwServiceBits, bSetBitsOn, 1892 bUpdateImmediately, lpString); 1893 1894 if (ScmShutdown) 1895 return ERROR_SHUTDOWN_IN_PROGRESS; 1896 1897 if (lpString != NULL) 1898 return ERROR_INVALID_PARAMETER; 1899 1900 if (hServiceStatus == 0) 1901 { 1902 DPRINT("hServiceStatus == NULL\n"); 1903 return ERROR_INVALID_HANDLE; 1904 } 1905 1906 // FIXME: Validate the status handle 1907 pService = (PSERVICE)hServiceStatus; 1908 1909 if (bSetBitsOn) 1910 { 1911 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits); 1912 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits); 1913 pService->dwServiceBits |= dwServiceBits; 1914 g_dwServiceBits |= dwServiceBits; 1915 DPRINT("New service bits: %08lx\n", pService->dwServiceBits); 1916 DPRINT("New global service bits: %08lx\n", g_dwServiceBits); 1917 } 1918 else 1919 { 1920 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits); 1921 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits); 1922 pService->dwServiceBits &= ~dwServiceBits; 1923 g_dwServiceBits &= ~dwServiceBits; 1924 DPRINT("New service bits: %08lx\n", pService->dwServiceBits); 1925 DPRINT("New global service bits: %08lx\n", g_dwServiceBits); 1926 } 1927 1928 return ERROR_SUCCESS; 1929 } 1930 1931 1932 /* Function 11 */ 1933 DWORD 1934 WINAPI 1935 RChangeServiceConfigW( 1936 SC_RPC_HANDLE hService, 1937 DWORD dwServiceType, 1938 DWORD dwStartType, 1939 DWORD dwErrorControl, 1940 LPWSTR lpBinaryPathName, 1941 LPWSTR lpLoadOrderGroup, 1942 LPDWORD lpdwTagId, 1943 LPBYTE lpDependencies, 1944 DWORD dwDependSize, 1945 LPWSTR lpServiceStartName, 1946 LPBYTE lpPassword, 1947 DWORD dwPwSize, 1948 LPWSTR lpDisplayName) 1949 { 1950 DWORD dwError = ERROR_SUCCESS; 1951 PSERVICE_HANDLE hSvc; 1952 PSERVICE lpService = NULL; 1953 HKEY hServiceKey = NULL; 1954 LPWSTR lpDisplayNameW = NULL; 1955 LPWSTR lpImagePathW = NULL; 1956 LPWSTR lpClearTextPassword = NULL; 1957 1958 DPRINT("RChangeServiceConfigW() called\n"); 1959 DPRINT("dwServiceType = 0x%lx\n", dwServiceType); 1960 DPRINT("dwStartType = %lu\n", dwStartType); 1961 DPRINT("dwErrorControl = %lu\n", dwErrorControl); 1962 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName); 1963 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); 1964 DPRINT("lpServiceStartName = %S\n", lpServiceStartName); 1965 DPRINT("lpPassword = %p\n", lpPassword); 1966 DPRINT("dwPwSite = %lu\n", dwPwSize); 1967 DPRINT("lpDisplayName = %S\n", lpDisplayName); 1968 1969 if (ScmShutdown) 1970 return ERROR_SHUTDOWN_IN_PROGRESS; 1971 1972 hSvc = ScmGetServiceFromHandle(hService); 1973 if (hSvc == NULL) 1974 { 1975 DPRINT1("Invalid service handle\n"); 1976 return ERROR_INVALID_HANDLE; 1977 } 1978 1979 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 1980 SERVICE_CHANGE_CONFIG)) 1981 { 1982 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 1983 return ERROR_ACCESS_DENIED; 1984 } 1985 1986 /* Check for invalid service type value */ 1987 if ((dwServiceType != SERVICE_NO_CHANGE) && 1988 (dwServiceType != SERVICE_KERNEL_DRIVER) && 1989 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) && 1990 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && 1991 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS)) 1992 { 1993 return ERROR_INVALID_PARAMETER; 1994 } 1995 1996 /* Check for invalid start type value */ 1997 if ((dwStartType != SERVICE_NO_CHANGE) && 1998 (dwStartType != SERVICE_BOOT_START) && 1999 (dwStartType != SERVICE_SYSTEM_START) && 2000 (dwStartType != SERVICE_AUTO_START) && 2001 (dwStartType != SERVICE_DEMAND_START) && 2002 (dwStartType != SERVICE_DISABLED)) 2003 { 2004 return ERROR_INVALID_PARAMETER; 2005 } 2006 2007 /* Only drivers can be boot start or system start services */ 2008 if ((dwStartType == SERVICE_BOOT_START) || 2009 (dwStartType == SERVICE_SYSTEM_START)) 2010 { 2011 if ((dwServiceType != SERVICE_KERNEL_DRIVER) && 2012 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) 2013 return ERROR_INVALID_PARAMETER; 2014 } 2015 2016 /* Check for invalid error control value */ 2017 if ((dwErrorControl != SERVICE_NO_CHANGE) && 2018 (dwErrorControl != SERVICE_ERROR_IGNORE) && 2019 (dwErrorControl != SERVICE_ERROR_NORMAL) && 2020 (dwErrorControl != SERVICE_ERROR_SEVERE) && 2021 (dwErrorControl != SERVICE_ERROR_CRITICAL)) 2022 { 2023 return ERROR_INVALID_PARAMETER; 2024 } 2025 2026 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup)) 2027 { 2028 return ERROR_INVALID_PARAMETER; 2029 } 2030 2031 lpService = hSvc->ServiceEntry; 2032 if (lpService == NULL) 2033 { 2034 DPRINT("lpService == NULL\n"); 2035 return ERROR_INVALID_HANDLE; 2036 } 2037 2038 /* Lock the service database exclusively */ 2039 ScmLockDatabaseExclusive(); 2040 2041 if (lpService->bDeleted) 2042 { 2043 DPRINT("Service has already been marked for delete\n"); 2044 dwError = ERROR_SERVICE_MARKED_FOR_DELETE; 2045 goto done; 2046 } 2047 2048 /* Open the service key */ 2049 dwError = ScmOpenServiceKey(lpService->szServiceName, 2050 KEY_SET_VALUE, 2051 &hServiceKey); 2052 if (dwError != ERROR_SUCCESS) 2053 goto done; 2054 2055 /* Write service data to the registry */ 2056 2057 /* Set the display name */ 2058 if (lpDisplayName != NULL && *lpDisplayName != 0) 2059 { 2060 RegSetValueExW(hServiceKey, 2061 L"DisplayName", 2062 0, 2063 REG_SZ, 2064 (LPBYTE)lpDisplayName, 2065 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR))); 2066 2067 /* Update the display name */ 2068 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 2069 HEAP_ZERO_MEMORY, 2070 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); 2071 if (lpDisplayNameW == NULL) 2072 { 2073 dwError = ERROR_NOT_ENOUGH_MEMORY; 2074 goto done; 2075 } 2076 2077 wcscpy(lpDisplayNameW, lpDisplayName); 2078 if (lpService->lpDisplayName != lpService->lpServiceName) 2079 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); 2080 2081 lpService->lpDisplayName = lpDisplayNameW; 2082 } 2083 2084 if (dwServiceType != SERVICE_NO_CHANGE) 2085 { 2086 /* Set the service type */ 2087 dwError = RegSetValueExW(hServiceKey, 2088 L"Type", 2089 0, 2090 REG_DWORD, 2091 (LPBYTE)&dwServiceType, 2092 sizeof(DWORD)); 2093 if (dwError != ERROR_SUCCESS) 2094 goto done; 2095 2096 lpService->Status.dwServiceType = dwServiceType; 2097 } 2098 2099 if (dwStartType != SERVICE_NO_CHANGE) 2100 { 2101 /* Set the start value */ 2102 dwError = RegSetValueExW(hServiceKey, 2103 L"Start", 2104 0, 2105 REG_DWORD, 2106 (LPBYTE)&dwStartType, 2107 sizeof(DWORD)); 2108 if (dwError != ERROR_SUCCESS) 2109 goto done; 2110 2111 lpService->dwStartType = dwStartType; 2112 } 2113 2114 if (dwErrorControl != SERVICE_NO_CHANGE) 2115 { 2116 /* Set the error control value */ 2117 dwError = RegSetValueExW(hServiceKey, 2118 L"ErrorControl", 2119 0, 2120 REG_DWORD, 2121 (LPBYTE)&dwErrorControl, 2122 sizeof(DWORD)); 2123 if (dwError != ERROR_SUCCESS) 2124 goto done; 2125 2126 lpService->dwErrorControl = dwErrorControl; 2127 } 2128 2129 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0) 2130 { 2131 /* Set the image path */ 2132 lpImagePathW = lpBinaryPathName; 2133 2134 if (lpService->Status.dwServiceType & SERVICE_DRIVER) 2135 { 2136 dwError = ScmCanonDriverImagePath(lpService->dwStartType, 2137 lpBinaryPathName, 2138 &lpImagePathW); 2139 2140 if (dwError != ERROR_SUCCESS) 2141 goto done; 2142 } 2143 2144 dwError = RegSetValueExW(hServiceKey, 2145 L"ImagePath", 2146 0, 2147 REG_EXPAND_SZ, 2148 (LPBYTE)lpImagePathW, 2149 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR))); 2150 2151 if (lpImagePathW != lpBinaryPathName) 2152 HeapFree(GetProcessHeap(), 0, lpImagePathW); 2153 2154 if (dwError != ERROR_SUCCESS) 2155 goto done; 2156 } 2157 2158 /* Set the group name */ 2159 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) 2160 { 2161 dwError = RegSetValueExW(hServiceKey, 2162 L"Group", 2163 0, 2164 REG_SZ, 2165 (LPBYTE)lpLoadOrderGroup, 2166 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR))); 2167 if (dwError != ERROR_SUCCESS) 2168 goto done; 2169 2170 dwError = ScmSetServiceGroup(lpService, 2171 lpLoadOrderGroup); 2172 if (dwError != ERROR_SUCCESS) 2173 goto done; 2174 } 2175 2176 /* Set the tag */ 2177 if (lpdwTagId != NULL) 2178 { 2179 dwError = ScmAssignNewTag(lpService); 2180 if (dwError != ERROR_SUCCESS) 2181 goto done; 2182 2183 dwError = RegSetValueExW(hServiceKey, 2184 L"Tag", 2185 0, 2186 REG_DWORD, 2187 (LPBYTE)&lpService->dwTag, 2188 sizeof(DWORD)); 2189 if (dwError != ERROR_SUCCESS) 2190 goto done; 2191 2192 *lpdwTagId = lpService->dwTag; 2193 } 2194 2195 /* Write dependencies */ 2196 if (lpDependencies != NULL && *lpDependencies != 0) 2197 { 2198 dwError = ScmWriteDependencies(hServiceKey, 2199 (LPWSTR)lpDependencies, 2200 dwDependSize); 2201 if (dwError != ERROR_SUCCESS) 2202 goto done; 2203 } 2204 2205 /* Start name and password are only used by Win32 services */ 2206 if (lpService->Status.dwServiceType & SERVICE_WIN32) 2207 { 2208 /* Write service start name */ 2209 if (lpServiceStartName != NULL && *lpServiceStartName != 0) 2210 { 2211 dwError = RegSetValueExW(hServiceKey, 2212 L"ObjectName", 2213 0, 2214 REG_SZ, 2215 (LPBYTE)lpServiceStartName, 2216 (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR))); 2217 if (dwError != ERROR_SUCCESS) 2218 goto done; 2219 } 2220 2221 if (lpPassword != NULL) 2222 { 2223 if (*(LPWSTR)lpPassword != 0) 2224 { 2225 /* Decrypt the password */ 2226 dwError = ScmDecryptPassword(hService, 2227 lpPassword, 2228 dwPwSize, 2229 &lpClearTextPassword); 2230 if (dwError != ERROR_SUCCESS) 2231 { 2232 DPRINT1("ScmDecryptPassword failed (Error %lu)\n", dwError); 2233 goto done; 2234 } 2235 DPRINT("Clear text password: %S\n", lpClearTextPassword); 2236 2237 /* Write the password */ 2238 dwError = ScmSetServicePassword(lpService->szServiceName, 2239 lpClearTextPassword); 2240 if (dwError != ERROR_SUCCESS) 2241 { 2242 DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError); 2243 goto done; 2244 } 2245 } 2246 else 2247 { 2248 /* Delete the password */ 2249 dwError = ScmSetServicePassword(lpService->szServiceName, 2250 NULL); 2251 if (dwError == ERROR_FILE_NOT_FOUND) 2252 dwError = ERROR_SUCCESS; 2253 2254 if (dwError != ERROR_SUCCESS) 2255 { 2256 DPRINT1("ScmSetServicePassword failed (Error %lu)\n", dwError); 2257 goto done; 2258 } 2259 } 2260 } 2261 } 2262 2263 done: 2264 if (lpClearTextPassword != NULL) 2265 { 2266 /* Wipe and release the password buffer */ 2267 SecureZeroMemory(lpClearTextPassword, 2268 (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR)); 2269 HeapFree(GetProcessHeap(), 0, lpClearTextPassword); 2270 } 2271 2272 if (hServiceKey != NULL) 2273 RegCloseKey(hServiceKey); 2274 2275 /* Unlock the service database */ 2276 ScmUnlockDatabase(); 2277 2278 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError); 2279 2280 return dwError; 2281 } 2282 2283 2284 /* Function 12 */ 2285 DWORD 2286 WINAPI 2287 RCreateServiceW( 2288 SC_RPC_HANDLE hSCManager, 2289 LPCWSTR lpServiceName, 2290 LPCWSTR lpDisplayName, 2291 DWORD dwDesiredAccess, 2292 DWORD dwServiceType, 2293 DWORD dwStartType, 2294 DWORD dwErrorControl, 2295 LPCWSTR lpBinaryPathName, 2296 LPCWSTR lpLoadOrderGroup, 2297 LPDWORD lpdwTagId, 2298 LPBYTE lpDependencies, 2299 DWORD dwDependSize, 2300 LPCWSTR lpServiceStartName, 2301 LPBYTE lpPassword, 2302 DWORD dwPwSize, 2303 LPSC_RPC_HANDLE lpServiceHandle) 2304 { 2305 PMANAGER_HANDLE hManager; 2306 DWORD dwError = ERROR_SUCCESS; 2307 PSERVICE lpService = NULL; 2308 SC_HANDLE hServiceHandle = NULL; 2309 LPWSTR lpImagePath = NULL; 2310 LPWSTR lpClearTextPassword = NULL; 2311 HKEY hServiceKey = NULL; 2312 LPWSTR lpObjectName; 2313 2314 DPRINT("RCreateServiceW() called\n"); 2315 DPRINT("lpServiceName = %S\n", lpServiceName); 2316 DPRINT("lpDisplayName = %S\n", lpDisplayName); 2317 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess); 2318 DPRINT("dwServiceType = 0x%lx\n", dwServiceType); 2319 DPRINT("dwStartType = %lu\n", dwStartType); 2320 DPRINT("dwErrorControl = %lu\n", dwErrorControl); 2321 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName); 2322 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup); 2323 DPRINT("lpdwTagId = %p\n", lpdwTagId); 2324 2325 if (ScmShutdown) 2326 return ERROR_SHUTDOWN_IN_PROGRESS; 2327 2328 hManager = ScmGetServiceManagerFromHandle(hSCManager); 2329 if (hManager == NULL) 2330 { 2331 DPRINT1("Invalid service manager handle\n"); 2332 return ERROR_INVALID_HANDLE; 2333 } 2334 2335 /* Check access rights */ 2336 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, 2337 SC_MANAGER_CREATE_SERVICE)) 2338 { 2339 DPRINT("Insufficient access rights! 0x%lx\n", 2340 hManager->Handle.DesiredAccess); 2341 return ERROR_ACCESS_DENIED; 2342 } 2343 2344 if (*lpServiceName == 0) 2345 return ERROR_INVALID_NAME; 2346 2347 if (*lpBinaryPathName == 0) 2348 return ERROR_INVALID_PARAMETER; 2349 2350 /* Check for invalid service type value */ 2351 if ((dwServiceType != SERVICE_KERNEL_DRIVER) && 2352 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) && 2353 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) && 2354 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS)) 2355 { 2356 return ERROR_INVALID_PARAMETER; 2357 } 2358 2359 /* Check for invalid start type value */ 2360 if ((dwStartType != SERVICE_BOOT_START) && 2361 (dwStartType != SERVICE_SYSTEM_START) && 2362 (dwStartType != SERVICE_AUTO_START) && 2363 (dwStartType != SERVICE_DEMAND_START) && 2364 (dwStartType != SERVICE_DISABLED)) 2365 { 2366 return ERROR_INVALID_PARAMETER; 2367 } 2368 2369 /* Only drivers can be boot start or system start services */ 2370 if ((dwStartType == SERVICE_BOOT_START) || 2371 (dwStartType == SERVICE_SYSTEM_START)) 2372 { 2373 if ((dwServiceType != SERVICE_KERNEL_DRIVER) && 2374 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER)) 2375 { 2376 return ERROR_INVALID_PARAMETER; 2377 } 2378 } 2379 2380 /* Check for invalid error control value */ 2381 if ((dwErrorControl != SERVICE_ERROR_IGNORE) && 2382 (dwErrorControl != SERVICE_ERROR_NORMAL) && 2383 (dwErrorControl != SERVICE_ERROR_SEVERE) && 2384 (dwErrorControl != SERVICE_ERROR_CRITICAL)) 2385 { 2386 return ERROR_INVALID_PARAMETER; 2387 } 2388 2389 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) && 2390 (lpServiceStartName)) 2391 { 2392 /* We allow LocalSystem to run interactive. */ 2393 if (_wcsicmp(lpServiceStartName, L"LocalSystem")) 2394 { 2395 return ERROR_INVALID_PARAMETER; 2396 } 2397 } 2398 2399 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup)) 2400 { 2401 return ERROR_INVALID_PARAMETER; 2402 } 2403 2404 /* Lock the service database exclusively */ 2405 ScmLockDatabaseExclusive(); 2406 2407 lpService = ScmGetServiceEntryByName(lpServiceName); 2408 if (lpService) 2409 { 2410 /* Unlock the service database */ 2411 ScmUnlockDatabase(); 2412 2413 /* Check if it is marked for deletion */ 2414 if (lpService->bDeleted) 2415 return ERROR_SERVICE_MARKED_FOR_DELETE; 2416 2417 /* Return service-exists error */ 2418 return ERROR_SERVICE_EXISTS; 2419 } 2420 2421 if (lpDisplayName != NULL && 2422 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL) 2423 { 2424 /* Unlock the service database */ 2425 ScmUnlockDatabase(); 2426 2427 return ERROR_DUPLICATE_SERVICE_NAME; 2428 } 2429 2430 if (dwServiceType & SERVICE_DRIVER) 2431 { 2432 dwError = ScmCanonDriverImagePath(dwStartType, 2433 lpBinaryPathName, 2434 &lpImagePath); 2435 if (dwError != ERROR_SUCCESS) 2436 goto done; 2437 } 2438 else 2439 { 2440 if (dwStartType == SERVICE_BOOT_START || 2441 dwStartType == SERVICE_SYSTEM_START) 2442 { 2443 /* Unlock the service database */ 2444 ScmUnlockDatabase(); 2445 2446 return ERROR_INVALID_PARAMETER; 2447 } 2448 } 2449 2450 /* Allocate a new service entry */ 2451 dwError = ScmCreateNewServiceRecord(lpServiceName, 2452 &lpService, 2453 dwServiceType, 2454 dwStartType); 2455 if (dwError != ERROR_SUCCESS) 2456 goto done; 2457 2458 /* Fill the new service entry */ 2459 lpService->dwErrorControl = dwErrorControl; 2460 2461 /* Fill the display name */ 2462 if (lpDisplayName != NULL && 2463 *lpDisplayName != 0 && 2464 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0) 2465 { 2466 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(), 2467 HEAP_ZERO_MEMORY, 2468 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR)); 2469 if (lpService->lpDisplayName == NULL) 2470 { 2471 dwError = ERROR_NOT_ENOUGH_MEMORY; 2472 goto done; 2473 } 2474 wcscpy(lpService->lpDisplayName, lpDisplayName); 2475 } 2476 2477 /* Assign the service to a group */ 2478 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) 2479 { 2480 dwError = ScmSetServiceGroup(lpService, 2481 lpLoadOrderGroup); 2482 if (dwError != ERROR_SUCCESS) 2483 goto done; 2484 } 2485 2486 /* Assign a new tag */ 2487 if (lpdwTagId != NULL) 2488 { 2489 dwError = ScmAssignNewTag(lpService); 2490 if (dwError != ERROR_SUCCESS) 2491 goto done; 2492 } 2493 2494 /* Assign the default security descriptor */ 2495 if (dwServiceType & SERVICE_WIN32) 2496 { 2497 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor); 2498 if (dwError != ERROR_SUCCESS) 2499 goto done; 2500 } 2501 2502 /* Write service data to the registry */ 2503 /* Create the service key */ 2504 dwError = ScmCreateServiceKey(lpServiceName, 2505 KEY_WRITE, 2506 &hServiceKey); 2507 if (dwError != ERROR_SUCCESS) 2508 goto done; 2509 2510 /* Set the display name */ 2511 if (lpDisplayName != NULL && *lpDisplayName != 0) 2512 { 2513 RegSetValueExW(hServiceKey, 2514 L"DisplayName", 2515 0, 2516 REG_SZ, 2517 (LPBYTE)lpDisplayName, 2518 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR))); 2519 } 2520 2521 /* Set the service type */ 2522 dwError = RegSetValueExW(hServiceKey, 2523 L"Type", 2524 0, 2525 REG_DWORD, 2526 (LPBYTE)&dwServiceType, 2527 sizeof(DWORD)); 2528 if (dwError != ERROR_SUCCESS) 2529 goto done; 2530 2531 /* Set the start value */ 2532 dwError = RegSetValueExW(hServiceKey, 2533 L"Start", 2534 0, 2535 REG_DWORD, 2536 (LPBYTE)&dwStartType, 2537 sizeof(DWORD)); 2538 if (dwError != ERROR_SUCCESS) 2539 goto done; 2540 2541 /* Set the error control value */ 2542 dwError = RegSetValueExW(hServiceKey, 2543 L"ErrorControl", 2544 0, 2545 REG_DWORD, 2546 (LPBYTE)&dwErrorControl, 2547 sizeof(DWORD)); 2548 if (dwError != ERROR_SUCCESS) 2549 goto done; 2550 2551 /* Set the image path */ 2552 if (dwServiceType & SERVICE_WIN32) 2553 { 2554 dwError = RegSetValueExW(hServiceKey, 2555 L"ImagePath", 2556 0, 2557 REG_EXPAND_SZ, 2558 (LPBYTE)lpBinaryPathName, 2559 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR))); 2560 if (dwError != ERROR_SUCCESS) 2561 goto done; 2562 } 2563 else if (dwServiceType & SERVICE_DRIVER) 2564 { 2565 dwError = RegSetValueExW(hServiceKey, 2566 L"ImagePath", 2567 0, 2568 REG_EXPAND_SZ, 2569 (LPBYTE)lpImagePath, 2570 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR))); 2571 if (dwError != ERROR_SUCCESS) 2572 goto done; 2573 } 2574 2575 /* Set the group name */ 2576 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0) 2577 { 2578 dwError = RegSetValueExW(hServiceKey, 2579 L"Group", 2580 0, 2581 REG_SZ, 2582 (LPBYTE)lpLoadOrderGroup, 2583 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR))); 2584 if (dwError != ERROR_SUCCESS) 2585 goto done; 2586 } 2587 2588 /* Set the service tag */ 2589 if (lpdwTagId != NULL) 2590 { 2591 dwError = RegSetValueExW(hServiceKey, 2592 L"Tag", 2593 0, 2594 REG_DWORD, 2595 (LPBYTE)&lpService->dwTag, 2596 sizeof(DWORD)); 2597 if (dwError != ERROR_SUCCESS) 2598 goto done; 2599 } 2600 2601 /* Write dependencies */ 2602 if (lpDependencies != NULL && *lpDependencies != 0) 2603 { 2604 dwError = ScmWriteDependencies(hServiceKey, 2605 (LPCWSTR)lpDependencies, 2606 dwDependSize); 2607 if (dwError != ERROR_SUCCESS) 2608 goto done; 2609 } 2610 2611 /* Start name and password are only used by Win32 services */ 2612 if (dwServiceType & SERVICE_WIN32) 2613 { 2614 /* Write service start name */ 2615 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem"; 2616 dwError = RegSetValueExW(hServiceKey, 2617 L"ObjectName", 2618 0, 2619 REG_SZ, 2620 (LPBYTE)lpObjectName, 2621 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR))); 2622 if (dwError != ERROR_SUCCESS) 2623 goto done; 2624 2625 if (lpPassword != NULL && *(LPWSTR)lpPassword != 0) 2626 { 2627 /* Decrypt the password */ 2628 dwError = ScmDecryptPassword(hSCManager, 2629 lpPassword, 2630 dwPwSize, 2631 &lpClearTextPassword); 2632 if (dwError != ERROR_SUCCESS) 2633 goto done; 2634 2635 /* Write the password */ 2636 dwError = ScmSetServicePassword(lpServiceName, 2637 lpClearTextPassword); 2638 if (dwError != ERROR_SUCCESS) 2639 goto done; 2640 } 2641 2642 /* Write the security descriptor */ 2643 dwError = ScmWriteSecurityDescriptor(hServiceKey, 2644 lpService->pSecurityDescriptor); 2645 if (dwError != ERROR_SUCCESS) 2646 goto done; 2647 } 2648 2649 dwError = ScmCreateServiceHandle(lpService, 2650 &hServiceHandle); 2651 if (dwError != ERROR_SUCCESS) 2652 goto done; 2653 2654 dwError = ScmCheckAccess(hServiceHandle, 2655 dwDesiredAccess); 2656 if (dwError != ERROR_SUCCESS) 2657 goto done; 2658 2659 ScmReferenceService(lpService); 2660 2661 /* Get the service tag (if Win32) */ 2662 ScmGenerateServiceTag(lpService); 2663 2664 DPRINT("CreateService - lpService->RefCount %u\n", lpService->RefCount); 2665 2666 done: 2667 /* Unlock the service database */ 2668 ScmUnlockDatabase(); 2669 2670 if (hServiceKey != NULL) 2671 RegCloseKey(hServiceKey); 2672 2673 if (lpClearTextPassword != NULL) 2674 { 2675 /* Wipe and release the password buffer */ 2676 SecureZeroMemory(lpClearTextPassword, 2677 (wcslen(lpClearTextPassword) + 1) * sizeof(WCHAR)); 2678 HeapFree(GetProcessHeap(), 0, lpClearTextPassword); 2679 } 2680 2681 if (dwError == ERROR_SUCCESS) 2682 { 2683 DPRINT("hService %p\n", hServiceHandle); 2684 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle; 2685 2686 if (lpdwTagId != NULL) 2687 *lpdwTagId = lpService->dwTag; 2688 } 2689 else 2690 { 2691 if (lpService != NULL && 2692 lpService->lpServiceName != NULL) 2693 { 2694 /* Release the display name buffer */ 2695 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName); 2696 } 2697 2698 if (hServiceHandle) 2699 { 2700 /* Remove the service handle */ 2701 HeapFree(GetProcessHeap(), 0, hServiceHandle); 2702 } 2703 2704 if (lpService != NULL) 2705 { 2706 /* FIXME: remove the service entry */ 2707 } 2708 } 2709 2710 if (lpImagePath != NULL) 2711 HeapFree(GetProcessHeap(), 0, lpImagePath); 2712 2713 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError); 2714 2715 return dwError; 2716 } 2717 2718 2719 /* Function 13 */ 2720 DWORD 2721 WINAPI 2722 REnumDependentServicesW( 2723 SC_RPC_HANDLE hService, 2724 DWORD dwServiceState, 2725 LPBYTE lpServices, 2726 DWORD cbBufSize, 2727 LPBOUNDED_DWORD_256K pcbBytesNeeded, 2728 LPBOUNDED_DWORD_256K lpServicesReturned) 2729 { 2730 DWORD dwError = ERROR_SUCCESS; 2731 DWORD dwServicesReturned = 0; 2732 DWORD dwServiceCount; 2733 HKEY hServicesKey = NULL; 2734 PSERVICE_HANDLE hSvc; 2735 PSERVICE lpService = NULL; 2736 PSERVICE *lpServicesArray = NULL; 2737 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL; 2738 LPWSTR lpStr; 2739 2740 *pcbBytesNeeded = 0; 2741 *lpServicesReturned = 0; 2742 2743 DPRINT("REnumDependentServicesW() called\n"); 2744 2745 hSvc = ScmGetServiceFromHandle(hService); 2746 if (hSvc == NULL) 2747 { 2748 DPRINT1("Invalid service handle\n"); 2749 return ERROR_INVALID_HANDLE; 2750 } 2751 2752 lpService = hSvc->ServiceEntry; 2753 2754 /* Check access rights */ 2755 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 2756 SC_MANAGER_ENUMERATE_SERVICE)) 2757 { 2758 DPRINT("Insufficient access rights! 0x%lx\n", 2759 hSvc->Handle.DesiredAccess); 2760 return ERROR_ACCESS_DENIED; 2761 } 2762 2763 /* Open the Services Reg key */ 2764 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 2765 L"System\\CurrentControlSet\\Services", 2766 0, 2767 KEY_READ, 2768 &hServicesKey); 2769 if (dwError != ERROR_SUCCESS) 2770 return dwError; 2771 2772 /* First determine the bytes needed and get the number of dependent services */ 2773 dwError = Int_EnumDependentServicesW(hServicesKey, 2774 lpService, 2775 dwServiceState, 2776 NULL, 2777 pcbBytesNeeded, 2778 &dwServicesReturned); 2779 if (dwError != ERROR_SUCCESS) 2780 goto Done; 2781 2782 /* If buffer size is less than the bytes needed or pointer is null */ 2783 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded)) 2784 { 2785 dwError = ERROR_MORE_DATA; 2786 goto Done; 2787 } 2788 2789 /* Allocate memory for array of service pointers */ 2790 lpServicesArray = HeapAlloc(GetProcessHeap(), 2791 HEAP_ZERO_MEMORY, 2792 (dwServicesReturned + 1) * sizeof(PSERVICE)); 2793 if (!lpServicesArray) 2794 { 2795 DPRINT1("Could not allocate buffer\n"); 2796 dwError = ERROR_NOT_ENOUGH_MEMORY; 2797 goto Done; 2798 } 2799 2800 dwServicesReturned = 0; 2801 *pcbBytesNeeded = 0; 2802 2803 dwError = Int_EnumDependentServicesW(hServicesKey, 2804 lpService, 2805 dwServiceState, 2806 lpServicesArray, 2807 pcbBytesNeeded, 2808 &dwServicesReturned); 2809 if (dwError != ERROR_SUCCESS) 2810 { 2811 goto Done; 2812 } 2813 2814 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices; 2815 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW))); 2816 2817 /* Copy EnumDepenedentService to Buffer */ 2818 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++) 2819 { 2820 lpService = lpServicesArray[dwServiceCount]; 2821 2822 /* Copy status info */ 2823 memcpy(&lpServicesPtr->ServiceStatus, 2824 &lpService->Status, 2825 sizeof(SERVICE_STATUS)); 2826 2827 /* Copy display name */ 2828 wcscpy(lpStr, lpService->lpDisplayName); 2829 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); 2830 lpStr += (wcslen(lpService->lpDisplayName) + 1); 2831 2832 /* Copy service name */ 2833 wcscpy(lpStr, lpService->lpServiceName); 2834 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); 2835 lpStr += (wcslen(lpService->lpServiceName) + 1); 2836 2837 lpServicesPtr++; 2838 } 2839 2840 *lpServicesReturned = dwServicesReturned; 2841 2842 Done: 2843 if (lpServicesArray != NULL) 2844 HeapFree(GetProcessHeap(), 0, lpServicesArray); 2845 2846 RegCloseKey(hServicesKey); 2847 2848 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError); 2849 2850 return dwError; 2851 } 2852 2853 2854 /* Function 14 */ 2855 DWORD 2856 WINAPI 2857 REnumServicesStatusW( 2858 SC_RPC_HANDLE hSCManager, 2859 DWORD dwServiceType, 2860 DWORD dwServiceState, 2861 LPBYTE lpBuffer, 2862 DWORD dwBufSize, 2863 LPBOUNDED_DWORD_256K pcbBytesNeeded, 2864 LPBOUNDED_DWORD_256K lpServicesReturned, 2865 LPBOUNDED_DWORD_256K lpResumeHandle) 2866 { 2867 /* Enumerate all the services, not regarding of their group */ 2868 return REnumServiceGroupW(hSCManager, 2869 dwServiceType, 2870 dwServiceState, 2871 lpBuffer, 2872 dwBufSize, 2873 pcbBytesNeeded, 2874 lpServicesReturned, 2875 lpResumeHandle, 2876 NULL); 2877 } 2878 2879 2880 /* Function 15 */ 2881 DWORD 2882 WINAPI 2883 ROpenSCManagerW( 2884 LPWSTR lpMachineName, 2885 LPWSTR lpDatabaseName, 2886 DWORD dwDesiredAccess, 2887 LPSC_RPC_HANDLE lpScHandle) 2888 { 2889 DWORD dwError; 2890 SC_HANDLE hHandle; 2891 2892 DPRINT("ROpenSCManagerW() called\n"); 2893 DPRINT("lpMachineName = %p\n", lpMachineName); 2894 DPRINT("lpMachineName: %S\n", lpMachineName); 2895 DPRINT("lpDataBaseName = %p\n", lpDatabaseName); 2896 DPRINT("lpDataBaseName: %S\n", lpDatabaseName); 2897 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); 2898 2899 if (ScmShutdown) 2900 return ERROR_SHUTDOWN_IN_PROGRESS; 2901 2902 if (!lpScHandle) 2903 return ERROR_INVALID_PARAMETER; 2904 2905 dwError = ScmCreateManagerHandle(lpDatabaseName, 2906 &hHandle); 2907 if (dwError != ERROR_SUCCESS) 2908 { 2909 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError); 2910 return dwError; 2911 } 2912 2913 /* Check the desired access */ 2914 dwError = ScmCheckAccess(hHandle, 2915 dwDesiredAccess | SC_MANAGER_CONNECT); 2916 if (dwError != ERROR_SUCCESS) 2917 { 2918 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError); 2919 HeapFree(GetProcessHeap(), 0, hHandle); 2920 return dwError; 2921 } 2922 2923 *lpScHandle = (SC_RPC_HANDLE)hHandle; 2924 DPRINT("*hScm = %p\n", *lpScHandle); 2925 2926 DPRINT("ROpenSCManagerW() done\n"); 2927 2928 return ERROR_SUCCESS; 2929 } 2930 2931 2932 /* Function 16 */ 2933 DWORD 2934 WINAPI 2935 ROpenServiceW( 2936 SC_RPC_HANDLE hSCManager, 2937 LPWSTR lpServiceName, 2938 DWORD dwDesiredAccess, 2939 LPSC_RPC_HANDLE lpServiceHandle) 2940 { 2941 PSERVICE lpService; 2942 PMANAGER_HANDLE hManager; 2943 SC_HANDLE hHandle; 2944 DWORD dwError = ERROR_SUCCESS; 2945 2946 DPRINT("ROpenServiceW() called\n"); 2947 DPRINT("hSCManager = %p\n", hSCManager); 2948 DPRINT("lpServiceName = %p\n", lpServiceName); 2949 DPRINT("lpServiceName: %S\n", lpServiceName); 2950 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess); 2951 2952 if (ScmShutdown) 2953 return ERROR_SHUTDOWN_IN_PROGRESS; 2954 2955 hManager = ScmGetServiceManagerFromHandle(hSCManager); 2956 if (hManager == NULL) 2957 { 2958 DPRINT1("Invalid service manager handle\n"); 2959 return ERROR_INVALID_HANDLE; 2960 } 2961 2962 if (!lpServiceHandle) 2963 return ERROR_INVALID_PARAMETER; 2964 2965 if (!lpServiceName) 2966 return ERROR_INVALID_ADDRESS; 2967 2968 /* Lock the service database exclusive */ 2969 ScmLockDatabaseExclusive(); 2970 2971 /* Get service database entry */ 2972 lpService = ScmGetServiceEntryByName(lpServiceName); 2973 if (lpService == NULL) 2974 { 2975 DPRINT("Could not find service\n"); 2976 dwError = ERROR_SERVICE_DOES_NOT_EXIST; 2977 goto Done; 2978 } 2979 2980 /* Create a service handle */ 2981 dwError = ScmCreateServiceHandle(lpService, 2982 &hHandle); 2983 if (dwError != ERROR_SUCCESS) 2984 { 2985 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError); 2986 goto Done; 2987 } 2988 2989 /* Check the desired access */ 2990 dwError = ScmCheckAccess(hHandle, 2991 dwDesiredAccess); 2992 if (dwError != ERROR_SUCCESS) 2993 { 2994 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError); 2995 HeapFree(GetProcessHeap(), 0, hHandle); 2996 goto Done; 2997 } 2998 2999 ScmReferenceService(lpService); 3000 DPRINT("OpenService %S - lpService->RefCount %u\n", lpService->lpServiceName, lpService->RefCount); 3001 3002 *lpServiceHandle = (SC_RPC_HANDLE)hHandle; 3003 DPRINT("*hService = %p\n", *lpServiceHandle); 3004 3005 Done: 3006 /* Unlock the service database */ 3007 ScmUnlockDatabase(); 3008 3009 DPRINT("ROpenServiceW() done\n"); 3010 3011 return dwError; 3012 } 3013 3014 3015 /* Function 17 */ 3016 DWORD 3017 WINAPI 3018 RQueryServiceConfigW( 3019 SC_RPC_HANDLE hService, 3020 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig, 3021 DWORD cbBufSize, 3022 LPBOUNDED_DWORD_8K pcbBytesNeeded) 3023 { 3024 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf; 3025 DWORD dwError = ERROR_SUCCESS; 3026 PSERVICE_HANDLE hSvc; 3027 PSERVICE lpService = NULL; 3028 HKEY hServiceKey = NULL; 3029 LPWSTR lpImagePath = NULL; 3030 LPWSTR lpServiceStartName = NULL; 3031 LPWSTR lpDependencies = NULL; 3032 DWORD dwDependenciesLength = 0; 3033 DWORD dwRequiredSize; 3034 LPWSTR lpStr; 3035 3036 DPRINT("RQueryServiceConfigW() called\n"); 3037 3038 if (ScmShutdown) 3039 return ERROR_SHUTDOWN_IN_PROGRESS; 3040 3041 hSvc = ScmGetServiceFromHandle(hService); 3042 if (hSvc == NULL) 3043 { 3044 DPRINT1("Invalid service handle\n"); 3045 return ERROR_INVALID_HANDLE; 3046 } 3047 3048 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 3049 SERVICE_QUERY_CONFIG)) 3050 { 3051 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 3052 return ERROR_ACCESS_DENIED; 3053 } 3054 3055 lpService = hSvc->ServiceEntry; 3056 if (lpService == NULL) 3057 { 3058 DPRINT("lpService == NULL\n"); 3059 return ERROR_INVALID_HANDLE; 3060 } 3061 3062 /* Lock the service database shared */ 3063 ScmLockDatabaseShared(); 3064 3065 dwError = ScmOpenServiceKey(lpService->lpServiceName, 3066 KEY_READ, 3067 &hServiceKey); 3068 if (dwError != ERROR_SUCCESS) 3069 goto Done; 3070 3071 /* Read the image path */ 3072 dwError = ScmReadString(hServiceKey, 3073 L"ImagePath", 3074 &lpImagePath); 3075 if (dwError != ERROR_SUCCESS) 3076 goto Done; 3077 3078 /* Read the service start name */ 3079 ScmReadString(hServiceKey, 3080 L"ObjectName", 3081 &lpServiceStartName); 3082 3083 /* Read the dependencies */ 3084 ScmReadDependencies(hServiceKey, 3085 &lpDependencies, 3086 &dwDependenciesLength); 3087 3088 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW); 3089 3090 if (lpImagePath != NULL) 3091 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)); 3092 else 3093 dwRequiredSize += 2 * sizeof(WCHAR); 3094 3095 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL)) 3096 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR)); 3097 else 3098 dwRequiredSize += 2 * sizeof(WCHAR); 3099 3100 if (lpDependencies != NULL) 3101 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR); 3102 else 3103 dwRequiredSize += 2 * sizeof(WCHAR); 3104 3105 if (lpServiceStartName != NULL) 3106 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR)); 3107 else 3108 dwRequiredSize += 2 * sizeof(WCHAR); 3109 3110 if (lpService->lpDisplayName != NULL) 3111 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR)); 3112 else 3113 dwRequiredSize += 2 * sizeof(WCHAR); 3114 3115 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize) 3116 { 3117 dwError = ERROR_INSUFFICIENT_BUFFER; 3118 } 3119 else 3120 { 3121 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType; 3122 lpServiceConfig->dwStartType = lpService->dwStartType; 3123 lpServiceConfig->dwErrorControl = lpService->dwErrorControl; 3124 lpServiceConfig->dwTagId = lpService->dwTag; 3125 3126 lpStr = (LPWSTR)(lpServiceConfig + 1); 3127 3128 /* Append the image path */ 3129 if (lpImagePath != NULL) 3130 { 3131 wcscpy(lpStr, lpImagePath); 3132 } 3133 else 3134 { 3135 *lpStr = 0; 3136 } 3137 3138 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 3139 lpStr += (wcslen(lpStr) + 1); 3140 3141 /* Append the group name */ 3142 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL)) 3143 { 3144 wcscpy(lpStr, lpService->lpGroup->lpGroupName); 3145 } 3146 else 3147 { 3148 *lpStr = 0; 3149 } 3150 3151 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 3152 lpStr += (wcslen(lpStr) + 1); 3153 3154 /* Append Dependencies */ 3155 if (lpDependencies != NULL) 3156 { 3157 memcpy(lpStr, 3158 lpDependencies, 3159 dwDependenciesLength * sizeof(WCHAR)); 3160 } 3161 else 3162 { 3163 *lpStr = 0; 3164 } 3165 3166 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 3167 if (lpDependencies != NULL) 3168 lpStr += dwDependenciesLength; 3169 else 3170 lpStr += (wcslen(lpStr) + 1); 3171 3172 /* Append the service start name */ 3173 if (lpServiceStartName != NULL) 3174 { 3175 wcscpy(lpStr, lpServiceStartName); 3176 } 3177 else 3178 { 3179 *lpStr = 0; 3180 } 3181 3182 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 3183 lpStr += (wcslen(lpStr) + 1); 3184 3185 /* Append the display name */ 3186 if (lpService->lpDisplayName != NULL) 3187 { 3188 wcscpy(lpStr, lpService->lpDisplayName); 3189 } 3190 else 3191 { 3192 *lpStr = 0; 3193 } 3194 3195 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 3196 } 3197 3198 if (pcbBytesNeeded != NULL) 3199 *pcbBytesNeeded = dwRequiredSize; 3200 3201 Done: 3202 /* Unlock the service database */ 3203 ScmUnlockDatabase(); 3204 3205 if (lpImagePath != NULL) 3206 HeapFree(GetProcessHeap(), 0, lpImagePath); 3207 3208 if (lpServiceStartName != NULL) 3209 HeapFree(GetProcessHeap(), 0, lpServiceStartName); 3210 3211 if (lpDependencies != NULL) 3212 HeapFree(GetProcessHeap(), 0, lpDependencies); 3213 3214 if (hServiceKey != NULL) 3215 RegCloseKey(hServiceKey); 3216 3217 DPRINT("RQueryServiceConfigW() done\n"); 3218 3219 return dwError; 3220 } 3221 3222 3223 /* Function 18 */ 3224 DWORD 3225 WINAPI 3226 RQueryServiceLockStatusW( 3227 SC_RPC_HANDLE hSCManager, 3228 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus, 3229 DWORD cbBufSize, 3230 LPBOUNDED_DWORD_4K pcbBytesNeeded) 3231 { 3232 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf; 3233 PMANAGER_HANDLE hMgr; 3234 DWORD dwRequiredSize; 3235 3236 if (!lpLockStatus || !pcbBytesNeeded) 3237 return ERROR_INVALID_PARAMETER; 3238 3239 hMgr = ScmGetServiceManagerFromHandle(hSCManager); 3240 if (hMgr == NULL) 3241 { 3242 DPRINT1("Invalid service manager handle\n"); 3243 return ERROR_INVALID_HANDLE; 3244 } 3245 3246 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, 3247 SC_MANAGER_QUERY_LOCK_STATUS)) 3248 { 3249 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess); 3250 return ERROR_ACCESS_DENIED; 3251 } 3252 3253 /* FIXME: we need to compute instead the real length of the owner name */ 3254 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR); 3255 *pcbBytesNeeded = dwRequiredSize; 3256 3257 if (cbBufSize < dwRequiredSize) 3258 return ERROR_INSUFFICIENT_BUFFER; 3259 3260 ScmQueryServiceLockStatusW(lpLockStatus); 3261 3262 return ERROR_SUCCESS; 3263 } 3264 3265 3266 /* Function 19 */ 3267 DWORD 3268 WINAPI 3269 RStartServiceW( 3270 SC_RPC_HANDLE hService, 3271 DWORD argc, 3272 LPSTRING_PTRSW argv) 3273 { 3274 DWORD dwError = ERROR_SUCCESS; 3275 PSERVICE_HANDLE hSvc; 3276 PSERVICE lpService = NULL; 3277 3278 #ifndef NDEBUG 3279 DWORD i; 3280 3281 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv); 3282 DPRINT(" argc: %lu\n", argc); 3283 if (argv != NULL) 3284 { 3285 for (i = 0; i < argc; i++) 3286 { 3287 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr); 3288 } 3289 } 3290 #endif 3291 3292 if (ScmShutdown) 3293 return ERROR_SHUTDOWN_IN_PROGRESS; 3294 3295 hSvc = ScmGetServiceFromHandle(hService); 3296 if (hSvc == NULL) 3297 { 3298 DPRINT1("Invalid service handle\n"); 3299 return ERROR_INVALID_HANDLE; 3300 } 3301 3302 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 3303 SERVICE_START)) 3304 { 3305 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 3306 return ERROR_ACCESS_DENIED; 3307 } 3308 3309 lpService = hSvc->ServiceEntry; 3310 if (lpService == NULL) 3311 { 3312 DPRINT("lpService == NULL\n"); 3313 return ERROR_INVALID_HANDLE; 3314 } 3315 3316 if (lpService->dwStartType == SERVICE_DISABLED) 3317 return ERROR_SERVICE_DISABLED; 3318 3319 if (lpService->bDeleted) 3320 return ERROR_SERVICE_MARKED_FOR_DELETE; 3321 3322 /* Start the service */ 3323 dwError = ScmStartService(lpService, argc, (PCWSTR*)argv); 3324 3325 return dwError; 3326 } 3327 3328 3329 /* Function 20 */ 3330 DWORD 3331 WINAPI 3332 RGetServiceDisplayNameW( 3333 SC_RPC_HANDLE hSCManager, 3334 LPCWSTR lpServiceName, 3335 LPWSTR lpDisplayName, 3336 DWORD *lpcchBuffer) 3337 { 3338 // PMANAGER_HANDLE hManager; 3339 PSERVICE lpService; 3340 LPCWSTR lpSvcDisplayName; 3341 DWORD dwLength; 3342 DWORD dwError; 3343 3344 DPRINT("RGetServiceDisplayNameW() called\n"); 3345 DPRINT("hSCManager = %p\n", hSCManager); 3346 DPRINT("lpServiceName: %S\n", lpServiceName); 3347 DPRINT("lpDisplayName: %p\n", lpDisplayName); 3348 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); 3349 3350 #if 0 3351 hManager = (PMANAGER_HANDLE)hSCManager; 3352 if (hManager->Handle.Tag != MANAGER_TAG) 3353 { 3354 DPRINT("Invalid manager handle\n"); 3355 return ERROR_INVALID_HANDLE; 3356 } 3357 #endif 3358 3359 /* Get service database entry */ 3360 lpService = ScmGetServiceEntryByName(lpServiceName); 3361 if (lpService == NULL) 3362 { 3363 DPRINT("Could not find service\n"); 3364 return ERROR_SERVICE_DOES_NOT_EXIST; 3365 } 3366 3367 if (lpService->lpDisplayName) 3368 lpSvcDisplayName = lpService->lpDisplayName; 3369 else 3370 lpSvcDisplayName = lpService->lpServiceName; 3371 3372 dwLength = (DWORD)wcslen(lpSvcDisplayName); 3373 3374 if (*lpcchBuffer > dwLength) 3375 { 3376 if (lpDisplayName != NULL) 3377 wcscpy(lpDisplayName, lpSvcDisplayName); 3378 3379 dwError = ERROR_SUCCESS; 3380 } 3381 else 3382 { 3383 dwError = ERROR_INSUFFICIENT_BUFFER; 3384 } 3385 3386 *lpcchBuffer = dwLength; 3387 3388 return dwError; 3389 } 3390 3391 3392 /* Function 21 */ 3393 DWORD 3394 WINAPI 3395 RGetServiceKeyNameW( 3396 SC_RPC_HANDLE hSCManager, 3397 LPCWSTR lpDisplayName, 3398 LPWSTR lpServiceName, 3399 DWORD *lpcchBuffer) 3400 { 3401 // PMANAGER_HANDLE hManager; 3402 PSERVICE lpService; 3403 DWORD dwLength; 3404 DWORD dwError; 3405 3406 DPRINT("RGetServiceKeyNameW() called\n"); 3407 DPRINT("hSCManager = %p\n", hSCManager); 3408 DPRINT("lpDisplayName: %S\n", lpDisplayName); 3409 DPRINT("lpServiceName: %p\n", lpServiceName); 3410 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); 3411 3412 #if 0 3413 hManager = (PMANAGER_HANDLE)hSCManager; 3414 if (hManager->Handle.Tag != MANAGER_TAG) 3415 { 3416 DPRINT("Invalid manager handle\n"); 3417 return ERROR_INVALID_HANDLE; 3418 } 3419 #endif 3420 3421 /* Get service database entry */ 3422 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName); 3423 if (lpService == NULL) 3424 { 3425 DPRINT("Could not find service\n"); 3426 return ERROR_SERVICE_DOES_NOT_EXIST; 3427 } 3428 3429 dwLength = (DWORD)wcslen(lpService->lpServiceName); 3430 3431 if (*lpcchBuffer > dwLength) 3432 { 3433 if (lpServiceName != NULL) 3434 wcscpy(lpServiceName, lpService->lpServiceName); 3435 3436 dwError = ERROR_SUCCESS; 3437 } 3438 else 3439 { 3440 dwError = ERROR_INSUFFICIENT_BUFFER; 3441 } 3442 3443 *lpcchBuffer = dwLength; 3444 3445 return dwError; 3446 } 3447 3448 3449 /* Function 22 */ 3450 DWORD 3451 WINAPI 3452 RI_ScSetServiceBitsA( 3453 RPC_SERVICE_STATUS_HANDLE hServiceStatus, 3454 DWORD dwServiceBits, 3455 int bSetBitsOn, 3456 int bUpdateImmediately, 3457 char *lpString) 3458 { 3459 if (ScmShutdown) 3460 return ERROR_SHUTDOWN_IN_PROGRESS; 3461 3462 if (lpString != NULL) 3463 return ERROR_INVALID_PARAMETER; 3464 3465 return RI_ScSetServiceBitsW(hServiceStatus, 3466 dwServiceBits, 3467 bSetBitsOn, 3468 bUpdateImmediately, 3469 NULL); 3470 } 3471 3472 3473 /* Function 23 */ 3474 DWORD 3475 WINAPI 3476 RChangeServiceConfigA( 3477 SC_RPC_HANDLE hService, 3478 DWORD dwServiceType, 3479 DWORD dwStartType, 3480 DWORD dwErrorControl, 3481 LPSTR lpBinaryPathName, 3482 LPSTR lpLoadOrderGroup, 3483 LPDWORD lpdwTagId, 3484 LPBYTE lpDependencies, 3485 DWORD dwDependSize, 3486 LPSTR lpServiceStartName, 3487 LPBYTE lpPassword, 3488 DWORD dwPwSize, 3489 LPSTR lpDisplayName) 3490 { 3491 DWORD dwError = ERROR_SUCCESS; 3492 LPWSTR lpBinaryPathNameW = NULL; 3493 LPWSTR lpLoadOrderGroupW = NULL; 3494 LPWSTR lpDependenciesW = NULL; 3495 LPWSTR lpServiceStartNameW = NULL; 3496 LPWSTR lpDisplayNameW = NULL; 3497 DWORD dwDependenciesLength = 0; 3498 SIZE_T cchLength; 3499 int len; 3500 LPCSTR lpStr; 3501 3502 if (lpBinaryPathName) 3503 { 3504 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0); 3505 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3506 if (!lpBinaryPathNameW) 3507 { 3508 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3509 goto cleanup; 3510 } 3511 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len); 3512 } 3513 3514 if (lpLoadOrderGroup) 3515 { 3516 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0); 3517 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3518 if (!lpLoadOrderGroupW) 3519 { 3520 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3521 goto cleanup; 3522 } 3523 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len); 3524 } 3525 3526 if (lpDependencies) 3527 { 3528 lpStr = (LPCSTR)lpDependencies; 3529 while (*lpStr) 3530 { 3531 cchLength = strlen(lpStr) + 1; 3532 dwDependenciesLength += (DWORD)cchLength; 3533 lpStr = lpStr + cchLength; 3534 } 3535 dwDependenciesLength++; 3536 3537 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR)); 3538 if (!lpDependenciesW) 3539 { 3540 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3541 goto cleanup; 3542 } 3543 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength); 3544 } 3545 3546 if (lpServiceStartName) 3547 { 3548 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0); 3549 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3550 if (!lpServiceStartNameW) 3551 { 3552 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3553 goto cleanup; 3554 } 3555 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len); 3556 } 3557 3558 if (lpDisplayName) 3559 { 3560 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0); 3561 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3562 if (!lpDisplayNameW) 3563 { 3564 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3565 goto cleanup; 3566 } 3567 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len); 3568 } 3569 3570 dwError = RChangeServiceConfigW(hService, 3571 dwServiceType, 3572 dwStartType, 3573 dwErrorControl, 3574 lpBinaryPathNameW, 3575 lpLoadOrderGroupW, 3576 lpdwTagId, 3577 (LPBYTE)lpDependenciesW, 3578 dwDependenciesLength, 3579 lpServiceStartNameW, 3580 lpPassword, 3581 dwPwSize, 3582 lpDisplayNameW); 3583 3584 cleanup: 3585 if (lpBinaryPathNameW != NULL) 3586 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); 3587 3588 if (lpLoadOrderGroupW != NULL) 3589 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); 3590 3591 if (lpDependenciesW != NULL) 3592 HeapFree(GetProcessHeap(), 0, lpDependenciesW); 3593 3594 if (lpServiceStartNameW != NULL) 3595 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW); 3596 3597 if (lpDisplayNameW != NULL) 3598 HeapFree(GetProcessHeap(), 0, lpDisplayNameW); 3599 3600 return dwError; 3601 } 3602 3603 3604 /* Function 24 */ 3605 DWORD 3606 WINAPI 3607 RCreateServiceA( 3608 SC_RPC_HANDLE hSCManager, 3609 LPSTR lpServiceName, 3610 LPSTR lpDisplayName, 3611 DWORD dwDesiredAccess, 3612 DWORD dwServiceType, 3613 DWORD dwStartType, 3614 DWORD dwErrorControl, 3615 LPSTR lpBinaryPathName, 3616 LPSTR lpLoadOrderGroup, 3617 LPDWORD lpdwTagId, 3618 LPBYTE lpDependencies, 3619 DWORD dwDependSize, 3620 LPSTR lpServiceStartName, 3621 LPBYTE lpPassword, 3622 DWORD dwPwSize, 3623 LPSC_RPC_HANDLE lpServiceHandle) 3624 { 3625 DWORD dwError = ERROR_SUCCESS; 3626 LPWSTR lpServiceNameW = NULL; 3627 LPWSTR lpDisplayNameW = NULL; 3628 LPWSTR lpBinaryPathNameW = NULL; 3629 LPWSTR lpLoadOrderGroupW = NULL; 3630 LPWSTR lpDependenciesW = NULL; 3631 LPWSTR lpServiceStartNameW = NULL; 3632 DWORD dwDependenciesLength = 0; 3633 SIZE_T cchLength; 3634 int len; 3635 LPCSTR lpStr; 3636 3637 if (lpServiceName) 3638 { 3639 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0); 3640 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3641 if (!lpServiceNameW) 3642 { 3643 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3644 goto cleanup; 3645 } 3646 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len); 3647 } 3648 3649 if (lpDisplayName) 3650 { 3651 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0); 3652 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3653 if (!lpDisplayNameW) 3654 { 3655 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3656 goto cleanup; 3657 } 3658 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len); 3659 } 3660 3661 if (lpBinaryPathName) 3662 { 3663 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0); 3664 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3665 if (!lpBinaryPathNameW) 3666 { 3667 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3668 goto cleanup; 3669 } 3670 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len); 3671 } 3672 3673 if (lpLoadOrderGroup) 3674 { 3675 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0); 3676 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3677 if (!lpLoadOrderGroupW) 3678 { 3679 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3680 goto cleanup; 3681 } 3682 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len); 3683 } 3684 3685 if (lpDependencies) 3686 { 3687 lpStr = (LPCSTR)lpDependencies; 3688 while (*lpStr) 3689 { 3690 cchLength = strlen(lpStr) + 1; 3691 dwDependenciesLength += (DWORD)cchLength; 3692 lpStr = lpStr + cchLength; 3693 } 3694 dwDependenciesLength++; 3695 3696 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR)); 3697 if (!lpDependenciesW) 3698 { 3699 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3700 goto cleanup; 3701 } 3702 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength); 3703 } 3704 3705 if (lpServiceStartName) 3706 { 3707 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0); 3708 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR)); 3709 if (!lpServiceStartNameW) 3710 { 3711 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 3712 goto cleanup; 3713 } 3714 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len); 3715 } 3716 3717 dwError = RCreateServiceW(hSCManager, 3718 lpServiceNameW, 3719 lpDisplayNameW, 3720 dwDesiredAccess, 3721 dwServiceType, 3722 dwStartType, 3723 dwErrorControl, 3724 lpBinaryPathNameW, 3725 lpLoadOrderGroupW, 3726 lpdwTagId, 3727 (LPBYTE)lpDependenciesW, 3728 dwDependenciesLength, 3729 lpServiceStartNameW, 3730 lpPassword, 3731 dwPwSize, 3732 lpServiceHandle); 3733 3734 cleanup: 3735 if (lpServiceNameW !=NULL) 3736 HeapFree(GetProcessHeap(), 0, lpServiceNameW); 3737 3738 if (lpDisplayNameW != NULL) 3739 HeapFree(GetProcessHeap(), 0, lpDisplayNameW); 3740 3741 if (lpBinaryPathNameW != NULL) 3742 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW); 3743 3744 if (lpLoadOrderGroupW != NULL) 3745 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW); 3746 3747 if (lpDependenciesW != NULL) 3748 HeapFree(GetProcessHeap(), 0, lpDependenciesW); 3749 3750 if (lpServiceStartNameW != NULL) 3751 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW); 3752 3753 return dwError; 3754 } 3755 3756 3757 /* Function 25 */ 3758 DWORD 3759 WINAPI 3760 REnumDependentServicesA( 3761 SC_RPC_HANDLE hService, 3762 DWORD dwServiceState, 3763 LPBYTE lpServices, 3764 DWORD cbBufSize, 3765 LPBOUNDED_DWORD_256K pcbBytesNeeded, 3766 LPBOUNDED_DWORD_256K lpServicesReturned) 3767 { 3768 DWORD dwError = ERROR_SUCCESS; 3769 DWORD dwServicesReturned = 0; 3770 DWORD dwServiceCount; 3771 HKEY hServicesKey = NULL; 3772 PSERVICE_HANDLE hSvc; 3773 PSERVICE lpService = NULL; 3774 PSERVICE *lpServicesArray = NULL; 3775 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL; 3776 LPSTR lpStr; 3777 3778 *pcbBytesNeeded = 0; 3779 *lpServicesReturned = 0; 3780 3781 DPRINT("REnumDependentServicesA() called\n"); 3782 3783 hSvc = ScmGetServiceFromHandle(hService); 3784 if (hSvc == NULL) 3785 { 3786 DPRINT1("Invalid service handle\n"); 3787 return ERROR_INVALID_HANDLE; 3788 } 3789 3790 lpService = hSvc->ServiceEntry; 3791 3792 /* Check access rights */ 3793 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 3794 SC_MANAGER_ENUMERATE_SERVICE)) 3795 { 3796 DPRINT("Insufficient access rights! 0x%lx\n", 3797 hSvc->Handle.DesiredAccess); 3798 return ERROR_ACCESS_DENIED; 3799 } 3800 3801 /* Open the Services Reg key */ 3802 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 3803 L"System\\CurrentControlSet\\Services", 3804 0, 3805 KEY_READ, 3806 &hServicesKey); 3807 3808 if (dwError != ERROR_SUCCESS) 3809 return dwError; 3810 3811 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for 3812 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded 3813 are the same for both. Verified in WINXP. */ 3814 3815 /* First determine the bytes needed and get the number of dependent services*/ 3816 dwError = Int_EnumDependentServicesW(hServicesKey, 3817 lpService, 3818 dwServiceState, 3819 NULL, 3820 pcbBytesNeeded, 3821 &dwServicesReturned); 3822 if (dwError != ERROR_SUCCESS) 3823 goto Done; 3824 3825 /* If buffer size is less than the bytes needed or pointer is null*/ 3826 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded)) 3827 { 3828 dwError = ERROR_MORE_DATA; 3829 goto Done; 3830 } 3831 3832 /* Allocate memory for array of service pointers */ 3833 lpServicesArray = HeapAlloc(GetProcessHeap(), 3834 HEAP_ZERO_MEMORY, 3835 (dwServicesReturned + 1) * sizeof(PSERVICE)); 3836 if (!lpServicesArray) 3837 { 3838 DPRINT("Could not allocate buffer\n"); 3839 dwError = ERROR_NOT_ENOUGH_MEMORY; 3840 goto Done; 3841 } 3842 3843 dwServicesReturned = 0; 3844 *pcbBytesNeeded = 0; 3845 3846 dwError = Int_EnumDependentServicesW(hServicesKey, 3847 lpService, 3848 dwServiceState, 3849 lpServicesArray, 3850 pcbBytesNeeded, 3851 &dwServicesReturned); 3852 if (dwError != ERROR_SUCCESS) 3853 { 3854 goto Done; 3855 } 3856 3857 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices; 3858 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA))); 3859 3860 /* Copy EnumDepenedentService to Buffer */ 3861 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++) 3862 { 3863 lpService = lpServicesArray[dwServiceCount]; 3864 3865 /* Copy the status info */ 3866 memcpy(&lpServicesPtr->ServiceStatus, 3867 &lpService->Status, 3868 sizeof(SERVICE_STATUS)); 3869 3870 /* Copy display name */ 3871 WideCharToMultiByte(CP_ACP, 3872 0, 3873 lpService->lpDisplayName, 3874 -1, 3875 lpStr, 3876 (int)wcslen(lpService->lpDisplayName), 3877 0, 3878 0); 3879 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); 3880 lpStr += strlen(lpStr) + 1; 3881 3882 /* Copy service name */ 3883 WideCharToMultiByte(CP_ACP, 3884 0, 3885 lpService->lpServiceName, 3886 -1, 3887 lpStr, 3888 (int)wcslen(lpService->lpServiceName), 3889 0, 3890 0); 3891 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices); 3892 lpStr += strlen(lpStr) + 1; 3893 3894 lpServicesPtr++; 3895 } 3896 3897 *lpServicesReturned = dwServicesReturned; 3898 3899 Done: 3900 if (lpServicesArray) 3901 HeapFree(GetProcessHeap(), 0, lpServicesArray); 3902 3903 RegCloseKey(hServicesKey); 3904 3905 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError); 3906 3907 return dwError; 3908 } 3909 3910 3911 /* Function 26 */ 3912 DWORD 3913 WINAPI 3914 REnumServicesStatusA( 3915 SC_RPC_HANDLE hSCManager, 3916 DWORD dwServiceType, 3917 DWORD dwServiceState, 3918 LPBYTE lpBuffer, 3919 DWORD dwBufSize, 3920 LPBOUNDED_DWORD_256K pcbBytesNeeded, 3921 LPBOUNDED_DWORD_256K lpServicesReturned, 3922 LPBOUNDED_DWORD_256K lpResumeHandle) 3923 { 3924 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL; 3925 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW; 3926 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL; 3927 LPWSTR lpStringPtrW; 3928 LPSTR lpStringPtrA; 3929 DWORD dwError; 3930 DWORD dwServiceCount; 3931 3932 DPRINT("REnumServicesStatusA() called\n"); 3933 3934 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL) 3935 { 3936 return ERROR_INVALID_ADDRESS; 3937 } 3938 3939 if ((dwBufSize > 0) && (lpBuffer)) 3940 { 3941 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize); 3942 if (!lpStatusPtrW) 3943 { 3944 DPRINT("Failed to allocate buffer\n"); 3945 return ERROR_NOT_ENOUGH_MEMORY; 3946 } 3947 } 3948 3949 dwError = REnumServicesStatusW(hSCManager, 3950 dwServiceType, 3951 dwServiceState, 3952 (LPBYTE)lpStatusPtrW, 3953 dwBufSize, 3954 pcbBytesNeeded, 3955 lpServicesReturned, 3956 lpResumeHandle); 3957 3958 /* if no services were returned then we are Done */ 3959 if (*lpServicesReturned == 0) 3960 goto Done; 3961 3962 lpStatusPtrIncrW = lpStatusPtrW; 3963 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer; 3964 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer + 3965 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA)); 3966 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + 3967 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW)); 3968 3969 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++) 3970 { 3971 /* Copy the service name */ 3972 WideCharToMultiByte(CP_ACP, 3973 0, 3974 lpStringPtrW, 3975 -1, 3976 lpStringPtrA, 3977 (int)wcslen(lpStringPtrW), 3978 0, 3979 0); 3980 3981 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); 3982 lpStringPtrA += wcslen(lpStringPtrW) + 1; 3983 lpStringPtrW += wcslen(lpStringPtrW) + 1; 3984 3985 /* Copy the display name */ 3986 WideCharToMultiByte(CP_ACP, 3987 0, 3988 lpStringPtrW, 3989 -1, 3990 lpStringPtrA, 3991 (int)wcslen(lpStringPtrW), 3992 0, 3993 0); 3994 3995 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); 3996 lpStringPtrA += wcslen(lpStringPtrW) + 1; 3997 lpStringPtrW += wcslen(lpStringPtrW) + 1; 3998 3999 /* Copy the status information */ 4000 memcpy(&lpStatusPtrA->ServiceStatus, 4001 &lpStatusPtrIncrW->ServiceStatus, 4002 sizeof(SERVICE_STATUS)); 4003 4004 lpStatusPtrIncrW++; 4005 lpStatusPtrA++; 4006 } 4007 4008 Done: 4009 if (lpStatusPtrW) 4010 HeapFree(GetProcessHeap(), 0, lpStatusPtrW); 4011 4012 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError); 4013 4014 return dwError; 4015 } 4016 4017 4018 /* Function 27 */ 4019 DWORD 4020 WINAPI 4021 ROpenSCManagerA( 4022 LPSTR lpMachineName, 4023 LPSTR lpDatabaseName, 4024 DWORD dwDesiredAccess, 4025 LPSC_RPC_HANDLE lpScHandle) 4026 { 4027 UNICODE_STRING MachineName; 4028 UNICODE_STRING DatabaseName; 4029 DWORD dwError; 4030 4031 DPRINT("ROpenSCManagerA() called\n"); 4032 4033 if (lpMachineName) 4034 RtlCreateUnicodeStringFromAsciiz(&MachineName, 4035 lpMachineName); 4036 4037 if (lpDatabaseName) 4038 RtlCreateUnicodeStringFromAsciiz(&DatabaseName, 4039 lpDatabaseName); 4040 4041 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL, 4042 lpDatabaseName ? DatabaseName.Buffer : NULL, 4043 dwDesiredAccess, 4044 lpScHandle); 4045 4046 if (lpMachineName) 4047 RtlFreeUnicodeString(&MachineName); 4048 4049 if (lpDatabaseName) 4050 RtlFreeUnicodeString(&DatabaseName); 4051 4052 return dwError; 4053 } 4054 4055 4056 /* Function 28 */ 4057 DWORD 4058 WINAPI 4059 ROpenServiceA( 4060 SC_RPC_HANDLE hSCManager, 4061 LPSTR lpServiceName, 4062 DWORD dwDesiredAccess, 4063 LPSC_RPC_HANDLE lpServiceHandle) 4064 { 4065 UNICODE_STRING ServiceName; 4066 DWORD dwError; 4067 4068 DPRINT("ROpenServiceA() called\n"); 4069 4070 if (lpServiceName) 4071 RtlCreateUnicodeStringFromAsciiz(&ServiceName, 4072 lpServiceName); 4073 4074 dwError = ROpenServiceW(hSCManager, 4075 lpServiceName ? ServiceName.Buffer : NULL, 4076 dwDesiredAccess, 4077 lpServiceHandle); 4078 4079 if (lpServiceName) 4080 RtlFreeUnicodeString(&ServiceName); 4081 4082 return dwError; 4083 } 4084 4085 4086 /* Function 29 */ 4087 DWORD 4088 WINAPI 4089 RQueryServiceConfigA( 4090 SC_RPC_HANDLE hService, 4091 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig, 4092 DWORD cbBufSize, 4093 LPBOUNDED_DWORD_8K pcbBytesNeeded) 4094 { 4095 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf; 4096 DWORD dwError = ERROR_SUCCESS; 4097 PSERVICE_HANDLE hSvc; 4098 PSERVICE lpService = NULL; 4099 HKEY hServiceKey = NULL; 4100 LPWSTR lpImagePath = NULL; 4101 LPWSTR lpServiceStartName = NULL; 4102 LPWSTR lpDependencies = NULL; 4103 DWORD dwDependenciesLength = 0; 4104 DWORD dwRequiredSize; 4105 LPSTR lpStr; 4106 4107 DPRINT("RQueryServiceConfigA() called\n"); 4108 4109 if (ScmShutdown) 4110 return ERROR_SHUTDOWN_IN_PROGRESS; 4111 4112 hSvc = ScmGetServiceFromHandle(hService); 4113 if (hSvc == NULL) 4114 { 4115 DPRINT1("Invalid service handle\n"); 4116 return ERROR_INVALID_HANDLE; 4117 } 4118 4119 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 4120 SERVICE_QUERY_CONFIG)) 4121 { 4122 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 4123 return ERROR_ACCESS_DENIED; 4124 } 4125 4126 lpService = hSvc->ServiceEntry; 4127 if (lpService == NULL) 4128 { 4129 DPRINT("lpService == NULL\n"); 4130 return ERROR_INVALID_HANDLE; 4131 } 4132 4133 /* Lock the service database shared */ 4134 ScmLockDatabaseShared(); 4135 4136 dwError = ScmOpenServiceKey(lpService->lpServiceName, 4137 KEY_READ, 4138 &hServiceKey); 4139 if (dwError != ERROR_SUCCESS) 4140 goto Done; 4141 4142 /* Read the image path */ 4143 dwError = ScmReadString(hServiceKey, 4144 L"ImagePath", 4145 &lpImagePath); 4146 if (dwError != ERROR_SUCCESS) 4147 goto Done; 4148 4149 /* Read the service start name */ 4150 ScmReadString(hServiceKey, 4151 L"ObjectName", 4152 &lpServiceStartName); 4153 4154 /* Read the dependencies */ 4155 ScmReadDependencies(hServiceKey, 4156 &lpDependencies, 4157 &dwDependenciesLength); 4158 4159 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGA); 4160 4161 if (lpImagePath != NULL) 4162 dwRequiredSize += (DWORD)(wcslen(lpImagePath) + 1); 4163 else 4164 dwRequiredSize += 2 * sizeof(CHAR); 4165 4166 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL)) 4167 dwRequiredSize += (DWORD)(wcslen(lpService->lpGroup->lpGroupName) + 1); 4168 else 4169 dwRequiredSize += 2 * sizeof(CHAR); 4170 4171 /* Add Dependencies length */ 4172 if (lpDependencies != NULL) 4173 dwRequiredSize += dwDependenciesLength; 4174 else 4175 dwRequiredSize += 2 * sizeof(CHAR); 4176 4177 if (lpServiceStartName != NULL) 4178 dwRequiredSize += (DWORD)(wcslen(lpServiceStartName) + 1); 4179 else 4180 dwRequiredSize += 2 * sizeof(CHAR); 4181 4182 if (lpService->lpDisplayName != NULL) 4183 dwRequiredSize += (DWORD)(wcslen(lpService->lpDisplayName) + 1); 4184 else 4185 dwRequiredSize += 2 * sizeof(CHAR); 4186 4187 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize) 4188 { 4189 dwError = ERROR_INSUFFICIENT_BUFFER; 4190 } 4191 else 4192 { 4193 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType; 4194 lpServiceConfig->dwStartType = lpService->dwStartType; 4195 lpServiceConfig->dwErrorControl = lpService->dwErrorControl; 4196 lpServiceConfig->dwTagId = lpService->dwTag; 4197 4198 lpStr = (LPSTR)(lpServiceConfig + 1); 4199 4200 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings. 4201 Verified in WINXP */ 4202 4203 if (lpImagePath) 4204 { 4205 WideCharToMultiByte(CP_ACP, 4206 0, 4207 lpImagePath, 4208 -1, 4209 lpStr, 4210 (int)(wcslen(lpImagePath) + 1), 4211 0, 4212 0); 4213 } 4214 else 4215 { 4216 *lpStr = 0; 4217 } 4218 4219 lpServiceConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 4220 lpStr += (strlen((LPSTR)lpStr) + 1); 4221 4222 if (lpService->lpGroup && lpService->lpGroup->lpGroupName) 4223 { 4224 WideCharToMultiByte(CP_ACP, 4225 0, 4226 lpService->lpGroup->lpGroupName, 4227 -1, 4228 lpStr, 4229 (int)(wcslen(lpService->lpGroup->lpGroupName) + 1), 4230 0, 4231 0); 4232 } 4233 else 4234 { 4235 *lpStr = 0; 4236 } 4237 4238 lpServiceConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 4239 lpStr += (strlen(lpStr) + 1); 4240 4241 /* Append Dependencies */ 4242 if (lpDependencies) 4243 { 4244 WideCharToMultiByte(CP_ACP, 4245 0, 4246 lpDependencies, 4247 dwDependenciesLength, 4248 lpStr, 4249 dwDependenciesLength, 4250 0, 4251 0); 4252 } 4253 else 4254 { 4255 *lpStr = 0; 4256 } 4257 4258 lpServiceConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 4259 if (lpDependencies) 4260 lpStr += dwDependenciesLength; 4261 else 4262 lpStr += (strlen(lpStr) + 1); 4263 4264 if (lpServiceStartName) 4265 { 4266 WideCharToMultiByte(CP_ACP, 4267 0, 4268 lpServiceStartName, 4269 -1, 4270 lpStr, 4271 (int)(wcslen(lpServiceStartName) + 1), 4272 0, 4273 0); 4274 } 4275 else 4276 { 4277 *lpStr = 0; 4278 } 4279 4280 lpServiceConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 4281 lpStr += (strlen(lpStr) + 1); 4282 4283 if (lpService->lpDisplayName) 4284 { 4285 WideCharToMultiByte(CP_ACP, 4286 0, 4287 lpService->lpDisplayName, 4288 -1, 4289 lpStr, 4290 (int)(wcslen(lpService->lpDisplayName) + 1), 4291 0, 4292 0); 4293 } 4294 else 4295 { 4296 *lpStr = 0; 4297 } 4298 4299 lpServiceConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig); 4300 } 4301 4302 if (pcbBytesNeeded != NULL) 4303 *pcbBytesNeeded = dwRequiredSize; 4304 4305 Done: 4306 /* Unlock the service database */ 4307 ScmUnlockDatabase(); 4308 4309 if (lpImagePath != NULL) 4310 HeapFree(GetProcessHeap(), 0, lpImagePath); 4311 4312 if (lpServiceStartName != NULL) 4313 HeapFree(GetProcessHeap(), 0, lpServiceStartName); 4314 4315 if (lpDependencies != NULL) 4316 HeapFree(GetProcessHeap(), 0, lpDependencies); 4317 4318 if (hServiceKey != NULL) 4319 RegCloseKey(hServiceKey); 4320 4321 DPRINT("RQueryServiceConfigA() done\n"); 4322 4323 return dwError; 4324 } 4325 4326 4327 /* Function 30 */ 4328 DWORD 4329 WINAPI 4330 RQueryServiceLockStatusA( 4331 SC_RPC_HANDLE hSCManager, 4332 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus, 4333 DWORD cbBufSize, 4334 LPBOUNDED_DWORD_4K pcbBytesNeeded) 4335 { 4336 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSA)lpBuf; 4337 PMANAGER_HANDLE hMgr; 4338 DWORD dwRequiredSize; 4339 4340 if (!lpLockStatus || !pcbBytesNeeded) 4341 return ERROR_INVALID_PARAMETER; 4342 4343 hMgr = ScmGetServiceManagerFromHandle(hSCManager); 4344 if (hMgr == NULL) 4345 { 4346 DPRINT1("Invalid service manager handle\n"); 4347 return ERROR_INVALID_HANDLE; 4348 } 4349 4350 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess, 4351 SC_MANAGER_QUERY_LOCK_STATUS)) 4352 { 4353 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess); 4354 return ERROR_ACCESS_DENIED; 4355 } 4356 4357 /* FIXME: we need to compute instead the real length of the owner name */ 4358 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSA) + sizeof(CHAR); 4359 *pcbBytesNeeded = dwRequiredSize; 4360 4361 if (cbBufSize < dwRequiredSize) 4362 return ERROR_INSUFFICIENT_BUFFER; 4363 4364 ScmQueryServiceLockStatusA(lpLockStatus); 4365 4366 return ERROR_SUCCESS; 4367 } 4368 4369 4370 /* Function 31 */ 4371 DWORD 4372 WINAPI 4373 RStartServiceA( 4374 SC_RPC_HANDLE hService, 4375 DWORD argc, 4376 LPSTRING_PTRSA argv) 4377 { 4378 DWORD dwError = ERROR_SUCCESS; 4379 PSERVICE_HANDLE hSvc; 4380 PSERVICE lpService = NULL; 4381 PWSTR* pVector = NULL; 4382 DWORD i; 4383 DWORD dwLength; 4384 4385 DPRINT("RStartServiceA() called\n"); 4386 4387 if (ScmShutdown) 4388 return ERROR_SHUTDOWN_IN_PROGRESS; 4389 4390 hSvc = ScmGetServiceFromHandle(hService); 4391 if (hSvc == NULL) 4392 { 4393 DPRINT1("Invalid service handle\n"); 4394 return ERROR_INVALID_HANDLE; 4395 } 4396 4397 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 4398 SERVICE_START)) 4399 { 4400 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 4401 return ERROR_ACCESS_DENIED; 4402 } 4403 4404 lpService = hSvc->ServiceEntry; 4405 if (lpService == NULL) 4406 { 4407 DPRINT("lpService == NULL\n"); 4408 return ERROR_INVALID_HANDLE; 4409 } 4410 4411 if (lpService->dwStartType == SERVICE_DISABLED) 4412 return ERROR_SERVICE_DISABLED; 4413 4414 if (lpService->bDeleted) 4415 return ERROR_SERVICE_MARKED_FOR_DELETE; 4416 4417 /* Build a Unicode argument vector */ 4418 if (argc > 0) 4419 { 4420 pVector = HeapAlloc(GetProcessHeap(), 4421 HEAP_ZERO_MEMORY, 4422 argc * sizeof(PWSTR)); 4423 if (!pVector) 4424 return ERROR_NOT_ENOUGH_MEMORY; 4425 4426 for (i = 0; i < argc; i++) 4427 { 4428 dwLength = MultiByteToWideChar(CP_ACP, 4429 0, 4430 argv[i].StringPtr, 4431 -1, 4432 NULL, 4433 0); 4434 4435 pVector[i] = HeapAlloc(GetProcessHeap(), 4436 HEAP_ZERO_MEMORY, 4437 dwLength * sizeof(WCHAR)); 4438 if (!pVector[i]) 4439 { 4440 dwError = ERROR_NOT_ENOUGH_MEMORY; 4441 goto done; 4442 } 4443 4444 MultiByteToWideChar(CP_ACP, 4445 0, 4446 argv[i].StringPtr, 4447 -1, 4448 pVector[i], 4449 dwLength); 4450 } 4451 } 4452 4453 /* Start the service */ 4454 dwError = ScmStartService(lpService, argc, (PCWSTR*)pVector); 4455 4456 done: 4457 /* Free the Unicode argument vector */ 4458 if (pVector) 4459 { 4460 for (i = 0; i < argc; i++) 4461 { 4462 if (pVector[i]) 4463 HeapFree(GetProcessHeap(), 0, pVector[i]); 4464 } 4465 HeapFree(GetProcessHeap(), 0, pVector); 4466 } 4467 4468 return dwError; 4469 } 4470 4471 4472 /* Function 32 */ 4473 DWORD 4474 WINAPI 4475 RGetServiceDisplayNameA( 4476 SC_RPC_HANDLE hSCManager, 4477 LPCSTR lpServiceName, 4478 LPSTR lpDisplayName, 4479 LPBOUNDED_DWORD_4K lpcchBuffer) 4480 { 4481 // PMANAGER_HANDLE hManager; 4482 PSERVICE lpService = NULL; 4483 LPCWSTR lpSvcDisplayName; 4484 LPWSTR lpServiceNameW; 4485 DWORD dwLength; 4486 4487 DPRINT("RGetServiceDisplayNameA() called\n"); 4488 DPRINT("hSCManager = %p\n", hSCManager); 4489 DPRINT("lpServiceName: %s\n", lpServiceName); 4490 DPRINT("lpDisplayName: %p\n", lpDisplayName); 4491 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); 4492 4493 #if 0 4494 hManager = (PMANAGER_HANDLE)hSCManager; 4495 if (hManager->Handle.Tag != MANAGER_TAG) 4496 { 4497 DPRINT("Invalid manager handle\n"); 4498 return ERROR_INVALID_HANDLE; 4499 } 4500 #endif 4501 4502 /* Get service database entry */ 4503 if (lpServiceName != NULL) 4504 { 4505 dwLength = (DWORD)(strlen(lpServiceName) + 1); 4506 lpServiceNameW = HeapAlloc(GetProcessHeap(), 4507 HEAP_ZERO_MEMORY, 4508 dwLength * sizeof(WCHAR)); 4509 if (!lpServiceNameW) 4510 return ERROR_NOT_ENOUGH_MEMORY; 4511 4512 MultiByteToWideChar(CP_ACP, 4513 0, 4514 lpServiceName, 4515 -1, 4516 lpServiceNameW, 4517 dwLength); 4518 4519 lpService = ScmGetServiceEntryByName(lpServiceNameW); 4520 4521 HeapFree(GetProcessHeap(), 0, lpServiceNameW); 4522 } 4523 4524 if (lpService == NULL) 4525 { 4526 DPRINT("Could not find service\n"); 4527 return ERROR_SERVICE_DOES_NOT_EXIST; 4528 } 4529 4530 if (lpService->lpDisplayName) 4531 lpSvcDisplayName = lpService->lpDisplayName; 4532 else 4533 lpSvcDisplayName = lpService->lpServiceName; 4534 4535 /* 4536 * NOTE: On Windows the comparison on *lpcchBuffer is made against 4537 * the number of (wide) characters of the UNICODE display name, and 4538 * not against the number of bytes needed to store the ANSI string. 4539 */ 4540 dwLength = (DWORD)wcslen(lpSvcDisplayName); 4541 4542 if (*lpcchBuffer > dwLength) 4543 { 4544 if (lpDisplayName != NULL && 4545 WideCharToMultiByte(CP_ACP, 4546 0, 4547 lpSvcDisplayName, 4548 -1, 4549 lpDisplayName, 4550 (int)*lpcchBuffer, 4551 NULL, 4552 NULL) == 0) 4553 { 4554 /* 4555 * But then, if *lpcchBuffer was greater than the number of 4556 * (wide) characters of the UNICODE display name, yet smaller 4557 * than the number of bytes needed due to the possible presence 4558 * of DBCS characters, the *exact* number of bytes is returned 4559 * (without the NULL terminator). 4560 */ 4561 dwLength = (DWORD)WideCharToMultiByte(CP_ACP, 4562 0, 4563 lpSvcDisplayName, 4564 (int)dwLength, 4565 NULL, 4566 0, 4567 NULL, 4568 NULL); 4569 *lpDisplayName = 0; 4570 *lpcchBuffer = dwLength; 4571 return ERROR_INSUFFICIENT_BUFFER; 4572 } 4573 4574 /* 4575 * NOTE: On Windows, RGetServiceDisplayNameA() does not update 4576 * *lpcchBuffer on success, contrary to RGetServiceDisplayNameW(). 4577 */ 4578 return ERROR_SUCCESS; 4579 } 4580 else 4581 { 4582 /* 4583 * NOTE: On Windows, if *lpcchBuffer is smaller than the number of 4584 * (wide) characters of the UNICODE display name, only an upper 4585 * estimation is returned by doubling the string length, to account 4586 * for the presence of any possible DBCS characters. 4587 */ 4588 *lpcchBuffer = dwLength * sizeof(WCHAR); 4589 return ERROR_INSUFFICIENT_BUFFER; 4590 } 4591 } 4592 4593 4594 /* Function 33 */ 4595 DWORD 4596 WINAPI 4597 RGetServiceKeyNameA( 4598 SC_RPC_HANDLE hSCManager, 4599 LPCSTR lpDisplayName, 4600 LPSTR lpServiceName, 4601 LPBOUNDED_DWORD_4K lpcchBuffer) 4602 { 4603 // PMANAGER_HANDLE hManager; 4604 PSERVICE lpService; 4605 LPWSTR lpDisplayNameW; 4606 DWORD dwLength; 4607 4608 DPRINT("RGetServiceKeyNameA() called\n"); 4609 DPRINT("hSCManager = %p\n", hSCManager); 4610 DPRINT("lpDisplayName: %s\n", lpDisplayName); 4611 DPRINT("lpServiceName: %p\n", lpServiceName); 4612 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer); 4613 4614 #if 0 4615 hManager = (PMANAGER_HANDLE)hSCManager; 4616 if (hManager->Handle.Tag != MANAGER_TAG) 4617 { 4618 DPRINT("Invalid manager handle\n"); 4619 return ERROR_INVALID_HANDLE; 4620 } 4621 #endif 4622 4623 /* Get service database entry */ 4624 4625 dwLength = (DWORD)(strlen(lpDisplayName) + 1); 4626 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 4627 HEAP_ZERO_MEMORY, 4628 dwLength * sizeof(WCHAR)); 4629 if (!lpDisplayNameW) 4630 return ERROR_NOT_ENOUGH_MEMORY; 4631 4632 MultiByteToWideChar(CP_ACP, 4633 0, 4634 lpDisplayName, 4635 -1, 4636 lpDisplayNameW, 4637 dwLength); 4638 4639 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW); 4640 4641 HeapFree(GetProcessHeap(), 0, lpDisplayNameW); 4642 4643 if (lpService == NULL) 4644 { 4645 DPRINT("Could not find service\n"); 4646 return ERROR_SERVICE_DOES_NOT_EXIST; 4647 } 4648 4649 /* 4650 * NOTE: On Windows the comparison on *lpcchBuffer is made against 4651 * the number of (wide) characters of the UNICODE service name, and 4652 * not against the number of bytes needed to store the ANSI string. 4653 */ 4654 dwLength = (DWORD)wcslen(lpService->lpServiceName); 4655 4656 if (*lpcchBuffer > dwLength) 4657 { 4658 if (lpServiceName != NULL && 4659 WideCharToMultiByte(CP_ACP, 4660 0, 4661 lpService->lpServiceName, 4662 -1, 4663 lpServiceName, 4664 (int)*lpcchBuffer, 4665 NULL, 4666 NULL) == 0) 4667 { 4668 /* 4669 * But then, if *lpcchBuffer was greater than the number of 4670 * (wide) characters of the UNICODE service name, yet smaller 4671 * than the number of bytes needed due to the possible presence 4672 * of DBCS characters, the *exact* number of bytes is returned 4673 * (without the NULL terminator). 4674 */ 4675 dwLength = (DWORD)WideCharToMultiByte(CP_ACP, 4676 0, 4677 lpService->lpServiceName, 4678 (int)dwLength, 4679 NULL, 4680 0, 4681 NULL, 4682 NULL); 4683 *lpServiceName = 0; 4684 *lpcchBuffer = dwLength; 4685 return ERROR_INSUFFICIENT_BUFFER; 4686 } 4687 4688 /* 4689 * NOTE: On Windows, RGetServiceKeyNameA() does not update 4690 * *lpcchBuffer on success, contrary to RGetServiceKeyNameW(). 4691 */ 4692 return ERROR_SUCCESS; 4693 } 4694 else 4695 { 4696 /* 4697 * NOTE: On Windows, if *lpcchBuffer is smaller than the number of 4698 * (wide) characters of the UNICODE service name, only an upper 4699 * estimation is returned by doubling the string length, to account 4700 * for the presence of any possible DBCS characters. 4701 */ 4702 *lpcchBuffer = dwLength * sizeof(WCHAR); 4703 return ERROR_INSUFFICIENT_BUFFER; 4704 } 4705 } 4706 4707 4708 /* Function 34 */ 4709 DWORD 4710 WINAPI 4711 RI_ScGetCurrentGroupStateW( 4712 SC_RPC_HANDLE hSCManager, 4713 LPWSTR lpLoadOrderGroup, 4714 LPDWORD lpState) 4715 { 4716 PMANAGER_HANDLE hManager; 4717 PSERVICE_GROUP pServiceGroup; 4718 DWORD dwError = ERROR_SUCCESS; 4719 4720 DPRINT("RI_ScGetCurrentGroupStateW() called\n"); 4721 4722 if (ScmShutdown) 4723 return ERROR_SHUTDOWN_IN_PROGRESS; 4724 4725 hManager = ScmGetServiceManagerFromHandle(hSCManager); 4726 if (hManager == NULL) 4727 { 4728 DPRINT1("Invalid service manager handle\n"); 4729 return ERROR_INVALID_HANDLE; 4730 } 4731 4732 /* Check for SC_MANAGER_ENUMERATE_SERVICE access right */ 4733 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, 4734 SC_MANAGER_ENUMERATE_SERVICE)) 4735 { 4736 DPRINT("Insufficient access rights! 0x%lx\n", 4737 hManager->Handle.DesiredAccess); 4738 return ERROR_ACCESS_DENIED; 4739 } 4740 4741 /* Lock the service database shared */ 4742 ScmLockDatabaseShared(); 4743 4744 /* Get the group list entry */ 4745 pServiceGroup = ScmGetServiceGroupByName(lpLoadOrderGroup); 4746 if (pServiceGroup == NULL) 4747 { 4748 dwError = ERROR_SERVICE_DOES_NOT_EXIST; 4749 goto done; 4750 } 4751 4752 /* FIXME: Return the group state */ 4753 *lpState = 0; 4754 4755 done: 4756 /* Unlock the service database */ 4757 ScmUnlockDatabase(); 4758 4759 DPRINT("RI_ScGetCurrentGroupStateW() done (Error %lu)\n", dwError); 4760 4761 return dwError; 4762 } 4763 4764 4765 /* Function 35 */ 4766 DWORD 4767 WINAPI 4768 REnumServiceGroupW( 4769 SC_RPC_HANDLE hSCManager, 4770 DWORD dwServiceType, 4771 DWORD dwServiceState, 4772 LPBYTE lpBuffer, 4773 DWORD cbBufSize, 4774 LPBOUNDED_DWORD_256K pcbBytesNeeded, 4775 LPBOUNDED_DWORD_256K lpServicesReturned, 4776 LPBOUNDED_DWORD_256K lpResumeIndex, 4777 LPCWSTR pszGroupName) 4778 { 4779 PMANAGER_HANDLE hManager; 4780 PSERVICE lpService; 4781 DWORD dwError = ERROR_SUCCESS; 4782 PLIST_ENTRY ServiceEntry; 4783 PSERVICE CurrentService; 4784 DWORD dwState; 4785 DWORD dwRequiredSize; 4786 DWORD dwServiceCount; 4787 DWORD dwSize; 4788 DWORD dwLastResumeCount = 0; 4789 LPENUM_SERVICE_STATUSW lpStatusPtr; 4790 LPWSTR lpStringPtr; 4791 4792 DPRINT("REnumServiceGroupW() called\n"); 4793 4794 if (ScmShutdown) 4795 return ERROR_SHUTDOWN_IN_PROGRESS; 4796 4797 hManager = ScmGetServiceManagerFromHandle(hSCManager); 4798 if (hManager == NULL) 4799 { 4800 DPRINT1("Invalid service manager handle\n"); 4801 return ERROR_INVALID_HANDLE; 4802 } 4803 4804 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL) 4805 { 4806 return ERROR_INVALID_ADDRESS; 4807 } 4808 4809 *pcbBytesNeeded = 0; 4810 *lpServicesReturned = 0; 4811 4812 if ((dwServiceType == 0) || 4813 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0)) 4814 { 4815 DPRINT("Invalid Service Type\n"); 4816 return ERROR_INVALID_PARAMETER; 4817 } 4818 4819 if ((dwServiceState == 0) || 4820 ((dwServiceState & ~SERVICE_STATE_ALL) != 0)) 4821 { 4822 DPRINT("Invalid Service State\n"); 4823 return ERROR_INVALID_PARAMETER; 4824 } 4825 4826 /* Check access rights */ 4827 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, 4828 SC_MANAGER_ENUMERATE_SERVICE)) 4829 { 4830 DPRINT("Insufficient access rights! 0x%lx\n", 4831 hManager->Handle.DesiredAccess); 4832 return ERROR_ACCESS_DENIED; 4833 } 4834 4835 if (lpResumeIndex) 4836 dwLastResumeCount = *lpResumeIndex; 4837 4838 /* Lock the service database shared */ 4839 ScmLockDatabaseShared(); 4840 4841 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount); 4842 if (lpService == NULL) 4843 { 4844 dwError = ERROR_SUCCESS; 4845 goto Done; 4846 } 4847 4848 dwRequiredSize = 0; 4849 dwServiceCount = 0; 4850 4851 for (ServiceEntry = &lpService->ServiceListEntry; 4852 ServiceEntry != &ServiceListHead; 4853 ServiceEntry = ServiceEntry->Flink) 4854 { 4855 CurrentService = CONTAINING_RECORD(ServiceEntry, 4856 SERVICE, 4857 ServiceListEntry); 4858 4859 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) 4860 continue; 4861 4862 dwState = SERVICE_ACTIVE; 4863 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) 4864 dwState = SERVICE_INACTIVE; 4865 4866 if ((dwState & dwServiceState) == 0) 4867 continue; 4868 4869 if (pszGroupName) 4870 { 4871 if (*pszGroupName == 0) 4872 { 4873 if (CurrentService->lpGroup != NULL) 4874 continue; 4875 } 4876 else 4877 { 4878 if ((CurrentService->lpGroup == NULL) || 4879 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0) 4880 continue; 4881 } 4882 } 4883 4884 dwSize = sizeof(ENUM_SERVICE_STATUSW) + 4885 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + 4886 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); 4887 4888 if (dwRequiredSize + dwSize > cbBufSize) 4889 { 4890 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName); 4891 break; 4892 } 4893 4894 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName); 4895 dwRequiredSize += dwSize; 4896 dwServiceCount++; 4897 dwLastResumeCount = CurrentService->dwResumeCount; 4898 } 4899 4900 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize); 4901 DPRINT("dwServiceCount: %lu\n", dwServiceCount); 4902 4903 for (; 4904 ServiceEntry != &ServiceListHead; 4905 ServiceEntry = ServiceEntry->Flink) 4906 { 4907 CurrentService = CONTAINING_RECORD(ServiceEntry, 4908 SERVICE, 4909 ServiceListEntry); 4910 4911 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) 4912 continue; 4913 4914 dwState = SERVICE_ACTIVE; 4915 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) 4916 dwState = SERVICE_INACTIVE; 4917 4918 if ((dwState & dwServiceState) == 0) 4919 continue; 4920 4921 if (pszGroupName) 4922 { 4923 if (*pszGroupName == 0) 4924 { 4925 if (CurrentService->lpGroup != NULL) 4926 continue; 4927 } 4928 else 4929 { 4930 if ((CurrentService->lpGroup == NULL) || 4931 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0) 4932 continue; 4933 } 4934 } 4935 4936 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) + 4937 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + 4938 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR))); 4939 4940 dwError = ERROR_MORE_DATA; 4941 } 4942 4943 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize); 4944 4945 if (lpResumeIndex) 4946 *lpResumeIndex = dwLastResumeCount; 4947 4948 *lpServicesReturned = dwServiceCount; 4949 *pcbBytesNeeded = dwRequiredSize; 4950 4951 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer; 4952 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer + 4953 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW)); 4954 4955 dwRequiredSize = 0; 4956 for (ServiceEntry = &lpService->ServiceListEntry; 4957 ServiceEntry != &ServiceListHead; 4958 ServiceEntry = ServiceEntry->Flink) 4959 { 4960 CurrentService = CONTAINING_RECORD(ServiceEntry, 4961 SERVICE, 4962 ServiceListEntry); 4963 4964 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) 4965 continue; 4966 4967 dwState = SERVICE_ACTIVE; 4968 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) 4969 dwState = SERVICE_INACTIVE; 4970 4971 if ((dwState & dwServiceState) == 0) 4972 continue; 4973 4974 if (pszGroupName) 4975 { 4976 if (*pszGroupName == 0) 4977 { 4978 if (CurrentService->lpGroup != NULL) 4979 continue; 4980 } 4981 else 4982 { 4983 if ((CurrentService->lpGroup == NULL) || 4984 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0) 4985 continue; 4986 } 4987 } 4988 4989 dwSize = sizeof(ENUM_SERVICE_STATUSW) + 4990 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + 4991 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); 4992 4993 if (dwRequiredSize + dwSize > cbBufSize) 4994 break; 4995 4996 /* Copy the service name */ 4997 wcscpy(lpStringPtr, CurrentService->lpServiceName); 4998 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); 4999 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1); 5000 5001 /* Copy the display name */ 5002 wcscpy(lpStringPtr, CurrentService->lpDisplayName); 5003 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); 5004 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1); 5005 5006 /* Copy the status information */ 5007 memcpy(&lpStatusPtr->ServiceStatus, 5008 &CurrentService->Status, 5009 sizeof(SERVICE_STATUS)); 5010 5011 lpStatusPtr++; 5012 dwRequiredSize += dwSize; 5013 } 5014 5015 if (dwError == ERROR_SUCCESS) 5016 { 5017 *pcbBytesNeeded = 0; 5018 if (lpResumeIndex) *lpResumeIndex = 0; 5019 } 5020 5021 Done: 5022 /* Unlock the service database */ 5023 ScmUnlockDatabase(); 5024 5025 DPRINT("REnumServiceGroupW() done (Error %lu)\n", dwError); 5026 5027 return dwError; 5028 } 5029 5030 5031 /* Function 36 */ 5032 DWORD 5033 WINAPI 5034 RChangeServiceConfig2A( 5035 SC_RPC_HANDLE hService, 5036 SC_RPC_CONFIG_INFOA Info) 5037 { 5038 SC_RPC_CONFIG_INFOW InfoW = { 0 }; 5039 DWORD dwRet, dwLength; 5040 PVOID ptr = NULL; 5041 5042 DPRINT("RChangeServiceConfig2A() called\n"); 5043 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); 5044 5045 if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) || 5046 (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS)) 5047 { 5048 return ERROR_INVALID_LEVEL; 5049 } 5050 5051 InfoW.dwInfoLevel = Info.dwInfoLevel; 5052 5053 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) 5054 { 5055 LPSERVICE_DESCRIPTIONW lpServiceDescriptionW; 5056 LPSERVICE_DESCRIPTIONA lpServiceDescriptionA; 5057 5058 lpServiceDescriptionA = Info.psd; 5059 5060 if (lpServiceDescriptionA && 5061 lpServiceDescriptionA->lpDescription) 5062 { 5063 dwLength = (DWORD)((strlen(lpServiceDescriptionA->lpDescription) + 1) * sizeof(WCHAR)); 5064 5065 lpServiceDescriptionW = HeapAlloc(GetProcessHeap(), 5066 HEAP_ZERO_MEMORY, 5067 dwLength + sizeof(SERVICE_DESCRIPTIONW)); 5068 if (!lpServiceDescriptionW) 5069 { 5070 return ERROR_NOT_ENOUGH_MEMORY; 5071 } 5072 5073 lpServiceDescriptionW->lpDescription = (LPWSTR)(lpServiceDescriptionW + 1); 5074 5075 MultiByteToWideChar(CP_ACP, 5076 0, 5077 lpServiceDescriptionA->lpDescription, 5078 -1, 5079 lpServiceDescriptionW->lpDescription, 5080 dwLength); 5081 5082 ptr = lpServiceDescriptionW; 5083 InfoW.psd = lpServiceDescriptionW; 5084 } 5085 } 5086 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5087 { 5088 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW; 5089 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA; 5090 DWORD dwRebootLen = 0; 5091 DWORD dwCommandLen = 0; 5092 DWORD dwActionArrayLen = 0; 5093 LPWSTR lpStr = NULL; 5094 5095 lpServiceFailureActionsA = Info.psfa; 5096 5097 if (lpServiceFailureActionsA) 5098 { 5099 /* 5100 * The following code is inspired by the 5101 * SERVICE_CONFIG_FAILURE_ACTIONS case of 5102 * the RQueryServiceConfig2W function. 5103 */ 5104 5105 /* Retrieve the needed length for the two data strings */ 5106 if (lpServiceFailureActionsA->lpRebootMsg) 5107 { 5108 dwRebootLen = (DWORD)((strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR)); 5109 } 5110 if (lpServiceFailureActionsA->lpCommand) 5111 { 5112 dwCommandLen = (DWORD)((strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR)); 5113 } 5114 5115 /* 5116 * Retrieve the size of the lpsaActions array if needed. 5117 * We will copy the lpsaActions array only if there is at 5118 * least one action AND that the original array is valid. 5119 */ 5120 if (lpServiceFailureActionsA->cActions > 0 && lpServiceFailureActionsA->lpsaActions) 5121 { 5122 dwActionArrayLen = lpServiceFailureActionsA->cActions * sizeof(SC_ACTION); 5123 } 5124 5125 /* Compute the total length for the UNICODE structure, including data */ 5126 dwLength = sizeof(SERVICE_FAILURE_ACTIONSW) + 5127 dwActionArrayLen + dwRebootLen + dwCommandLen; 5128 5129 /* Allocate the structure */ 5130 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(), 5131 HEAP_ZERO_MEMORY, 5132 dwLength); 5133 if (!lpServiceFailureActionsW) 5134 { 5135 return ERROR_NOT_ENOUGH_MEMORY; 5136 } 5137 5138 /* Copy the members */ 5139 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod; 5140 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions; 5141 5142 /* Copy the lpsaActions array if needed */ 5143 if (dwActionArrayLen > 0) 5144 { 5145 /* The storage zone is just after the end of the SERVICE_FAILURE_ACTIONSW structure */ 5146 lpServiceFailureActionsW->lpsaActions = (LPSC_ACTION)((ULONG_PTR)(lpServiceFailureActionsW + 1)); 5147 5148 /* dwActionArrayLen == lpServiceFailureActionsW->cActions * sizeof(SC_ACTION) */ 5149 RtlCopyMemory(lpServiceFailureActionsW->lpsaActions, 5150 lpServiceFailureActionsA->lpsaActions, 5151 dwActionArrayLen); 5152 } 5153 else 5154 { 5155 /* No lpsaActions array */ 5156 lpServiceFailureActionsW->lpsaActions = NULL; 5157 } 5158 /* The data strings are stored just after the lpsaActions array */ 5159 lpStr = (LPWSTR)((ULONG_PTR)(lpServiceFailureActionsW + 1) + dwActionArrayLen); 5160 5161 /* 5162 * Convert the data strings to UNICODE 5163 */ 5164 5165 lpServiceFailureActionsW->lpRebootMsg = NULL; 5166 lpServiceFailureActionsW->lpCommand = NULL; 5167 5168 if (dwRebootLen) 5169 { 5170 /* lpRebootMsg points just after the lpsaActions array */ 5171 lpServiceFailureActionsW->lpRebootMsg = lpStr; 5172 5173 MultiByteToWideChar(CP_ACP, 5174 0, 5175 lpServiceFailureActionsA->lpRebootMsg, 5176 -1, 5177 lpServiceFailureActionsW->lpRebootMsg, 5178 dwRebootLen); 5179 5180 lpStr += dwRebootLen / sizeof(WCHAR); 5181 } 5182 5183 if (dwCommandLen) 5184 { 5185 /* lpRebootMsg points just after the lpRebootMsg data string */ 5186 lpServiceFailureActionsW->lpCommand = lpStr; 5187 5188 MultiByteToWideChar(CP_ACP, 5189 0, 5190 lpServiceFailureActionsA->lpCommand, 5191 -1, 5192 lpServiceFailureActionsW->lpCommand, 5193 dwCommandLen); 5194 } 5195 5196 /* Set the pointers */ 5197 ptr = lpServiceFailureActionsW; 5198 InfoW.psfa = lpServiceFailureActionsW; 5199 } 5200 } 5201 5202 dwRet = RChangeServiceConfig2W(hService, InfoW); 5203 5204 HeapFree(GetProcessHeap(), 0, ptr); 5205 5206 return dwRet; 5207 } 5208 5209 5210 static DWORD 5211 ScmSetFailureActions(HKEY hServiceKey, 5212 LPSERVICE_FAILURE_ACTIONSW lpFailureActions) 5213 { 5214 LPSERVICE_FAILURE_ACTIONSW lpReadBuffer = NULL; 5215 LPSERVICE_FAILURE_ACTIONSW lpWriteBuffer = NULL; 5216 DWORD dwRequiredSize = 0; 5217 DWORD dwType = 0; 5218 DWORD dwError; 5219 5220 /* There is nothing to be done if we have no failure actions */ 5221 if (lpFailureActions == NULL) 5222 return ERROR_SUCCESS; 5223 5224 /* 5225 * 1- Retrieve the original value of FailureActions. 5226 */ 5227 5228 /* Query value length */ 5229 dwError = RegQueryValueExW(hServiceKey, 5230 L"FailureActions", 5231 NULL, 5232 &dwType, 5233 NULL, 5234 &dwRequiredSize); 5235 if (dwError != ERROR_SUCCESS && 5236 dwError != ERROR_MORE_DATA && 5237 dwError != ERROR_FILE_NOT_FOUND) 5238 { 5239 return dwError; 5240 } 5241 5242 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize) 5243 : sizeof(SERVICE_FAILURE_ACTIONSW); 5244 5245 /* Initialize the read buffer */ 5246 lpReadBuffer = HeapAlloc(GetProcessHeap(), 5247 HEAP_ZERO_MEMORY, 5248 dwRequiredSize); 5249 if (lpReadBuffer == NULL) 5250 return ERROR_NOT_ENOUGH_MEMORY; 5251 5252 /* Now we can fill the read buffer */ 5253 if (dwError != ERROR_FILE_NOT_FOUND && 5254 dwType == REG_BINARY) 5255 { 5256 dwError = RegQueryValueExW(hServiceKey, 5257 L"FailureActions", 5258 NULL, 5259 NULL, 5260 (LPBYTE)lpReadBuffer, 5261 &dwRequiredSize); 5262 if (dwError != ERROR_SUCCESS && 5263 dwError != ERROR_FILE_NOT_FOUND) 5264 goto done; 5265 5266 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW)) 5267 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW); 5268 } 5269 else 5270 { 5271 /* 5272 * The value of the error doesn't really matter, the only 5273 * important thing is that it must be != ERROR_SUCCESS. 5274 */ 5275 dwError = ERROR_INVALID_DATA; 5276 } 5277 5278 if (dwError == ERROR_SUCCESS) 5279 { 5280 lpReadBuffer->cActions = min(lpReadBuffer->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION)); 5281 lpReadBuffer->lpsaActions = (lpReadBuffer->cActions > 0 ? (LPSC_ACTION)(lpReadBuffer + 1) : NULL); 5282 } 5283 else 5284 { 5285 lpReadBuffer->dwResetPeriod = 0; 5286 lpReadBuffer->cActions = 0; 5287 lpReadBuffer->lpsaActions = NULL; 5288 } 5289 5290 lpReadBuffer->lpRebootMsg = NULL; 5291 lpReadBuffer->lpCommand = NULL; 5292 5293 /* 5294 * 2- Initialize the new value to set. 5295 */ 5296 5297 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW); 5298 5299 if (lpFailureActions->lpsaActions == NULL) 5300 { 5301 /* 5302 * lpFailureActions->cActions is ignored. 5303 * Therefore we use the original values 5304 * of cActions and lpsaActions. 5305 */ 5306 dwRequiredSize += lpReadBuffer->cActions * sizeof(SC_ACTION); 5307 } 5308 else 5309 { 5310 /* 5311 * The reset period and array of failure actions 5312 * are deleted if lpFailureActions->cActions == 0 . 5313 */ 5314 dwRequiredSize += lpFailureActions->cActions * sizeof(SC_ACTION); 5315 } 5316 5317 lpWriteBuffer = HeapAlloc(GetProcessHeap(), 5318 HEAP_ZERO_MEMORY, 5319 dwRequiredSize); 5320 if (lpWriteBuffer == NULL) 5321 { 5322 dwError = ERROR_NOT_ENOUGH_MEMORY; 5323 goto done; 5324 } 5325 5326 /* Clean the pointers as they have no meaning when the structure is stored in the registry */ 5327 lpWriteBuffer->lpRebootMsg = NULL; 5328 lpWriteBuffer->lpCommand = NULL; 5329 lpWriteBuffer->lpsaActions = NULL; 5330 5331 /* Set the members */ 5332 if (lpFailureActions->lpsaActions == NULL) 5333 { 5334 /* 5335 * lpFailureActions->dwResetPeriod and lpFailureActions->cActions are ignored. 5336 * Therefore we use the original values of dwResetPeriod, cActions and lpsaActions. 5337 */ 5338 lpWriteBuffer->dwResetPeriod = lpReadBuffer->dwResetPeriod; 5339 lpWriteBuffer->cActions = lpReadBuffer->cActions; 5340 5341 if (lpReadBuffer->lpsaActions != NULL) 5342 { 5343 memmove(lpWriteBuffer + 1, 5344 lpReadBuffer->lpsaActions, 5345 lpReadBuffer->cActions * sizeof(SC_ACTION)); 5346 } 5347 } 5348 else 5349 { 5350 if (lpFailureActions->cActions > 0) 5351 { 5352 lpWriteBuffer->dwResetPeriod = lpFailureActions->dwResetPeriod; 5353 lpWriteBuffer->cActions = lpFailureActions->cActions; 5354 5355 memmove(lpWriteBuffer + 1, 5356 lpFailureActions->lpsaActions, 5357 lpFailureActions->cActions * sizeof(SC_ACTION)); 5358 } 5359 else 5360 { 5361 /* The reset period and array of failure actions are deleted */ 5362 lpWriteBuffer->dwResetPeriod = 0; 5363 lpWriteBuffer->cActions = 0; 5364 } 5365 } 5366 5367 /* Save the new failure actions into the registry */ 5368 dwError = RegSetValueExW(hServiceKey, 5369 L"FailureActions", 5370 0, 5371 REG_BINARY, 5372 (LPBYTE)lpWriteBuffer, 5373 dwRequiredSize); 5374 5375 /* We modify the strings only in case of success.*/ 5376 if (dwError == ERROR_SUCCESS) 5377 { 5378 /* Modify the Reboot Message value, if specified */ 5379 if (lpFailureActions->lpRebootMsg != NULL) 5380 { 5381 /* If the Reboot Message is "" then we delete it */ 5382 if (*lpFailureActions->lpRebootMsg == 0) 5383 { 5384 DPRINT("Delete Reboot Message value\n"); 5385 RegDeleteValueW(hServiceKey, L"RebootMessage"); 5386 } 5387 else 5388 { 5389 DPRINT("Setting Reboot Message value %S\n", lpFailureActions->lpRebootMsg); 5390 RegSetValueExW(hServiceKey, 5391 L"RebootMessage", 5392 0, 5393 REG_SZ, 5394 (LPBYTE)lpFailureActions->lpRebootMsg, 5395 (DWORD)((wcslen(lpFailureActions->lpRebootMsg) + 1) * sizeof(WCHAR))); 5396 } 5397 } 5398 5399 /* Modify the Failure Command value, if specified */ 5400 if (lpFailureActions->lpCommand != NULL) 5401 { 5402 /* If the FailureCommand string is an empty string, delete the value */ 5403 if (*lpFailureActions->lpCommand == 0) 5404 { 5405 DPRINT("Delete Failure Command value\n"); 5406 RegDeleteValueW(hServiceKey, L"FailureCommand"); 5407 } 5408 else 5409 { 5410 DPRINT("Setting Failure Command value %S\n", lpFailureActions->lpCommand); 5411 RegSetValueExW(hServiceKey, 5412 L"FailureCommand", 5413 0, 5414 REG_SZ, 5415 (LPBYTE)lpFailureActions->lpCommand, 5416 (DWORD)((wcslen(lpFailureActions->lpCommand) + 1) * sizeof(WCHAR))); 5417 } 5418 } 5419 } 5420 5421 done: 5422 if (lpWriteBuffer != NULL) 5423 HeapFree(GetProcessHeap(), 0, lpWriteBuffer); 5424 5425 if (lpReadBuffer != NULL) 5426 HeapFree(GetProcessHeap(), 0, lpReadBuffer); 5427 5428 return dwError; 5429 } 5430 5431 5432 /* Function 37 */ 5433 DWORD 5434 WINAPI 5435 RChangeServiceConfig2W( 5436 SC_RPC_HANDLE hService, 5437 SC_RPC_CONFIG_INFOW Info) 5438 { 5439 DWORD dwError = ERROR_SUCCESS; 5440 PSERVICE_HANDLE hSvc; 5441 PSERVICE lpService = NULL; 5442 HKEY hServiceKey = NULL; 5443 ACCESS_MASK RequiredAccess = SERVICE_CHANGE_CONFIG; 5444 5445 DPRINT("RChangeServiceConfig2W() called\n"); 5446 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel); 5447 5448 if (ScmShutdown) 5449 return ERROR_SHUTDOWN_IN_PROGRESS; 5450 5451 if ((Info.dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) || 5452 (Info.dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS)) 5453 { 5454 return ERROR_INVALID_LEVEL; 5455 } 5456 5457 hSvc = ScmGetServiceFromHandle(hService); 5458 if (hSvc == NULL) 5459 { 5460 DPRINT("Invalid service handle\n"); 5461 return ERROR_INVALID_HANDLE; 5462 } 5463 5464 if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5465 RequiredAccess |= SERVICE_START; 5466 5467 /* Check the access rights */ 5468 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 5469 RequiredAccess)) 5470 { 5471 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 5472 return ERROR_ACCESS_DENIED; 5473 } 5474 5475 if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5476 { 5477 /* FIXME: Check if the caller has the SE_SHUTDOWN_NAME privilege */ 5478 5479 } 5480 5481 lpService = hSvc->ServiceEntry; 5482 if (lpService == NULL) 5483 { 5484 DPRINT("lpService == NULL\n"); 5485 return ERROR_INVALID_HANDLE; 5486 } 5487 5488 /* Failure actions can only be set for Win32 services, not for drivers */ 5489 if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5490 { 5491 if (lpService->Status.dwServiceType & SERVICE_DRIVER) 5492 return ERROR_CANNOT_DETECT_DRIVER_FAILURE; 5493 } 5494 5495 /* Lock the service database exclusively */ 5496 ScmLockDatabaseExclusive(); 5497 5498 if (lpService->bDeleted) 5499 { 5500 DPRINT("Service has already been marked for delete\n"); 5501 dwError = ERROR_SERVICE_MARKED_FOR_DELETE; 5502 goto done; 5503 } 5504 5505 /* Open the service key */ 5506 dwError = ScmOpenServiceKey(lpService->szServiceName, 5507 KEY_READ | KEY_SET_VALUE, 5508 &hServiceKey); 5509 if (dwError != ERROR_SUCCESS) 5510 goto done; 5511 5512 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) 5513 { 5514 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd; 5515 5516 /* Modify the service description, if specified */ 5517 if (lpServiceDescription != NULL && 5518 lpServiceDescription->lpDescription != NULL) 5519 { 5520 /* If the description is "" then we delete it */ 5521 if (*lpServiceDescription->lpDescription == 0) 5522 { 5523 DPRINT("Delete service description\n"); 5524 dwError = RegDeleteValueW(hServiceKey, L"Description"); 5525 5526 if (dwError == ERROR_FILE_NOT_FOUND) 5527 dwError = ERROR_SUCCESS; 5528 } 5529 else 5530 { 5531 DPRINT("Setting service description value %S\n", lpServiceDescription->lpDescription); 5532 dwError = RegSetValueExW(hServiceKey, 5533 L"Description", 5534 0, 5535 REG_SZ, 5536 (LPBYTE)lpServiceDescription->lpDescription, 5537 (DWORD)((wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR))); 5538 } 5539 } 5540 else 5541 { 5542 dwError = ERROR_SUCCESS; 5543 } 5544 } 5545 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5546 { 5547 dwError = ScmSetFailureActions(hServiceKey, 5548 (LPSERVICE_FAILURE_ACTIONSW)Info.psfa); 5549 } 5550 5551 done: 5552 if (hServiceKey != NULL) 5553 RegCloseKey(hServiceKey); 5554 5555 /* Unlock the service database */ 5556 ScmUnlockDatabase(); 5557 5558 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError); 5559 5560 return dwError; 5561 } 5562 5563 5564 /* Function 38 */ 5565 DWORD 5566 WINAPI 5567 RQueryServiceConfig2A( 5568 SC_RPC_HANDLE hService, 5569 DWORD dwInfoLevel, 5570 LPBYTE lpBuffer, 5571 DWORD cbBufSize, 5572 LPBOUNDED_DWORD_8K pcbBytesNeeded) 5573 { 5574 DWORD dwError = ERROR_SUCCESS; 5575 PSERVICE_HANDLE hSvc; 5576 PSERVICE lpService = NULL; 5577 HKEY hServiceKey = NULL; 5578 DWORD dwRequiredSize = 0; 5579 DWORD dwType = 0; 5580 LPWSTR lpDescriptionW = NULL; 5581 LPWSTR lpRebootMessageW = NULL; 5582 LPWSTR lpFailureCommandW = NULL; 5583 5584 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n", 5585 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded); 5586 5587 if (!lpBuffer) 5588 return ERROR_INVALID_ADDRESS; 5589 5590 if (ScmShutdown) 5591 return ERROR_SHUTDOWN_IN_PROGRESS; 5592 5593 if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) || 5594 (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS)) 5595 { 5596 return ERROR_INVALID_LEVEL; 5597 } 5598 5599 hSvc = ScmGetServiceFromHandle(hService); 5600 if (hSvc == NULL) 5601 { 5602 DPRINT1("Invalid service handle\n"); 5603 return ERROR_INVALID_HANDLE; 5604 } 5605 5606 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 5607 SERVICE_QUERY_CONFIG)) 5608 { 5609 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 5610 return ERROR_ACCESS_DENIED; 5611 } 5612 5613 lpService = hSvc->ServiceEntry; 5614 if (lpService == NULL) 5615 { 5616 DPRINT("lpService == NULL\n"); 5617 return ERROR_INVALID_HANDLE; 5618 } 5619 5620 /* Lock the service database shared */ 5621 ScmLockDatabaseShared(); 5622 5623 dwError = ScmOpenServiceKey(lpService->lpServiceName, 5624 KEY_READ, 5625 &hServiceKey); 5626 if (dwError != ERROR_SUCCESS) 5627 goto done; 5628 5629 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) 5630 { 5631 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer; 5632 LPSTR lpStr; 5633 5634 dwError = ScmReadString(hServiceKey, 5635 L"Description", 5636 &lpDescriptionW); 5637 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) 5638 goto done; 5639 5640 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA); 5641 if (dwError == ERROR_SUCCESS) 5642 *pcbBytesNeeded += (DWORD)((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR)); 5643 5644 if (cbBufSize < *pcbBytesNeeded) 5645 { 5646 dwError = ERROR_INSUFFICIENT_BUFFER; 5647 goto done; 5648 } 5649 5650 if (dwError == ERROR_SUCCESS) 5651 { 5652 lpStr = (LPSTR)(lpServiceDescription + 1); 5653 5654 WideCharToMultiByte(CP_ACP, 5655 0, 5656 lpDescriptionW, 5657 -1, 5658 lpStr, 5659 (int)wcslen(lpDescriptionW), 5660 NULL, 5661 NULL); 5662 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription); 5663 } 5664 else 5665 { 5666 lpServiceDescription->lpDescription = NULL; 5667 dwError = ERROR_SUCCESS; 5668 } 5669 } 5670 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5671 { 5672 LPSERVICE_FAILURE_ACTIONSA lpFailureActions = (LPSERVICE_FAILURE_ACTIONSA)lpBuffer; 5673 LPSTR lpStr = NULL; 5674 5675 /* Query value length */ 5676 dwError = RegQueryValueExW(hServiceKey, 5677 L"FailureActions", 5678 NULL, 5679 &dwType, 5680 NULL, 5681 &dwRequiredSize); 5682 if (dwError != ERROR_SUCCESS && 5683 dwError != ERROR_MORE_DATA && 5684 dwError != ERROR_FILE_NOT_FOUND) 5685 { 5686 goto done; 5687 } 5688 5689 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSA), dwRequiredSize) 5690 : sizeof(SERVICE_FAILURE_ACTIONSA); 5691 5692 /* Get the strings */ 5693 ScmReadString(hServiceKey, 5694 L"FailureCommand", 5695 &lpFailureCommandW); 5696 5697 ScmReadString(hServiceKey, 5698 L"RebootMessage", 5699 &lpRebootMessageW); 5700 5701 if (lpRebootMessageW) 5702 dwRequiredSize += (DWORD)((wcslen(lpRebootMessageW) + 1) * sizeof(WCHAR)); 5703 5704 if (lpFailureCommandW) 5705 dwRequiredSize += (DWORD)((wcslen(lpFailureCommandW) + 1) * sizeof(WCHAR)); 5706 5707 if (cbBufSize < dwRequiredSize) 5708 { 5709 *pcbBytesNeeded = dwRequiredSize; 5710 dwError = ERROR_INSUFFICIENT_BUFFER; 5711 goto done; 5712 } 5713 5714 /* Now we can fill the buffer */ 5715 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY) 5716 { 5717 dwError = RegQueryValueExW(hServiceKey, 5718 L"FailureActions", 5719 NULL, 5720 NULL, 5721 (LPBYTE)lpFailureActions, 5722 &dwRequiredSize); 5723 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) 5724 goto done; 5725 5726 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSA)) 5727 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSA); 5728 } 5729 else 5730 { 5731 /* 5732 * The value of the error doesn't really matter, the only 5733 * important thing is that it must be != ERROR_SUCCESS . 5734 */ 5735 dwError = ERROR_INVALID_DATA; 5736 } 5737 5738 if (dwError == ERROR_SUCCESS) 5739 { 5740 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSA)) / sizeof(SC_ACTION)); 5741 5742 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */ 5743 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSA) : NULL); 5744 5745 lpStr = (LPSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION)); 5746 } 5747 else 5748 { 5749 lpFailureActions->dwResetPeriod = 0; 5750 lpFailureActions->cActions = 0; 5751 lpFailureActions->lpsaActions = NULL; 5752 lpStr = (LPSTR)(lpFailureActions + 1); 5753 } 5754 5755 lpFailureActions->lpRebootMsg = NULL; 5756 lpFailureActions->lpCommand = NULL; 5757 5758 if (lpRebootMessageW) 5759 { 5760 WideCharToMultiByte(CP_ACP, 5761 0, 5762 lpRebootMessageW, 5763 -1, 5764 lpStr, 5765 (int)wcslen(lpRebootMessageW), 5766 NULL, 5767 NULL); 5768 lpFailureActions->lpRebootMsg = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions); 5769 lpStr += strlen(lpStr) + 1; 5770 } 5771 5772 if (lpFailureCommandW) 5773 { 5774 WideCharToMultiByte(CP_ACP, 5775 0, 5776 lpFailureCommandW, 5777 -1, 5778 lpStr, 5779 (int)wcslen(lpFailureCommandW), 5780 NULL, 5781 NULL); 5782 lpFailureActions->lpCommand = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions); 5783 /* lpStr += strlen(lpStr) + 1; */ 5784 } 5785 5786 dwError = ERROR_SUCCESS; 5787 } 5788 5789 done: 5790 /* Unlock the service database */ 5791 ScmUnlockDatabase(); 5792 5793 if (lpDescriptionW != NULL) 5794 HeapFree(GetProcessHeap(), 0, lpDescriptionW); 5795 5796 if (lpRebootMessageW != NULL) 5797 HeapFree(GetProcessHeap(), 0, lpRebootMessageW); 5798 5799 if (lpFailureCommandW != NULL) 5800 HeapFree(GetProcessHeap(), 0, lpFailureCommandW); 5801 5802 if (hServiceKey != NULL) 5803 RegCloseKey(hServiceKey); 5804 5805 DPRINT("RQueryServiceConfig2A() done (Error %lu)\n", dwError); 5806 5807 return dwError; 5808 } 5809 5810 5811 /* Function 39 */ 5812 DWORD 5813 WINAPI 5814 RQueryServiceConfig2W( 5815 SC_RPC_HANDLE hService, 5816 DWORD dwInfoLevel, 5817 LPBYTE lpBuffer, 5818 DWORD cbBufSize, 5819 LPBOUNDED_DWORD_8K pcbBytesNeeded) 5820 { 5821 DWORD dwError = ERROR_SUCCESS; 5822 PSERVICE_HANDLE hSvc; 5823 PSERVICE lpService = NULL; 5824 HKEY hServiceKey = NULL; 5825 DWORD dwRequiredSize = 0; 5826 DWORD dwType = 0; 5827 LPWSTR lpDescription = NULL; 5828 LPWSTR lpRebootMessage = NULL; 5829 LPWSTR lpFailureCommand = NULL; 5830 5831 DPRINT("RQueryServiceConfig2W() called\n"); 5832 5833 if (!lpBuffer) 5834 return ERROR_INVALID_ADDRESS; 5835 5836 if (ScmShutdown) 5837 return ERROR_SHUTDOWN_IN_PROGRESS; 5838 5839 if ((dwInfoLevel < SERVICE_CONFIG_DESCRIPTION) || 5840 (dwInfoLevel > SERVICE_CONFIG_FAILURE_ACTIONS)) 5841 { 5842 return ERROR_INVALID_LEVEL; 5843 } 5844 5845 hSvc = ScmGetServiceFromHandle(hService); 5846 if (hSvc == NULL) 5847 { 5848 DPRINT1("Invalid service handle\n"); 5849 return ERROR_INVALID_HANDLE; 5850 } 5851 5852 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 5853 SERVICE_QUERY_CONFIG)) 5854 { 5855 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 5856 return ERROR_ACCESS_DENIED; 5857 } 5858 5859 lpService = hSvc->ServiceEntry; 5860 if (lpService == NULL) 5861 { 5862 DPRINT("lpService == NULL\n"); 5863 return ERROR_INVALID_HANDLE; 5864 } 5865 5866 /* Lock the service database shared */ 5867 ScmLockDatabaseShared(); 5868 5869 dwError = ScmOpenServiceKey(lpService->lpServiceName, 5870 KEY_READ, 5871 &hServiceKey); 5872 if (dwError != ERROR_SUCCESS) 5873 goto done; 5874 5875 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION) 5876 { 5877 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer; 5878 LPWSTR lpStr; 5879 5880 dwError = ScmReadString(hServiceKey, 5881 L"Description", 5882 &lpDescription); 5883 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) 5884 goto done; 5885 5886 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW); 5887 if (dwError == ERROR_SUCCESS) 5888 *pcbBytesNeeded += (DWORD)((wcslen(lpDescription) + 1) * sizeof(WCHAR)); 5889 5890 if (cbBufSize < *pcbBytesNeeded) 5891 { 5892 dwError = ERROR_INSUFFICIENT_BUFFER; 5893 goto done; 5894 } 5895 5896 if (dwError == ERROR_SUCCESS) 5897 { 5898 lpStr = (LPWSTR)(lpServiceDescription + 1); 5899 wcscpy(lpStr, lpDescription); 5900 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription); 5901 } 5902 else 5903 { 5904 lpServiceDescription->lpDescription = NULL; 5905 dwError = ERROR_SUCCESS; 5906 } 5907 } 5908 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS) 5909 { 5910 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer; 5911 LPWSTR lpStr = NULL; 5912 5913 /* Query value length */ 5914 dwError = RegQueryValueExW(hServiceKey, 5915 L"FailureActions", 5916 NULL, 5917 &dwType, 5918 NULL, 5919 &dwRequiredSize); 5920 if (dwError != ERROR_SUCCESS && 5921 dwError != ERROR_MORE_DATA && 5922 dwError != ERROR_FILE_NOT_FOUND) 5923 { 5924 goto done; 5925 } 5926 5927 dwRequiredSize = (dwType == REG_BINARY) ? max(sizeof(SERVICE_FAILURE_ACTIONSW), dwRequiredSize) 5928 : sizeof(SERVICE_FAILURE_ACTIONSW); 5929 5930 /* Get the strings */ 5931 ScmReadString(hServiceKey, 5932 L"FailureCommand", 5933 &lpFailureCommand); 5934 5935 ScmReadString(hServiceKey, 5936 L"RebootMessage", 5937 &lpRebootMessage); 5938 5939 if (lpRebootMessage) 5940 dwRequiredSize += (DWORD)((wcslen(lpRebootMessage) + 1) * sizeof(WCHAR)); 5941 5942 if (lpFailureCommand) 5943 dwRequiredSize += (DWORD)((wcslen(lpFailureCommand) + 1) * sizeof(WCHAR)); 5944 5945 if (cbBufSize < dwRequiredSize) 5946 { 5947 *pcbBytesNeeded = dwRequiredSize; 5948 dwError = ERROR_INSUFFICIENT_BUFFER; 5949 goto done; 5950 } 5951 5952 /* Now we can fill the buffer */ 5953 if (dwError != ERROR_FILE_NOT_FOUND && dwType == REG_BINARY) 5954 { 5955 dwError = RegQueryValueExW(hServiceKey, 5956 L"FailureActions", 5957 NULL, 5958 NULL, 5959 (LPBYTE)lpFailureActions, 5960 &dwRequiredSize); 5961 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND) 5962 goto done; 5963 5964 if (dwRequiredSize < sizeof(SERVICE_FAILURE_ACTIONSW)) 5965 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW); 5966 } 5967 else 5968 { 5969 /* 5970 * The value of the error doesn't really matter, the only 5971 * important thing is that it must be != ERROR_SUCCESS . 5972 */ 5973 dwError = ERROR_INVALID_DATA; 5974 } 5975 5976 if (dwError == ERROR_SUCCESS) 5977 { 5978 lpFailureActions->cActions = min(lpFailureActions->cActions, (dwRequiredSize - sizeof(SERVICE_FAILURE_ACTIONSW)) / sizeof(SC_ACTION)); 5979 5980 /* Here lpFailureActions->lpsaActions contains an offset. The conversion is done by the caller. */ 5981 lpFailureActions->lpsaActions = (lpFailureActions->cActions > 0 ? (LPSC_ACTION)(ULONG_PTR)sizeof(SERVICE_FAILURE_ACTIONSW) : NULL); 5982 5983 lpStr = (LPWSTR)((ULONG_PTR)(lpFailureActions + 1) + lpFailureActions->cActions * sizeof(SC_ACTION)); 5984 } 5985 else 5986 { 5987 lpFailureActions->dwResetPeriod = 0; 5988 lpFailureActions->cActions = 0; 5989 lpFailureActions->lpsaActions = NULL; 5990 lpStr = (LPWSTR)(lpFailureActions + 1); 5991 } 5992 5993 lpFailureActions->lpRebootMsg = NULL; 5994 lpFailureActions->lpCommand = NULL; 5995 5996 if (lpRebootMessage) 5997 { 5998 wcscpy(lpStr, lpRebootMessage); 5999 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions); 6000 lpStr += wcslen(lpStr) + 1; 6001 } 6002 6003 if (lpFailureCommand) 6004 { 6005 wcscpy(lpStr, lpFailureCommand); 6006 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureActions); 6007 /* lpStr += wcslen(lpStr) + 1; */ 6008 } 6009 6010 dwError = ERROR_SUCCESS; 6011 } 6012 6013 done: 6014 /* Unlock the service database */ 6015 ScmUnlockDatabase(); 6016 6017 if (lpDescription != NULL) 6018 HeapFree(GetProcessHeap(), 0, lpDescription); 6019 6020 if (lpRebootMessage != NULL) 6021 HeapFree(GetProcessHeap(), 0, lpRebootMessage); 6022 6023 if (lpFailureCommand != NULL) 6024 HeapFree(GetProcessHeap(), 0, lpFailureCommand); 6025 6026 if (hServiceKey != NULL) 6027 RegCloseKey(hServiceKey); 6028 6029 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError); 6030 6031 return dwError; 6032 } 6033 6034 6035 /* Function 40 */ 6036 DWORD 6037 WINAPI 6038 RQueryServiceStatusEx( 6039 SC_RPC_HANDLE hService, 6040 SC_STATUS_TYPE InfoLevel, 6041 LPBYTE lpBuffer, 6042 DWORD cbBufSize, 6043 LPBOUNDED_DWORD_8K pcbBytesNeeded) 6044 { 6045 LPSERVICE_STATUS_PROCESS lpStatus; 6046 PSERVICE_HANDLE hSvc; 6047 PSERVICE lpService; 6048 6049 DPRINT("RQueryServiceStatusEx() called\n"); 6050 6051 if (ScmShutdown) 6052 return ERROR_SHUTDOWN_IN_PROGRESS; 6053 6054 if (InfoLevel != SC_STATUS_PROCESS_INFO) 6055 return ERROR_INVALID_LEVEL; 6056 6057 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS); 6058 6059 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS)) 6060 return ERROR_INSUFFICIENT_BUFFER; 6061 6062 hSvc = ScmGetServiceFromHandle(hService); 6063 if (hSvc == NULL) 6064 { 6065 DPRINT1("Invalid service handle\n"); 6066 return ERROR_INVALID_HANDLE; 6067 } 6068 6069 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess, 6070 SERVICE_QUERY_STATUS)) 6071 { 6072 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess); 6073 return ERROR_ACCESS_DENIED; 6074 } 6075 6076 lpService = hSvc->ServiceEntry; 6077 if (lpService == NULL) 6078 { 6079 DPRINT("lpService == NULL\n"); 6080 return ERROR_INVALID_HANDLE; 6081 } 6082 6083 /* Lock the service database shared */ 6084 ScmLockDatabaseShared(); 6085 6086 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer; 6087 6088 /* Return service status information */ 6089 RtlCopyMemory(lpStatus, 6090 &lpService->Status, 6091 sizeof(SERVICE_STATUS)); 6092 6093 /* Copy the service process ID */ 6094 if ((lpService->Status.dwCurrentState == SERVICE_STOPPED) || (lpService->lpImage == NULL)) 6095 lpStatus->dwProcessId = 0; 6096 else 6097 lpStatus->dwProcessId = lpService->lpImage->dwProcessId; 6098 6099 lpStatus->dwServiceFlags = 0; /* FIXME */ 6100 6101 /* Unlock the service database */ 6102 ScmUnlockDatabase(); 6103 6104 return ERROR_SUCCESS; 6105 } 6106 6107 6108 /* Function 41 */ 6109 DWORD 6110 WINAPI 6111 REnumServicesStatusExA( 6112 SC_RPC_HANDLE hSCManager, 6113 SC_ENUM_TYPE InfoLevel, 6114 DWORD dwServiceType, 6115 DWORD dwServiceState, 6116 LPBYTE lpBuffer, 6117 DWORD cbBufSize, 6118 LPBOUNDED_DWORD_256K pcbBytesNeeded, 6119 LPBOUNDED_DWORD_256K lpServicesReturned, 6120 LPBOUNDED_DWORD_256K lpResumeIndex, 6121 LPCSTR pszGroupName) 6122 { 6123 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL; 6124 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrIncrW; 6125 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL; 6126 LPWSTR lpStringPtrW; 6127 LPSTR lpStringPtrA; 6128 LPWSTR pszGroupNameW = NULL; 6129 DWORD dwError; 6130 DWORD dwServiceCount; 6131 6132 DPRINT("REnumServicesStatusExA() called\n"); 6133 6134 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL) 6135 { 6136 return ERROR_INVALID_ADDRESS; 6137 } 6138 6139 if (pszGroupName) 6140 { 6141 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR)); 6142 if (!pszGroupNameW) 6143 { 6144 DPRINT("Failed to allocate buffer\n"); 6145 dwError = ERROR_NOT_ENOUGH_MEMORY; 6146 goto Done; 6147 } 6148 6149 MultiByteToWideChar(CP_ACP, 6150 0, 6151 pszGroupName, 6152 -1, 6153 pszGroupNameW, 6154 (int)(strlen(pszGroupName) + 1)); 6155 } 6156 6157 if ((cbBufSize > 0) && (lpBuffer)) 6158 { 6159 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize); 6160 if (!lpStatusPtrW) 6161 { 6162 DPRINT("Failed to allocate buffer\n"); 6163 dwError = ERROR_NOT_ENOUGH_MEMORY; 6164 goto Done; 6165 } 6166 } 6167 6168 dwError = REnumServicesStatusExW(hSCManager, 6169 InfoLevel, 6170 dwServiceType, 6171 dwServiceState, 6172 (LPBYTE)lpStatusPtrW, 6173 cbBufSize, 6174 pcbBytesNeeded, 6175 lpServicesReturned, 6176 lpResumeIndex, 6177 pszGroupNameW); 6178 6179 /* if no services were returned then we are Done */ 6180 if (*lpServicesReturned == 0) 6181 goto Done; 6182 6183 lpStatusPtrIncrW = lpStatusPtrW; 6184 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer; 6185 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer + 6186 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA)); 6187 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW + 6188 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); 6189 6190 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++) 6191 { 6192 /* Copy the service name */ 6193 WideCharToMultiByte(CP_ACP, 6194 0, 6195 lpStringPtrW, 6196 -1, 6197 lpStringPtrA, 6198 (int)wcslen(lpStringPtrW), 6199 0, 6200 0); 6201 6202 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); 6203 lpStringPtrA += wcslen(lpStringPtrW) + 1; 6204 lpStringPtrW += wcslen(lpStringPtrW) + 1; 6205 6206 /* Copy the display name */ 6207 WideCharToMultiByte(CP_ACP, 6208 0, 6209 lpStringPtrW, 6210 -1, 6211 lpStringPtrA, 6212 (int)wcslen(lpStringPtrW), 6213 0, 6214 0); 6215 6216 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer); 6217 lpStringPtrA += wcslen(lpStringPtrW) + 1; 6218 lpStringPtrW += wcslen(lpStringPtrW) + 1; 6219 6220 /* Copy the status information */ 6221 memcpy(&lpStatusPtrA->ServiceStatusProcess, 6222 &lpStatusPtrIncrW->ServiceStatusProcess, 6223 sizeof(SERVICE_STATUS)); 6224 6225 /* Copy the service process ID */ 6226 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrIncrW->ServiceStatusProcess.dwProcessId; 6227 6228 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */ 6229 6230 lpStatusPtrIncrW++; 6231 lpStatusPtrA++; 6232 } 6233 6234 Done: 6235 if (pszGroupNameW) 6236 HeapFree(GetProcessHeap(), 0, pszGroupNameW); 6237 6238 if (lpStatusPtrW) 6239 HeapFree(GetProcessHeap(), 0, lpStatusPtrW); 6240 6241 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError); 6242 6243 return dwError; 6244 } 6245 6246 6247 /* Function 42 */ 6248 DWORD 6249 WINAPI 6250 REnumServicesStatusExW( 6251 SC_RPC_HANDLE hSCManager, 6252 SC_ENUM_TYPE InfoLevel, 6253 DWORD dwServiceType, 6254 DWORD dwServiceState, 6255 LPBYTE lpBuffer, 6256 DWORD cbBufSize, 6257 LPBOUNDED_DWORD_256K pcbBytesNeeded, 6258 LPBOUNDED_DWORD_256K lpServicesReturned, 6259 LPBOUNDED_DWORD_256K lpResumeIndex, 6260 LPCWSTR pszGroupName) 6261 { 6262 PMANAGER_HANDLE hManager; 6263 PSERVICE lpService; 6264 DWORD dwError = ERROR_SUCCESS; 6265 PLIST_ENTRY ServiceEntry; 6266 PSERVICE CurrentService; 6267 DWORD dwState; 6268 DWORD dwRequiredSize; 6269 DWORD dwServiceCount; 6270 DWORD dwSize; 6271 DWORD dwLastResumeCount = 0; 6272 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr; 6273 LPWSTR lpStringPtr; 6274 6275 DPRINT("REnumServicesStatusExW() called\n"); 6276 6277 if (ScmShutdown) 6278 return ERROR_SHUTDOWN_IN_PROGRESS; 6279 6280 if (InfoLevel != SC_ENUM_PROCESS_INFO) 6281 return ERROR_INVALID_LEVEL; 6282 6283 hManager = ScmGetServiceManagerFromHandle(hSCManager); 6284 if (hManager == NULL) 6285 { 6286 DPRINT1("Invalid service manager handle\n"); 6287 return ERROR_INVALID_HANDLE; 6288 } 6289 6290 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL) 6291 { 6292 return ERROR_INVALID_ADDRESS; 6293 } 6294 6295 *pcbBytesNeeded = 0; 6296 *lpServicesReturned = 0; 6297 6298 if ((dwServiceType == 0) || 6299 ((dwServiceType & ~SERVICE_TYPE_ALL) != 0)) 6300 { 6301 DPRINT("Invalid Service Type\n"); 6302 return ERROR_INVALID_PARAMETER; 6303 } 6304 6305 if ((dwServiceState == 0) || 6306 ((dwServiceState & ~SERVICE_STATE_ALL) != 0)) 6307 { 6308 DPRINT("Invalid Service State\n"); 6309 return ERROR_INVALID_PARAMETER; 6310 } 6311 6312 /* Check access rights */ 6313 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, 6314 SC_MANAGER_ENUMERATE_SERVICE)) 6315 { 6316 DPRINT("Insufficient access rights 0x%lx\n", 6317 hManager->Handle.DesiredAccess); 6318 return ERROR_ACCESS_DENIED; 6319 } 6320 6321 if (lpResumeIndex) 6322 dwLastResumeCount = *lpResumeIndex; 6323 6324 /* Lock the service database shared */ 6325 ScmLockDatabaseShared(); 6326 6327 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount); 6328 if (lpService == NULL) 6329 { 6330 dwError = ERROR_SUCCESS; 6331 goto Done; 6332 } 6333 6334 dwRequiredSize = 0; 6335 dwServiceCount = 0; 6336 6337 for (ServiceEntry = &lpService->ServiceListEntry; 6338 ServiceEntry != &ServiceListHead; 6339 ServiceEntry = ServiceEntry->Flink) 6340 { 6341 CurrentService = CONTAINING_RECORD(ServiceEntry, 6342 SERVICE, 6343 ServiceListEntry); 6344 6345 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) 6346 continue; 6347 6348 dwState = SERVICE_ACTIVE; 6349 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) 6350 dwState = SERVICE_INACTIVE; 6351 6352 if ((dwState & dwServiceState) == 0) 6353 continue; 6354 6355 if (pszGroupName) 6356 { 6357 if (*pszGroupName == 0) 6358 { 6359 if (CurrentService->lpGroup != NULL) 6360 continue; 6361 } 6362 else 6363 { 6364 if ((CurrentService->lpGroup == NULL) || 6365 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0) 6366 continue; 6367 } 6368 } 6369 6370 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) + 6371 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + 6372 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); 6373 6374 if (dwRequiredSize + dwSize <= cbBufSize) 6375 { 6376 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName); 6377 dwRequiredSize += dwSize; 6378 dwServiceCount++; 6379 dwLastResumeCount = CurrentService->dwResumeCount; 6380 } 6381 else 6382 { 6383 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName); 6384 break; 6385 } 6386 6387 } 6388 6389 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize); 6390 DPRINT("dwServiceCount: %lu\n", dwServiceCount); 6391 6392 for (; 6393 ServiceEntry != &ServiceListHead; 6394 ServiceEntry = ServiceEntry->Flink) 6395 { 6396 CurrentService = CONTAINING_RECORD(ServiceEntry, 6397 SERVICE, 6398 ServiceListEntry); 6399 6400 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) 6401 continue; 6402 6403 dwState = SERVICE_ACTIVE; 6404 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) 6405 dwState = SERVICE_INACTIVE; 6406 6407 if ((dwState & dwServiceState) == 0) 6408 continue; 6409 6410 if (pszGroupName) 6411 { 6412 if (*pszGroupName == 0) 6413 { 6414 if (CurrentService->lpGroup != NULL) 6415 continue; 6416 } 6417 else 6418 { 6419 if ((CurrentService->lpGroup == NULL) || 6420 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0) 6421 continue; 6422 } 6423 } 6424 6425 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) + 6426 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + 6427 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR))); 6428 6429 dwError = ERROR_MORE_DATA; 6430 } 6431 6432 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize); 6433 6434 if (lpResumeIndex) 6435 *lpResumeIndex = dwLastResumeCount; 6436 6437 *lpServicesReturned = dwServiceCount; 6438 *pcbBytesNeeded = dwRequiredSize; 6439 6440 /* If there was no services that matched */ 6441 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA)) 6442 { 6443 dwError = ERROR_SERVICE_DOES_NOT_EXIST; 6444 goto Done; 6445 } 6446 6447 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer; 6448 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer + 6449 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW)); 6450 6451 dwRequiredSize = 0; 6452 for (ServiceEntry = &lpService->ServiceListEntry; 6453 ServiceEntry != &ServiceListHead; 6454 ServiceEntry = ServiceEntry->Flink) 6455 { 6456 CurrentService = CONTAINING_RECORD(ServiceEntry, 6457 SERVICE, 6458 ServiceListEntry); 6459 6460 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0) 6461 continue; 6462 6463 dwState = SERVICE_ACTIVE; 6464 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED) 6465 dwState = SERVICE_INACTIVE; 6466 6467 if ((dwState & dwServiceState) == 0) 6468 continue; 6469 6470 if (pszGroupName) 6471 { 6472 if (*pszGroupName == 0) 6473 { 6474 if (CurrentService->lpGroup != NULL) 6475 continue; 6476 } 6477 else 6478 { 6479 if ((CurrentService->lpGroup == NULL) || 6480 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName) != 0) 6481 continue; 6482 } 6483 } 6484 6485 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) + 6486 (DWORD)((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) + 6487 (DWORD)((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)); 6488 6489 if (dwRequiredSize + dwSize <= cbBufSize) 6490 { 6491 /* Copy the service name */ 6492 wcscpy(lpStringPtr, 6493 CurrentService->lpServiceName); 6494 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); 6495 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1); 6496 6497 /* Copy the display name */ 6498 wcscpy(lpStringPtr, 6499 CurrentService->lpDisplayName); 6500 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer); 6501 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1); 6502 6503 /* Copy the status information */ 6504 memcpy(&lpStatusPtr->ServiceStatusProcess, 6505 &CurrentService->Status, 6506 sizeof(SERVICE_STATUS)); 6507 6508 /* Copy the service process ID */ 6509 if ((CurrentService->Status.dwCurrentState == SERVICE_STOPPED) || (CurrentService->lpImage == NULL)) 6510 lpStatusPtr->ServiceStatusProcess.dwProcessId = 0; 6511 else 6512 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->lpImage->dwProcessId; 6513 6514 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */ 6515 6516 lpStatusPtr++; 6517 dwRequiredSize += dwSize; 6518 } 6519 else 6520 { 6521 break; 6522 } 6523 } 6524 6525 if (dwError == 0) 6526 { 6527 *pcbBytesNeeded = 0; 6528 if (lpResumeIndex) 6529 *lpResumeIndex = 0; 6530 } 6531 6532 Done: 6533 /* Unlock the service database */ 6534 ScmUnlockDatabase(); 6535 6536 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError); 6537 6538 return dwError; 6539 } 6540 6541 6542 /* Function 43 */ 6543 DWORD 6544 WINAPI 6545 RSendTSMessage( 6546 handle_t BindingHandle) /* FIXME */ 6547 { 6548 UNIMPLEMENTED; 6549 return ERROR_CALL_NOT_IMPLEMENTED; 6550 } 6551 6552 6553 /* Function 44 */ 6554 DWORD 6555 WINAPI 6556 RCreateServiceWOW64A( 6557 handle_t BindingHandle, 6558 LPSTR lpServiceName, 6559 LPSTR lpDisplayName, 6560 DWORD dwDesiredAccess, 6561 DWORD dwServiceType, 6562 DWORD dwStartType, 6563 DWORD dwErrorControl, 6564 LPSTR lpBinaryPathName, 6565 LPSTR lpLoadOrderGroup, 6566 LPDWORD lpdwTagId, 6567 LPBYTE lpDependencies, 6568 DWORD dwDependSize, 6569 LPSTR lpServiceStartName, 6570 LPBYTE lpPassword, 6571 DWORD dwPwSize, 6572 LPSC_RPC_HANDLE lpServiceHandle) 6573 { 6574 UNIMPLEMENTED; 6575 return ERROR_CALL_NOT_IMPLEMENTED; 6576 } 6577 6578 6579 /* Function 45 */ 6580 DWORD 6581 WINAPI 6582 RCreateServiceWOW64W( 6583 handle_t BindingHandle, 6584 LPWSTR lpServiceName, 6585 LPWSTR lpDisplayName, 6586 DWORD dwDesiredAccess, 6587 DWORD dwServiceType, 6588 DWORD dwStartType, 6589 DWORD dwErrorControl, 6590 LPWSTR lpBinaryPathName, 6591 LPWSTR lpLoadOrderGroup, 6592 LPDWORD lpdwTagId, 6593 LPBYTE lpDependencies, 6594 DWORD dwDependSize, 6595 LPWSTR lpServiceStartName, 6596 LPBYTE lpPassword, 6597 DWORD dwPwSize, 6598 LPSC_RPC_HANDLE lpServiceHandle) 6599 { 6600 UNIMPLEMENTED; 6601 return ERROR_CALL_NOT_IMPLEMENTED; 6602 } 6603 6604 6605 /* Function 46 */ 6606 DWORD 6607 WINAPI 6608 RI_ScQueryServiceTagInfo( 6609 SC_RPC_HANDLE hSCManager, 6610 TAG_INFO_LEVEL dwInfoLevel, 6611 PTAG_INFO_NAME_FROM_TAG_IN_PARAMS * lpInParams, 6612 PTAG_INFO_NAME_FROM_TAG_OUT_PARAMS * lpOutParams) 6613 { 6614 PMANAGER_HANDLE hManager; 6615 6616 /* Validate handle */ 6617 hManager = ScmGetServiceManagerFromHandle(hSCManager); 6618 if (hManager == NULL) 6619 { 6620 return ERROR_INVALID_HANDLE; 6621 } 6622 6623 /* FIXME: should check whether client is local */ 6624 6625 /* Check access rights */ 6626 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, 6627 SC_MANAGER_ENUMERATE_SERVICE)) 6628 { 6629 return ERROR_ACCESS_DENIED; 6630 } 6631 6632 /* Check parameters */ 6633 if (lpInParams == NULL || lpOutParams == NULL) 6634 { 6635 return ERROR_INVALID_PARAMETER; 6636 } 6637 6638 /* Check info level */ 6639 if (dwInfoLevel != TagInfoLevelNameFromTag) 6640 { 6641 return ERROR_RETRY; 6642 } 6643 6644 /* Call internal helper */ 6645 return ScmGetServiceNameFromTag(*lpInParams, lpOutParams); 6646 } 6647 6648 6649 /* Function 47 */ 6650 DWORD 6651 WINAPI 6652 RNotifyServiceStatusChange( 6653 SC_RPC_HANDLE hService, 6654 SC_RPC_NOTIFY_PARAMS NotifyParams, 6655 GUID *pClientProcessGuid, 6656 GUID *pSCMProcessGuid, 6657 PBOOL pfCreateRemoteQueue, 6658 LPSC_NOTIFY_RPC_HANDLE phNotify) 6659 { 6660 UNIMPLEMENTED; 6661 return ERROR_CALL_NOT_IMPLEMENTED; 6662 } 6663 6664 6665 /* Function 48 */ 6666 DWORD 6667 WINAPI 6668 RGetNotifyResults( 6669 SC_NOTIFY_RPC_HANDLE hNotify, 6670 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams) 6671 { 6672 UNIMPLEMENTED; 6673 return ERROR_CALL_NOT_IMPLEMENTED; 6674 } 6675 6676 6677 /* Function 49 */ 6678 DWORD 6679 WINAPI 6680 RCloseNotifyHandle( 6681 LPSC_NOTIFY_RPC_HANDLE phNotify, 6682 PBOOL pfApcFired) 6683 { 6684 UNIMPLEMENTED; 6685 return ERROR_CALL_NOT_IMPLEMENTED; 6686 } 6687 6688 6689 /* Function 50 */ 6690 DWORD 6691 WINAPI 6692 RControlServiceExA( 6693 SC_RPC_HANDLE hService, 6694 DWORD dwControl, 6695 DWORD dwInfoLevel) 6696 { 6697 UNIMPLEMENTED; 6698 return ERROR_CALL_NOT_IMPLEMENTED; 6699 } 6700 6701 6702 /* Function 51 */ 6703 DWORD 6704 WINAPI 6705 RControlServiceExW( 6706 SC_RPC_HANDLE hService, 6707 DWORD dwControl, 6708 DWORD dwInfoLevel) 6709 { 6710 UNIMPLEMENTED; 6711 return ERROR_CALL_NOT_IMPLEMENTED; 6712 } 6713 6714 6715 /* Function 52 */ 6716 DWORD 6717 WINAPI 6718 RSendPnPMessage( 6719 handle_t BindingHandle) /* FIXME */ 6720 { 6721 UNIMPLEMENTED; 6722 return ERROR_CALL_NOT_IMPLEMENTED; 6723 } 6724 6725 6726 /* Function 53 */ 6727 DWORD 6728 WINAPI 6729 RI_ScValidatePnPService( 6730 _In_ SC_RPC_HANDLE hSCManager, 6731 _In_ LPWSTR pszServiceName, 6732 _Out_ RPC_SERVICE_STATUS_HANDLE *phServiceStatus) 6733 { 6734 PMANAGER_HANDLE hManager; 6735 PSERVICE pService; 6736 6737 DPRINT("RI_ScValidatePnPService(%p %S %p)\n", hSCManager, pszServiceName, phServiceStatus); 6738 6739 /* Validate handle */ 6740 hManager = ScmGetServiceManagerFromHandle(hSCManager); 6741 if (hManager == NULL) 6742 { 6743 DPRINT1("Invalid handle\n"); 6744 return ERROR_INVALID_HANDLE; 6745 } 6746 6747 /* FIXME: should check whether client is local */ 6748 6749 /* Check access rights */ 6750 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess, 6751 SC_MANAGER_CONNECT)) 6752 { 6753 DPRINT1("No SC_MANAGER_CONNECT access\n"); 6754 return ERROR_ACCESS_DENIED; 6755 } 6756 6757 pService = ScmGetServiceEntryByName(pszServiceName); 6758 DPRINT("pService: %p\n", pService); 6759 if (pService == NULL) 6760 return ERROR_SERVICE_DOES_NOT_EXIST; 6761 6762 *phServiceStatus = (RPC_SERVICE_STATUS_HANDLE)pService; 6763 6764 return ERROR_SUCCESS; 6765 } 6766 6767 6768 /* Function 54 */ 6769 DWORD 6770 WINAPI 6771 ROpenServiceStatusHandle( 6772 handle_t BindingHandle) /* FIXME */ 6773 { 6774 UNIMPLEMENTED; 6775 return ERROR_CALL_NOT_IMPLEMENTED; 6776 } 6777 6778 6779 /* Function 55 */ 6780 DWORD 6781 WINAPI 6782 RFunction55( 6783 handle_t BindingHandle) /* FIXME */ 6784 { 6785 UNIMPLEMENTED; 6786 return ERROR_CALL_NOT_IMPLEMENTED; 6787 } 6788 6789 6790 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len) 6791 { 6792 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len); 6793 } 6794 6795 6796 void __RPC_USER midl_user_free(void __RPC_FAR * ptr) 6797 { 6798 HeapFree(GetProcessHeap(), 0, ptr); 6799 } 6800 6801 6802 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject) 6803 { 6804 /* Close the handle */ 6805 RCloseServiceHandle(&hSCObject); 6806 } 6807 6808 6809 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock) 6810 { 6811 /* Unlock the database */ 6812 RUnlockServiceDatabase(&Lock); 6813 } 6814 6815 6816 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify) 6817 { 6818 } 6819 6820 /* EOF */ 6821