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