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