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