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