1 /* 2 * PROJECT: ReactOS advapi32 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: dll/win32/advapi32/service/sctrl.c 5 * PURPOSE: Service control manager functions 6 * COPYRIGHT: Copyright 1999 Emanuele Aliberti 7 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org> 8 * Gregor Brunmar <gregor.brunmar@home.se> 9 */ 10 11 12 /* INCLUDES ******************************************************************/ 13 14 #include <advapi32.h> 15 #include <pseh/pseh2.h> 16 17 WINE_DEFAULT_DEBUG_CHANNEL(advapi); 18 19 20 /* TYPES *********************************************************************/ 21 22 typedef struct _SERVICE_THREAD_PARAMSA 23 { 24 LPSERVICE_MAIN_FUNCTIONA lpServiceMain; 25 DWORD dwArgCount; 26 LPSTR *lpArgVector; 27 DWORD dwServiceTag; 28 } SERVICE_THREAD_PARAMSA, *PSERVICE_THREAD_PARAMSA; 29 30 31 typedef struct _SERVICE_THREAD_PARAMSW 32 { 33 LPSERVICE_MAIN_FUNCTIONW lpServiceMain; 34 DWORD dwArgCount; 35 LPWSTR *lpArgVector; 36 DWORD dwServiceTag; 37 } SERVICE_THREAD_PARAMSW, *PSERVICE_THREAD_PARAMSW; 38 39 40 typedef struct _ACTIVE_SERVICE 41 { 42 SERVICE_STATUS_HANDLE hServiceStatus; 43 UNICODE_STRING ServiceName; 44 union 45 { 46 LPSERVICE_MAIN_FUNCTIONA A; 47 LPSERVICE_MAIN_FUNCTIONW W; 48 } ServiceMain; 49 LPHANDLER_FUNCTION HandlerFunction; 50 LPHANDLER_FUNCTION_EX HandlerFunctionEx; 51 LPVOID HandlerContext; 52 BOOL bUnicode; 53 BOOL bOwnProcess; 54 DWORD dwServiceTag; 55 } ACTIVE_SERVICE, *PACTIVE_SERVICE; 56 57 58 /* GLOBALS *******************************************************************/ 59 60 static DWORD dwActiveServiceCount = 0; 61 static PACTIVE_SERVICE lpActiveServices = NULL; 62 static handle_t hStatusBinding = NULL; 63 static BOOL bSecurityServiceProcess = FALSE; 64 65 66 /* FUNCTIONS *****************************************************************/ 67 68 handle_t __RPC_USER 69 RPC_SERVICE_STATUS_HANDLE_bind(RPC_SERVICE_STATUS_HANDLE hServiceStatus) 70 { 71 return hStatusBinding; 72 } 73 74 75 void __RPC_USER 76 RPC_SERVICE_STATUS_HANDLE_unbind(RPC_SERVICE_STATUS_HANDLE hServiceStatus, 77 handle_t hBinding) 78 { 79 } 80 81 82 static RPC_STATUS 83 ScCreateStatusBinding(VOID) 84 { 85 LPWSTR pszStringBinding; 86 RPC_STATUS status; 87 88 TRACE("ScCreateStatusBinding()\n"); 89 90 status = RpcStringBindingComposeW(NULL, 91 L"ncacn_np", 92 NULL, 93 L"\\pipe\\ntsvcs", 94 NULL, 95 &pszStringBinding); 96 if (status != RPC_S_OK) 97 { 98 ERR("RpcStringBindingCompose returned 0x%x\n", status); 99 return status; 100 } 101 102 /* Set the binding handle that will be used to bind to the server. */ 103 status = RpcBindingFromStringBindingW(pszStringBinding, 104 &hStatusBinding); 105 if (status != RPC_S_OK) 106 { 107 ERR("RpcBindingFromStringBinding returned 0x%x\n", status); 108 } 109 110 status = RpcStringFreeW(&pszStringBinding); 111 if (status != RPC_S_OK) 112 { 113 ERR("RpcStringFree returned 0x%x\n", status); 114 } 115 116 return status; 117 } 118 119 120 static RPC_STATUS 121 ScDestroyStatusBinding(VOID) 122 { 123 RPC_STATUS status; 124 125 TRACE("ScDestroyStatusBinding()\n"); 126 127 if (hStatusBinding == NULL) 128 return RPC_S_OK; 129 130 status = RpcBindingFree(&hStatusBinding); 131 if (status != RPC_S_OK) 132 { 133 ERR("RpcBindingFree returned 0x%x\n", status); 134 } 135 else 136 { 137 hStatusBinding = NULL; 138 } 139 140 return status; 141 } 142 143 144 static PACTIVE_SERVICE 145 ScLookupServiceByServiceName(LPCWSTR lpServiceName) 146 { 147 DWORD i; 148 149 TRACE("ScLookupServiceByServiceName(%S)\n", 150 lpServiceName); 151 152 if (lpActiveServices[0].bOwnProcess) 153 return &lpActiveServices[0]; 154 155 for (i = 0; i < dwActiveServiceCount; i++) 156 { 157 TRACE("Checking %S\n", lpActiveServices[i].ServiceName.Buffer); 158 if (_wcsicmp(lpActiveServices[i].ServiceName.Buffer, lpServiceName) == 0) 159 { 160 TRACE("Found!\n"); 161 return &lpActiveServices[i]; 162 } 163 } 164 165 TRACE("No service found!\n"); 166 return NULL; 167 } 168 169 170 static DWORD WINAPI 171 ScServiceMainStubA(LPVOID Context) 172 { 173 PTEB Teb; 174 PSERVICE_THREAD_PARAMSA ThreadParams = Context; 175 176 TRACE("ScServiceMainStubA(%p)\n", Context); 177 178 /* Set service tag */ 179 Teb = NtCurrentTeb(); 180 Teb->SubProcessTag = UlongToPtr(ThreadParams->dwServiceTag); 181 182 /* Call the main service routine and free the arguments vector */ 183 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 184 ThreadParams->lpArgVector); 185 186 /* Reset service tag */ 187 Teb->SubProcessTag = 0; 188 189 if (ThreadParams->lpArgVector != NULL) 190 { 191 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 192 } 193 HeapFree(GetProcessHeap(), 0, ThreadParams); 194 195 return ERROR_SUCCESS; 196 } 197 198 199 static DWORD WINAPI 200 ScServiceMainStubW(LPVOID Context) 201 { 202 PTEB Teb; 203 PSERVICE_THREAD_PARAMSW ThreadParams = Context; 204 205 TRACE("ScServiceMainStubW(%p)\n", Context); 206 207 /* Set service tag */ 208 Teb = NtCurrentTeb(); 209 Teb->SubProcessTag = UlongToPtr(ThreadParams->dwServiceTag); 210 211 /* Call the main service routine and free the arguments vector */ 212 (ThreadParams->lpServiceMain)(ThreadParams->dwArgCount, 213 ThreadParams->lpArgVector); 214 215 /* Reset service tag */ 216 Teb->SubProcessTag = 0; 217 218 if (ThreadParams->lpArgVector != NULL) 219 { 220 HeapFree(GetProcessHeap(), 0, ThreadParams->lpArgVector); 221 } 222 HeapFree(GetProcessHeap(), 0, ThreadParams); 223 224 return ERROR_SUCCESS; 225 } 226 227 228 static DWORD 229 ScConnectControlPipe(HANDLE *hPipe) 230 { 231 DWORD dwBytesWritten; 232 DWORD dwState; 233 DWORD dwServiceCurrent = 1; 234 NTSTATUS Status; 235 WCHAR NtControlPipeName[MAX_PATH + 1]; 236 RTL_QUERY_REGISTRY_TABLE QueryTable[2]; 237 DWORD dwProcessId; 238 239 TRACE("ScConnectControlPipe(%p)\n", 240 hPipe); 241 242 /* Get the service number and create the named pipe */ 243 if (bSecurityServiceProcess == FALSE) 244 { 245 RtlZeroMemory(&QueryTable, sizeof(QueryTable)); 246 247 QueryTable[0].Name = L""; 248 QueryTable[0].Flags = RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_REQUIRED; 249 QueryTable[0].EntryContext = &dwServiceCurrent; 250 251 Status = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL, 252 L"ServiceCurrent", 253 QueryTable, 254 NULL, 255 NULL); 256 if (!NT_SUCCESS(Status)) 257 { 258 ERR("RtlQueryRegistryValues() failed (Status %lx)\n", Status); 259 return RtlNtStatusToDosError(Status); 260 } 261 } 262 else 263 { 264 dwServiceCurrent = 0; 265 } 266 267 swprintf(NtControlPipeName, L"\\\\.\\pipe\\net\\NtControlPipe%u", dwServiceCurrent); 268 TRACE("PipeName: %S\n", NtControlPipeName); 269 270 if (!WaitNamedPipeW(NtControlPipeName, 30000)) 271 { 272 ERR("WaitNamedPipe(%S) failed (Error %lu)\n", NtControlPipeName, GetLastError()); 273 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 274 } 275 276 *hPipe = CreateFileW(NtControlPipeName, 277 GENERIC_READ | GENERIC_WRITE, 278 FILE_SHARE_READ | FILE_SHARE_WRITE, 279 NULL, 280 OPEN_EXISTING, 281 FILE_ATTRIBUTE_NORMAL, 282 NULL); 283 if (*hPipe == INVALID_HANDLE_VALUE) 284 { 285 ERR("CreateFileW() failed for pipe %S (Error %lu)\n", NtControlPipeName, GetLastError()); 286 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 287 } 288 289 dwState = PIPE_READMODE_MESSAGE; 290 if (!SetNamedPipeHandleState(*hPipe, &dwState, NULL, NULL)) 291 { 292 CloseHandle(*hPipe); 293 *hPipe = INVALID_HANDLE_VALUE; 294 return ERROR_FAILED_SERVICE_CONTROLLER_CONNECT; 295 } 296 297 /* Pass the ProcessId to the SCM */ 298 dwProcessId = GetCurrentProcessId(); 299 WriteFile(*hPipe, 300 &dwProcessId, 301 sizeof(dwProcessId), 302 &dwBytesWritten, 303 NULL); 304 305 TRACE("Sent Process ID %lu\n", dwProcessId); 306 307 return ERROR_SUCCESS; 308 } 309 310 311 /* 312 * Ansi/Unicode argument layout of the vector passed to a service at startup, 313 * depending on the different versions of Windows considered: 314 * 315 * - XP/2003: 316 * [argv array of pointers][parameter 1][parameter 2]...[service name] 317 * 318 * - Vista: 319 * [argv array of pointers][align to 8 bytes] 320 * [parameter 1][parameter 2]...[service name] 321 * 322 * - Win7/8: 323 * [argv array of pointers][service name] 324 * [parameter 1][align to 4 bytes][parameter 2][align to 4 bytes]... 325 * 326 * Space for parameters and service name is always enough to store 327 * both the Ansi and the Unicode versions including NULL terminator. 328 */ 329 330 static DWORD 331 ScBuildUnicodeArgsVector(PSCM_CONTROL_PACKET ControlPacket, 332 LPDWORD lpArgCount, 333 LPWSTR **lpArgVector) 334 { 335 PWSTR *lpVector; 336 PWSTR pszServiceName; 337 DWORD cbServiceName; 338 DWORD cbArguments; 339 DWORD cbTotal; 340 DWORD i; 341 342 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL) 343 return ERROR_INVALID_PARAMETER; 344 345 *lpArgCount = 0; 346 *lpArgVector = NULL; 347 348 /* Retrieve and count the start command line (NULL-terminated) */ 349 pszServiceName = (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset); 350 cbServiceName = lstrlenW(pszServiceName) * sizeof(WCHAR) + sizeof(UNICODE_NULL); 351 352 /* 353 * The total size of the argument vector is equal to the entry for 354 * the service name, plus the size of the original argument vector. 355 */ 356 cbTotal = sizeof(PWSTR) + cbServiceName; 357 if (ControlPacket->dwArgumentsCount > 0) 358 cbArguments = ControlPacket->dwSize - ControlPacket->dwArgumentsOffset; 359 else 360 cbArguments = 0; 361 cbTotal += cbArguments; 362 363 /* Allocate the new argument vector */ 364 lpVector = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbTotal); 365 if (lpVector == NULL) 366 return ERROR_NOT_ENOUGH_MEMORY; 367 368 /* 369 * The first argument is reserved for the service name, which 370 * will be appended to the end of the argument string list. 371 */ 372 373 /* Copy the remaining arguments */ 374 if (ControlPacket->dwArgumentsCount > 0) 375 { 376 memcpy(&lpVector[1], 377 (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwArgumentsOffset), 378 cbArguments); 379 380 for (i = 0; i < ControlPacket->dwArgumentsCount; i++) 381 { 382 lpVector[i + 1] = (PWSTR)((ULONG_PTR)&lpVector[1] + (ULONG_PTR)lpVector[i + 1]); 383 TRACE("Unicode lpVector[%lu] = '%ls'\n", i + 1, lpVector[i + 1]); 384 } 385 } 386 387 /* Now copy the service name */ 388 lpVector[0] = (PWSTR)((ULONG_PTR)&lpVector[1] + cbArguments); 389 memcpy(lpVector[0], pszServiceName, cbServiceName); 390 TRACE("Unicode lpVector[%lu] = '%ls'\n", 0, lpVector[0]); 391 392 *lpArgCount = ControlPacket->dwArgumentsCount + 1; 393 *lpArgVector = lpVector; 394 395 return ERROR_SUCCESS; 396 } 397 398 399 static DWORD 400 ScBuildAnsiArgsVector(PSCM_CONTROL_PACKET ControlPacket, 401 LPDWORD lpArgCount, 402 LPSTR **lpArgVector) 403 { 404 DWORD dwError; 405 NTSTATUS Status; 406 DWORD ArgCount, i; 407 PWSTR *lpVectorW; 408 PSTR *lpVectorA; 409 UNICODE_STRING UnicodeString; 410 ANSI_STRING AnsiString; 411 412 if (ControlPacket == NULL || lpArgCount == NULL || lpArgVector == NULL) 413 return ERROR_INVALID_PARAMETER; 414 415 *lpArgCount = 0; 416 *lpArgVector = NULL; 417 418 /* Build the UNICODE arguments vector */ 419 dwError = ScBuildUnicodeArgsVector(ControlPacket, &ArgCount, &lpVectorW); 420 if (dwError != ERROR_SUCCESS) 421 return dwError; 422 423 /* Convert the vector to ANSI in place */ 424 lpVectorA = (PSTR*)lpVectorW; 425 for (i = 0; i < ArgCount; i++) 426 { 427 RtlInitUnicodeString(&UnicodeString, lpVectorW[i]); 428 RtlInitEmptyAnsiString(&AnsiString, lpVectorA[i], UnicodeString.MaximumLength); 429 Status = RtlUnicodeStringToAnsiString(&AnsiString, &UnicodeString, FALSE); 430 if (!NT_SUCCESS(Status)) 431 { 432 /* Failed to convert to ANSI; free the allocated vector and return */ 433 dwError = RtlNtStatusToDosError(Status); 434 HeapFree(GetProcessHeap(), 0, lpVectorW); 435 return dwError; 436 } 437 438 /* NULL-terminate the string */ 439 AnsiString.Buffer[AnsiString.Length / sizeof(CHAR)] = ANSI_NULL; 440 441 TRACE("Ansi lpVector[%lu] = '%s'\n", i, lpVectorA[i]); 442 } 443 444 *lpArgCount = ArgCount; 445 *lpArgVector = lpVectorA; 446 447 return ERROR_SUCCESS; 448 } 449 450 451 static DWORD 452 ScStartService(PACTIVE_SERVICE lpService, 453 PSCM_CONTROL_PACKET ControlPacket) 454 { 455 HANDLE ThreadHandle; 456 DWORD ThreadId; 457 DWORD dwError; 458 PSERVICE_THREAD_PARAMSA ThreadParamsA; 459 PSERVICE_THREAD_PARAMSW ThreadParamsW; 460 461 TRACE("ScStartService(%p %p)\n", 462 lpService, ControlPacket); 463 464 if (lpService == NULL || ControlPacket == NULL) 465 return ERROR_INVALID_PARAMETER; 466 467 TRACE("Size: %lu\n", ControlPacket->dwSize); 468 TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset)); 469 470 /* Set the service status handle */ 471 lpService->hServiceStatus = ControlPacket->hServiceStatus; 472 /* Set the service tag */ 473 lpService->dwServiceTag = ControlPacket->dwServiceTag; 474 475 /* Build the arguments vector */ 476 if (lpService->bUnicode != FALSE) 477 { 478 ThreadParamsW = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsW)); 479 if (ThreadParamsW == NULL) 480 return ERROR_NOT_ENOUGH_MEMORY; 481 dwError = ScBuildUnicodeArgsVector(ControlPacket, 482 &ThreadParamsW->dwArgCount, 483 &ThreadParamsW->lpArgVector); 484 if (dwError != ERROR_SUCCESS) 485 { 486 HeapFree(GetProcessHeap(), 0, ThreadParamsW); 487 return dwError; 488 } 489 ThreadParamsW->lpServiceMain = lpService->ServiceMain.W; 490 ThreadParamsW->dwServiceTag = ControlPacket->dwServiceTag; 491 ThreadHandle = CreateThread(NULL, 492 0, 493 ScServiceMainStubW, 494 ThreadParamsW, 495 0, 496 &ThreadId); 497 if (ThreadHandle == NULL) 498 { 499 if (ThreadParamsW->lpArgVector != NULL) 500 { 501 HeapFree(GetProcessHeap(), 0, ThreadParamsW->lpArgVector); 502 } 503 HeapFree(GetProcessHeap(), 0, ThreadParamsW); 504 505 return ERROR_SERVICE_NO_THREAD; 506 } 507 508 CloseHandle(ThreadHandle); 509 } 510 else 511 { 512 ThreadParamsA = HeapAlloc(GetProcessHeap(), 0, sizeof(*ThreadParamsA)); 513 if (ThreadParamsA == NULL) 514 return ERROR_NOT_ENOUGH_MEMORY; 515 dwError = ScBuildAnsiArgsVector(ControlPacket, 516 &ThreadParamsA->dwArgCount, 517 &ThreadParamsA->lpArgVector); 518 if (dwError != ERROR_SUCCESS) 519 { 520 HeapFree(GetProcessHeap(), 0, ThreadParamsA); 521 return dwError; 522 } 523 ThreadParamsA->lpServiceMain = lpService->ServiceMain.A; 524 ThreadParamsA->dwServiceTag = ControlPacket->dwServiceTag; 525 ThreadHandle = CreateThread(NULL, 526 0, 527 ScServiceMainStubA, 528 ThreadParamsA, 529 0, 530 &ThreadId); 531 if (ThreadHandle == NULL) 532 { 533 if (ThreadParamsA->lpArgVector != NULL) 534 { 535 HeapFree(GetProcessHeap(), 0, ThreadParamsA->lpArgVector); 536 } 537 HeapFree(GetProcessHeap(), 0, ThreadParamsA); 538 539 return ERROR_SERVICE_NO_THREAD; 540 } 541 542 CloseHandle(ThreadHandle); 543 } 544 545 return ERROR_SUCCESS; 546 } 547 548 549 static DWORD 550 ScControlService(PACTIVE_SERVICE lpService, 551 PSCM_CONTROL_PACKET ControlPacket) 552 { 553 DWORD dwError = ERROR_SUCCESS; 554 555 TRACE("ScControlService(%p %p)\n", 556 lpService, ControlPacket); 557 558 if (lpService == NULL || ControlPacket == NULL) 559 return ERROR_INVALID_PARAMETER; 560 561 TRACE("Size: %lu\n", ControlPacket->dwSize); 562 TRACE("Service: %S\n", (PWSTR)((ULONG_PTR)ControlPacket + ControlPacket->dwServiceNameOffset)); 563 564 /* Set service tag */ 565 NtCurrentTeb()->SubProcessTag = UlongToPtr(lpService->dwServiceTag); 566 567 if (lpService->HandlerFunction) 568 { 569 _SEH2_TRY 570 { 571 (lpService->HandlerFunction)(ControlPacket->dwControl); 572 } 573 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 574 { 575 dwError = ERROR_EXCEPTION_IN_SERVICE; 576 } 577 _SEH2_END; 578 } 579 else if (lpService->HandlerFunctionEx) 580 { 581 _SEH2_TRY 582 { 583 /* FIXME: Send correct 2nd and 3rd parameters */ 584 (lpService->HandlerFunctionEx)(ControlPacket->dwControl, 585 0, NULL, 586 lpService->HandlerContext); 587 } 588 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 589 { 590 dwError = ERROR_EXCEPTION_IN_SERVICE; 591 } 592 _SEH2_END; 593 } 594 else 595 { 596 dwError = ERROR_SERVICE_CANNOT_ACCEPT_CTRL; 597 } 598 599 /* Reset service tag */ 600 NtCurrentTeb()->SubProcessTag = 0; 601 602 TRACE("ScControlService() done (Error %lu)\n", dwError); 603 604 return dwError; 605 } 606 607 608 static BOOL 609 ScServiceDispatcher(HANDLE hPipe, 610 PSCM_CONTROL_PACKET ControlPacket, 611 DWORD dwBufferSize) 612 { 613 DWORD Count; 614 BOOL bResult; 615 BOOL bRunning = TRUE; 616 LPWSTR lpServiceName; 617 PACTIVE_SERVICE lpService; 618 SCM_REPLY_PACKET ReplyPacket; 619 DWORD dwError; 620 621 TRACE("ScServiceDispatcher(%p %p %lu)\n", 622 hPipe, ControlPacket, dwBufferSize); 623 624 if (ControlPacket == NULL || dwBufferSize < sizeof(SCM_CONTROL_PACKET)) 625 return FALSE; 626 627 while (bRunning) 628 { 629 /* Read command from the control pipe */ 630 bResult = ReadFile(hPipe, 631 ControlPacket, 632 dwBufferSize, 633 &Count, 634 NULL); 635 if (bResult == FALSE) 636 { 637 ERR("Pipe read failed (Error: %lu)\n", GetLastError()); 638 return FALSE; 639 } 640 641 lpServiceName = (LPWSTR)((PBYTE)ControlPacket + ControlPacket->dwServiceNameOffset); 642 TRACE("Service: %S\n", lpServiceName); 643 644 if ((ControlPacket->dwControl == SERVICE_CONTROL_STOP) && 645 (lpServiceName[0] == UNICODE_NULL)) 646 { 647 TRACE("Stop dispatcher thread\n"); 648 bRunning = FALSE; 649 dwError = ERROR_SUCCESS; 650 } 651 else 652 { 653 if (ControlPacket->dwControl == SERVICE_CONTROL_START_OWN) 654 lpActiveServices[0].bOwnProcess = TRUE; 655 656 lpService = ScLookupServiceByServiceName(lpServiceName); 657 if (lpService != NULL) 658 { 659 /* Execute command */ 660 switch (ControlPacket->dwControl) 661 { 662 case SERVICE_CONTROL_START_SHARE: 663 case SERVICE_CONTROL_START_OWN: 664 TRACE("Start command - received SERVICE_CONTROL_START\n"); 665 dwError = ScStartService(lpService, ControlPacket); 666 break; 667 668 case SERVICE_CONTROL_STOP: 669 TRACE("Stop command - received SERVICE_CONTROL_STOP\n"); 670 dwError = ScControlService(lpService, ControlPacket); 671 break; 672 673 default: 674 TRACE("Command %lu received\n", ControlPacket->dwControl); 675 dwError = ScControlService(lpService, ControlPacket); 676 break; 677 } 678 } 679 else 680 { 681 dwError = ERROR_SERVICE_NOT_IN_EXE; 682 } 683 } 684 685 ReplyPacket.dwError = dwError; 686 687 /* Send the reply packet */ 688 bResult = WriteFile(hPipe, 689 &ReplyPacket, 690 sizeof(ReplyPacket), 691 &Count, 692 NULL); 693 if (bResult == FALSE) 694 { 695 ERR("Pipe write failed (Error: %lu)\n", GetLastError()); 696 return FALSE; 697 } 698 } 699 700 return TRUE; 701 } 702 703 704 /********************************************************************** 705 * RegisterServiceCtrlHandlerA 706 * 707 * @implemented 708 */ 709 SERVICE_STATUS_HANDLE WINAPI 710 RegisterServiceCtrlHandlerA(LPCSTR lpServiceName, 711 LPHANDLER_FUNCTION lpHandlerProc) 712 { 713 ANSI_STRING ServiceNameA; 714 UNICODE_STRING ServiceNameU; 715 SERVICE_STATUS_HANDLE hServiceStatus; 716 717 TRACE("RegisterServiceCtrlHandlerA(%s %p)\n", 718 debugstr_a(lpServiceName), lpHandlerProc); 719 720 RtlInitAnsiString(&ServiceNameA, lpServiceName); 721 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 722 { 723 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 724 return NULL; 725 } 726 727 hServiceStatus = RegisterServiceCtrlHandlerW(ServiceNameU.Buffer, 728 lpHandlerProc); 729 730 RtlFreeUnicodeString(&ServiceNameU); 731 732 return hServiceStatus; 733 } 734 735 736 /********************************************************************** 737 * RegisterServiceCtrlHandlerW 738 * 739 * @implemented 740 */ 741 SERVICE_STATUS_HANDLE WINAPI 742 RegisterServiceCtrlHandlerW(LPCWSTR lpServiceName, 743 LPHANDLER_FUNCTION lpHandlerProc) 744 { 745 PACTIVE_SERVICE Service; 746 747 TRACE("RegisterServiceCtrlHandlerW(%s %p)\n", 748 debugstr_w(lpServiceName), lpHandlerProc); 749 750 Service = ScLookupServiceByServiceName(lpServiceName); 751 if (Service == NULL) 752 { 753 SetLastError(ERROR_SERVICE_NOT_IN_EXE); 754 return NULL; 755 } 756 757 if (!lpHandlerProc) 758 { 759 SetLastError(ERROR_INVALID_PARAMETER); 760 return NULL; 761 } 762 763 Service->HandlerFunction = lpHandlerProc; 764 Service->HandlerFunctionEx = NULL; 765 766 TRACE("RegisterServiceCtrlHandler returning %p\n", Service->hServiceStatus); 767 768 return Service->hServiceStatus; 769 } 770 771 772 /********************************************************************** 773 * RegisterServiceCtrlHandlerExA 774 * 775 * @implemented 776 */ 777 SERVICE_STATUS_HANDLE WINAPI 778 RegisterServiceCtrlHandlerExA(LPCSTR lpServiceName, 779 LPHANDLER_FUNCTION_EX lpHandlerProc, 780 LPVOID lpContext) 781 { 782 ANSI_STRING ServiceNameA; 783 UNICODE_STRING ServiceNameU; 784 SERVICE_STATUS_HANDLE hServiceStatus; 785 786 TRACE("RegisterServiceCtrlHandlerExA(%s %p %p)\n", 787 debugstr_a(lpServiceName), lpHandlerProc, lpContext); 788 789 RtlInitAnsiString(&ServiceNameA, lpServiceName); 790 if (!NT_SUCCESS(RtlAnsiStringToUnicodeString(&ServiceNameU, &ServiceNameA, TRUE))) 791 { 792 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 793 return NULL; 794 } 795 796 hServiceStatus = RegisterServiceCtrlHandlerExW(ServiceNameU.Buffer, 797 lpHandlerProc, 798 lpContext); 799 800 RtlFreeUnicodeString(&ServiceNameU); 801 802 return hServiceStatus; 803 } 804 805 806 /********************************************************************** 807 * RegisterServiceCtrlHandlerExW 808 * 809 * @implemented 810 */ 811 SERVICE_STATUS_HANDLE WINAPI 812 RegisterServiceCtrlHandlerExW(LPCWSTR lpServiceName, 813 LPHANDLER_FUNCTION_EX lpHandlerProc, 814 LPVOID lpContext) 815 { 816 PACTIVE_SERVICE Service; 817 818 TRACE("RegisterServiceCtrlHandlerExW(%s %p %p)\n", 819 debugstr_w(lpServiceName), lpHandlerProc, lpContext); 820 821 Service = ScLookupServiceByServiceName(lpServiceName); 822 if (Service == NULL) 823 { 824 SetLastError(ERROR_SERVICE_NOT_IN_EXE); 825 return NULL; 826 } 827 828 if (!lpHandlerProc) 829 { 830 SetLastError(ERROR_INVALID_PARAMETER); 831 return NULL; 832 } 833 834 Service->HandlerFunction = NULL; 835 Service->HandlerFunctionEx = lpHandlerProc; 836 Service->HandlerContext = lpContext; 837 838 TRACE("RegisterServiceCtrlHandlerEx returning %p\n", Service->hServiceStatus); 839 840 return Service->hServiceStatus; 841 } 842 843 844 /********************************************************************** 845 * I_ScIsSecurityProcess 846 * 847 * Undocumented 848 * 849 * @implemented 850 */ 851 VOID 852 WINAPI 853 I_ScIsSecurityProcess(VOID) 854 { 855 TRACE("I_ScIsSecurityProcess()\n"); 856 bSecurityServiceProcess = TRUE; 857 } 858 859 860 /********************************************************************** 861 * I_ScPnPGetServiceName 862 * 863 * Undocumented 864 * 865 * @implemented 866 */ 867 DWORD 868 WINAPI 869 I_ScPnPGetServiceName(IN SERVICE_STATUS_HANDLE hServiceStatus, 870 OUT LPWSTR lpServiceName, 871 IN DWORD cchServiceName) 872 { 873 DWORD i; 874 875 TRACE("I_ScPnPGetServiceName(%lu %p %lu)\n", 876 hServiceStatus, lpServiceName, cchServiceName); 877 878 for (i = 0; i < dwActiveServiceCount; i++) 879 { 880 if (lpActiveServices[i].hServiceStatus == hServiceStatus) 881 { 882 wcscpy(lpServiceName, lpActiveServices[i].ServiceName.Buffer); 883 return ERROR_SUCCESS; 884 } 885 } 886 887 return ERROR_SERVICE_NOT_IN_EXE; 888 } 889 890 891 /********************************************************************** 892 * I_ScSetServiceBitsA 893 * 894 * Undocumented 895 * 896 * @implemented 897 */ 898 BOOL WINAPI 899 I_ScSetServiceBitsA(SERVICE_STATUS_HANDLE hServiceStatus, 900 DWORD dwServiceBits, 901 BOOL bSetBitsOn, 902 BOOL bUpdateImmediately, 903 LPSTR lpString) 904 { 905 BOOL bResult; 906 907 TRACE("I_ScSetServiceBitsA(%lu %lx %u %u %s)\n", 908 hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately, 909 debugstr_a(lpString)); 910 911 RpcTryExcept 912 { 913 bResult = RI_ScSetServiceBitsA((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 914 dwServiceBits, 915 bSetBitsOn, 916 bUpdateImmediately, 917 lpString); 918 } 919 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 920 { 921 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 922 bResult = FALSE; 923 } 924 RpcEndExcept; 925 926 return bResult; 927 } 928 929 930 /********************************************************************** 931 * I_ScSetServiceBitsW 932 * 933 * Undocumented 934 * 935 * @implemented 936 */ 937 BOOL WINAPI 938 I_ScSetServiceBitsW(SERVICE_STATUS_HANDLE hServiceStatus, 939 DWORD dwServiceBits, 940 BOOL bSetBitsOn, 941 BOOL bUpdateImmediately, 942 LPWSTR lpString) 943 { 944 BOOL bResult; 945 946 TRACE("I_ScSetServiceBitsW(%lu %lx %u %u %s)\n", 947 hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately, 948 debugstr_w(lpString)); 949 950 RpcTryExcept 951 { 952 bResult = RI_ScSetServiceBitsW((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 953 dwServiceBits, 954 bSetBitsOn, 955 bUpdateImmediately, 956 lpString); 957 } 958 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 959 { 960 SetLastError(ScmRpcStatusToWinError(RpcExceptionCode())); 961 bResult = FALSE; 962 } 963 RpcEndExcept; 964 965 return bResult; 966 } 967 968 969 /********************************************************************** 970 * SetServiceBits 971 * 972 * @implemented 973 */ 974 BOOL WINAPI 975 SetServiceBits(SERVICE_STATUS_HANDLE hServiceStatus, 976 DWORD dwServiceBits, 977 BOOL bSetBitsOn, 978 BOOL bUpdateImmediately) 979 { 980 TRACE("SetServiceBits(%lu %lx %u %u)\n", 981 hServiceStatus, dwServiceBits, bSetBitsOn, bUpdateImmediately); 982 983 return I_ScSetServiceBitsW(hServiceStatus, 984 dwServiceBits, 985 bSetBitsOn, 986 bUpdateImmediately, 987 NULL); 988 } 989 990 991 /********************************************************************** 992 * SetServiceStatus 993 * 994 * @implemented 995 */ 996 BOOL WINAPI 997 SetServiceStatus(SERVICE_STATUS_HANDLE hServiceStatus, 998 LPSERVICE_STATUS lpServiceStatus) 999 { 1000 DWORD dwError; 1001 1002 TRACE("SetServiceStatus(%lu %p)\n", 1003 hServiceStatus, lpServiceStatus); 1004 1005 RpcTryExcept 1006 { 1007 dwError = RSetServiceStatus((RPC_SERVICE_STATUS_HANDLE)hServiceStatus, 1008 lpServiceStatus); 1009 } 1010 RpcExcept(EXCEPTION_EXECUTE_HANDLER) 1011 { 1012 dwError = ScmRpcStatusToWinError(RpcExceptionCode()); 1013 } 1014 RpcEndExcept; 1015 1016 if (dwError != ERROR_SUCCESS) 1017 { 1018 ERR("RSetServiceStatus() failed (Error %lu)\n", dwError); 1019 SetLastError(dwError); 1020 return FALSE; 1021 } 1022 1023 TRACE("SetServiceStatus() done\n"); 1024 1025 return TRUE; 1026 } 1027 1028 1029 /********************************************************************** 1030 * StartServiceCtrlDispatcherA 1031 * 1032 * @implemented 1033 */ 1034 BOOL WINAPI 1035 StartServiceCtrlDispatcherA(const SERVICE_TABLE_ENTRYA *lpServiceStartTable) 1036 { 1037 ULONG i; 1038 HANDLE hPipe; 1039 DWORD dwError; 1040 PSCM_CONTROL_PACKET ControlPacket; 1041 DWORD dwBufSize; 1042 BOOL bRet = TRUE; 1043 1044 TRACE("StartServiceCtrlDispatcherA(%p)\n", 1045 lpServiceStartTable); 1046 1047 i = 0; 1048 while (lpServiceStartTable[i].lpServiceProc != NULL) 1049 { 1050 i++; 1051 } 1052 1053 dwActiveServiceCount = i; 1054 1055 /* Allocate the service table */ 1056 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 1057 HEAP_ZERO_MEMORY, 1058 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 1059 if (lpActiveServices == NULL) 1060 { 1061 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1062 return FALSE; 1063 } 1064 1065 /* Copy service names and start procedure */ 1066 for (i = 0; i < dwActiveServiceCount; i++) 1067 { 1068 RtlCreateUnicodeStringFromAsciiz(&lpActiveServices[i].ServiceName, 1069 lpServiceStartTable[i].lpServiceName); 1070 lpActiveServices[i].ServiceMain.A = lpServiceStartTable[i].lpServiceProc; 1071 lpActiveServices[i].hServiceStatus = NULL; 1072 lpActiveServices[i].bUnicode = FALSE; 1073 lpActiveServices[i].bOwnProcess = FALSE; 1074 } 1075 1076 /* Connect to the SCM */ 1077 dwError = ScConnectControlPipe(&hPipe); 1078 if (dwError != ERROR_SUCCESS) 1079 { 1080 bRet = FALSE; 1081 goto done; 1082 } 1083 1084 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 1085 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 1086 1087 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 1088 HEAP_ZERO_MEMORY, 1089 dwBufSize); 1090 if (ControlPacket == NULL) 1091 { 1092 dwError = ERROR_NOT_ENOUGH_MEMORY; 1093 bRet = FALSE; 1094 goto done; 1095 } 1096 1097 ScCreateStatusBinding(); 1098 1099 /* Call the dispatcher loop */ 1100 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1101 1102 1103 ScDestroyStatusBinding(); 1104 1105 /* Close the connection */ 1106 CloseHandle(hPipe); 1107 1108 /* Free the control packet */ 1109 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1110 1111 done: 1112 /* Free the service table */ 1113 for (i = 0; i < dwActiveServiceCount; i++) 1114 { 1115 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1116 } 1117 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1118 lpActiveServices = NULL; 1119 dwActiveServiceCount = 0; 1120 1121 if (!bRet) 1122 SetLastError(dwError); 1123 1124 return bRet; 1125 } 1126 1127 1128 /********************************************************************** 1129 * StartServiceCtrlDispatcherW 1130 * 1131 * @implemented 1132 */ 1133 BOOL WINAPI 1134 StartServiceCtrlDispatcherW(const SERVICE_TABLE_ENTRYW *lpServiceStartTable) 1135 { 1136 ULONG i; 1137 HANDLE hPipe; 1138 DWORD dwError; 1139 PSCM_CONTROL_PACKET ControlPacket; 1140 DWORD dwBufSize; 1141 BOOL bRet = TRUE; 1142 1143 TRACE("StartServiceCtrlDispatcherW(%p)\n", 1144 lpServiceStartTable); 1145 1146 i = 0; 1147 while (lpServiceStartTable[i].lpServiceProc != NULL) 1148 { 1149 i++; 1150 } 1151 1152 dwActiveServiceCount = i; 1153 1154 /* Allocate the service table */ 1155 lpActiveServices = RtlAllocateHeap(RtlGetProcessHeap(), 1156 HEAP_ZERO_MEMORY, 1157 dwActiveServiceCount * sizeof(ACTIVE_SERVICE)); 1158 if (lpActiveServices == NULL) 1159 { 1160 SetLastError(ERROR_NOT_ENOUGH_MEMORY); 1161 return FALSE; 1162 } 1163 1164 /* Copy service names and start procedure */ 1165 for (i = 0; i < dwActiveServiceCount; i++) 1166 { 1167 RtlCreateUnicodeString(&lpActiveServices[i].ServiceName, 1168 lpServiceStartTable[i].lpServiceName); 1169 lpActiveServices[i].ServiceMain.W = lpServiceStartTable[i].lpServiceProc; 1170 lpActiveServices[i].hServiceStatus = NULL; 1171 lpActiveServices[i].bUnicode = TRUE; 1172 lpActiveServices[i].bOwnProcess = FALSE; 1173 } 1174 1175 /* Connect to the SCM */ 1176 dwError = ScConnectControlPipe(&hPipe); 1177 if (dwError != ERROR_SUCCESS) 1178 { 1179 bRet = FALSE; 1180 goto done; 1181 } 1182 1183 dwBufSize = sizeof(SCM_CONTROL_PACKET) + 1184 (MAX_SERVICE_NAME_LENGTH + 1) * sizeof(WCHAR); 1185 1186 ControlPacket = RtlAllocateHeap(RtlGetProcessHeap(), 1187 HEAP_ZERO_MEMORY, 1188 dwBufSize); 1189 if (ControlPacket == NULL) 1190 { 1191 dwError = ERROR_NOT_ENOUGH_MEMORY; 1192 bRet = FALSE; 1193 goto done; 1194 } 1195 1196 ScCreateStatusBinding(); 1197 1198 /* Call the dispatcher loop */ 1199 ScServiceDispatcher(hPipe, ControlPacket, dwBufSize); 1200 1201 ScDestroyStatusBinding(); 1202 1203 /* Close the connection */ 1204 CloseHandle(hPipe); 1205 1206 /* Free the control packet */ 1207 RtlFreeHeap(RtlGetProcessHeap(), 0, ControlPacket); 1208 1209 done: 1210 /* Free the service table */ 1211 for (i = 0; i < dwActiveServiceCount; i++) 1212 { 1213 RtlFreeUnicodeString(&lpActiveServices[i].ServiceName); 1214 } 1215 RtlFreeHeap(RtlGetProcessHeap(), 0, lpActiveServices); 1216 lpActiveServices = NULL; 1217 dwActiveServiceCount = 0; 1218 1219 if (!bRet) 1220 SetLastError(dwError); 1221 1222 return bRet; 1223 } 1224 1225 /* EOF */ 1226