[CMAKE]
[reactos.git] / base / system / services / rpcserver.c
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 #include "svcctl_s.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS *****************************************************************/
20
21 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
22 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
23
24 typedef struct _SCMGR_HANDLE
25 {
26 DWORD Tag;
27 DWORD DesiredAccess;
28 } SCMGR_HANDLE;
29
30
31 typedef struct _MANAGER_HANDLE
32 {
33 SCMGR_HANDLE Handle;
34 WCHAR DatabaseName[1];
35 } MANAGER_HANDLE, *PMANAGER_HANDLE;
36
37
38 typedef struct _SERVICE_HANDLE
39 {
40 SCMGR_HANDLE Handle;
41 PSERVICE ServiceEntry;
42 } SERVICE_HANDLE, *PSERVICE_HANDLE;
43
44
45 #define SC_MANAGER_READ \
46 (STANDARD_RIGHTS_READ | \
47 SC_MANAGER_QUERY_LOCK_STATUS | \
48 SC_MANAGER_ENUMERATE_SERVICE)
49
50 #define SC_MANAGER_WRITE \
51 (STANDARD_RIGHTS_WRITE | \
52 SC_MANAGER_MODIFY_BOOT_CONFIG | \
53 SC_MANAGER_CREATE_SERVICE)
54
55 #define SC_MANAGER_EXECUTE \
56 (STANDARD_RIGHTS_EXECUTE | \
57 SC_MANAGER_LOCK | \
58 SC_MANAGER_ENUMERATE_SERVICE | \
59 SC_MANAGER_CONNECT | \
60 SC_MANAGER_CREATE_SERVICE)
61
62
63 #define SERVICE_READ \
64 (STANDARD_RIGHTS_READ | \
65 SERVICE_INTERROGATE | \
66 SERVICE_ENUMERATE_DEPENDENTS | \
67 SERVICE_QUERY_STATUS | \
68 SERVICE_QUERY_CONFIG)
69
70 #define SERVICE_WRITE \
71 (STANDARD_RIGHTS_WRITE | \
72 SERVICE_CHANGE_CONFIG)
73
74 #define SERVICE_EXECUTE \
75 (STANDARD_RIGHTS_EXECUTE | \
76 SERVICE_USER_DEFINED_CONTROL | \
77 SERVICE_PAUSE_CONTINUE | \
78 SERVICE_STOP | \
79 SERVICE_START)
80
81
82 /* VARIABLES ***************************************************************/
83
84 static GENERIC_MAPPING
85 ScmManagerMapping = {SC_MANAGER_READ,
86 SC_MANAGER_WRITE,
87 SC_MANAGER_EXECUTE,
88 SC_MANAGER_ALL_ACCESS};
89
90 static GENERIC_MAPPING
91 ScmServiceMapping = {SERVICE_READ,
92 SERVICE_WRITE,
93 SERVICE_EXECUTE,
94 SC_MANAGER_ALL_ACCESS};
95
96
97 /* FUNCTIONS ***************************************************************/
98
99 VOID
100 ScmStartRpcServer(VOID)
101 {
102 RPC_STATUS Status;
103
104 DPRINT("ScmStartRpcServer() called\n");
105
106 Status = RpcServerUseProtseqEpW(L"ncacn_np",
107 10,
108 L"\\pipe\\ntsvcs",
109 NULL);
110 if (Status != RPC_S_OK)
111 {
112 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
113 return;
114 }
115
116 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
117 NULL,
118 NULL);
119 if (Status != RPC_S_OK)
120 {
121 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
122 return;
123 }
124
125 Status = RpcServerListen(1, 20, TRUE);
126 if (Status != RPC_S_OK)
127 {
128 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
129 return;
130 }
131
132 DPRINT("ScmStartRpcServer() done\n");
133 }
134
135
136 static DWORD
137 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
138 SC_HANDLE *Handle)
139 {
140 PMANAGER_HANDLE Ptr;
141
142 if (lpDatabaseName == NULL)
143 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
144
145 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
146 {
147 DPRINT("Database %S, does not exist\n",lpDatabaseName);
148 return ERROR_DATABASE_DOES_NOT_EXIST;
149 }
150 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
151 {
152 DPRINT("Invalid Database name %S.\n",lpDatabaseName);
153 return ERROR_INVALID_NAME;
154 }
155
156 Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
157 HEAP_ZERO_MEMORY,
158 sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
159 if (Ptr == NULL)
160 return ERROR_NOT_ENOUGH_MEMORY;
161
162 Ptr->Handle.Tag = MANAGER_TAG;
163
164 wcscpy(Ptr->DatabaseName, lpDatabaseName);
165
166 *Handle = (SC_HANDLE)Ptr;
167
168 return ERROR_SUCCESS;
169 }
170
171
172 static DWORD
173 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
174 SC_HANDLE *Handle)
175 {
176 PSERVICE_HANDLE Ptr;
177
178 Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
179 HEAP_ZERO_MEMORY,
180 sizeof(SERVICE_HANDLE));
181 if (Ptr == NULL)
182 return ERROR_NOT_ENOUGH_MEMORY;
183
184 Ptr->Handle.Tag = SERVICE_TAG;
185
186 Ptr->ServiceEntry = lpServiceEntry;
187
188 *Handle = (SC_HANDLE)Ptr;
189
190 return ERROR_SUCCESS;
191 }
192
193
194 static PMANAGER_HANDLE
195 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
196 {
197 PMANAGER_HANDLE pManager = NULL;
198
199 _SEH2_TRY
200 {
201 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
202 pManager = (PMANAGER_HANDLE)Handle;
203 }
204 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
205 {
206 DPRINT1("Exception: Invalid Service Manager handle!\n");
207 }
208 _SEH2_END;
209
210 return pManager;
211 }
212
213
214 static PSERVICE_HANDLE
215 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
216 {
217 PSERVICE_HANDLE pService = NULL;
218
219 _SEH2_TRY
220 {
221 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
222 pService = (PSERVICE_HANDLE)Handle;
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 DPRINT1("Exception: Invalid Service handle!\n");
227 }
228 _SEH2_END;
229
230 return pService;
231 }
232
233
234 static DWORD
235 ScmCheckAccess(SC_HANDLE Handle,
236 DWORD dwDesiredAccess)
237 {
238 PMANAGER_HANDLE hMgr;
239
240 hMgr = (PMANAGER_HANDLE)Handle;
241 if (hMgr->Handle.Tag == MANAGER_TAG)
242 {
243 RtlMapGenericMask(&dwDesiredAccess,
244 &ScmManagerMapping);
245
246 hMgr->Handle.DesiredAccess = dwDesiredAccess;
247
248 return ERROR_SUCCESS;
249 }
250 else if (hMgr->Handle.Tag == SERVICE_TAG)
251 {
252 RtlMapGenericMask(&dwDesiredAccess,
253 &ScmServiceMapping);
254
255 hMgr->Handle.DesiredAccess = dwDesiredAccess;
256
257 return ERROR_SUCCESS;
258 }
259
260 return ERROR_INVALID_HANDLE;
261 }
262
263
264 DWORD
265 ScmAssignNewTag(PSERVICE lpService)
266 {
267 /* FIXME */
268 DPRINT("Assigning new tag to service %S\n", lpService->lpServiceName);
269 lpService->dwTag = 0;
270 return ERROR_SUCCESS;
271 }
272
273
274 /* Internal recursive function */
275 /* Need to search for every dependency on every service */
276 static DWORD
277 Int_EnumDependentServicesW(HKEY hServicesKey,
278 PSERVICE lpService,
279 DWORD dwServiceState,
280 PSERVICE *lpServices,
281 LPDWORD pcbBytesNeeded,
282 LPDWORD lpServicesReturned)
283 {
284 DWORD dwError = ERROR_SUCCESS;
285 WCHAR szNameBuf[MAX_PATH];
286 WCHAR szValueBuf[MAX_PATH];
287 WCHAR *lpszNameBuf = szNameBuf;
288 WCHAR *lpszValueBuf = szValueBuf;
289 DWORD dwSize;
290 DWORD dwNumSubKeys;
291 DWORD dwIteration;
292 PSERVICE lpCurrentService;
293 HKEY hServiceEnumKey;
294 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
295 DWORD dwDependServiceStrPtr = 0;
296 DWORD dwRequiredSize = 0;
297
298 /* Get the number of service keys */
299 dwError = RegQueryInfoKeyW(hServicesKey,
300 NULL,
301 NULL,
302 NULL,
303 &dwNumSubKeys,
304 NULL,
305 NULL,
306 NULL,
307 NULL,
308 NULL,
309 NULL,
310 NULL);
311 if (dwError != ERROR_SUCCESS)
312 {
313 DPRINT("ERROR! Unable to get number of services keys.\n");
314 return dwError;
315 }
316
317 /* Iterate the service keys to see if another service depends on the this service */
318 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
319 {
320 dwSize = MAX_PATH;
321 dwError = RegEnumKeyExW(hServicesKey,
322 dwIteration,
323 lpszNameBuf,
324 &dwSize,
325 NULL,
326 NULL,
327 NULL,
328 NULL);
329 if (dwError != ERROR_SUCCESS)
330 return dwError;
331
332 /* Open the Service key */
333 dwError = RegOpenKeyExW(hServicesKey,
334 lpszNameBuf,
335 0,
336 KEY_READ,
337 &hServiceEnumKey);
338 if (dwError != ERROR_SUCCESS)
339 return dwError;
340
341 dwSize = MAX_PATH;
342
343 /* Check for the DependOnService Value */
344 dwError = RegQueryValueExW(hServiceEnumKey,
345 L"DependOnService",
346 NULL,
347 NULL,
348 (LPBYTE)lpszValueBuf,
349 &dwSize);
350
351 /* FIXME: Handle load order. */
352
353 /* If the service found has a DependOnService value */
354 if (dwError == ERROR_SUCCESS)
355 {
356 dwDependServiceStrPtr = 0;
357
358 /* Can be more than one Dependencies in the DependOnService string */
359 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
360 {
361 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
362 {
363 /* Get the current enumed service pointer */
364 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
365
366 /* Check for valid Service */
367 if (!lpCurrentService)
368 {
369 /* This should never happen! */
370 DPRINT("This should not happen at this point, report to Developer\n");
371 return ERROR_NOT_FOUND;
372 }
373
374 /* Determine state the service is in */
375 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
376 dwCurrentServiceState = SERVICE_INACTIVE;
377
378 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
379 if ((dwCurrentServiceState == dwServiceState) ||
380 (dwServiceState == SERVICE_STATE_ALL))
381 {
382 /* Calculate the required size */
383 dwRequiredSize += sizeof(SERVICE_STATUS);
384 dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
385 dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
386
387 /* Add the size for service name and display name pointers */
388 dwRequiredSize += (2 * sizeof(PVOID));
389
390 /* increase the BytesNeeded size */
391 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
392
393 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
394 comes first */
395
396 /* Recursive call to check for its dependencies */
397 Int_EnumDependentServicesW(hServicesKey,
398 lpCurrentService,
399 dwServiceState,
400 lpServices,
401 pcbBytesNeeded,
402 lpServicesReturned);
403
404 /* If the lpServices is valid set the service pointer */
405 if (lpServices)
406 lpServices[*lpServicesReturned] = lpCurrentService;
407
408 *lpServicesReturned = *lpServicesReturned + 1;
409 }
410 }
411
412 dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
413 }
414 }
415 else if (*pcbBytesNeeded)
416 {
417 dwError = ERROR_SUCCESS;
418 }
419
420 RegCloseKey(hServiceEnumKey);
421 }
422
423 return dwError;
424 }
425
426
427 /* Function 0 */
428 DWORD RCloseServiceHandle(
429 LPSC_RPC_HANDLE hSCObject)
430 {
431 PMANAGER_HANDLE hManager;
432 PSERVICE_HANDLE hService;
433 PSERVICE lpService;
434 HKEY hServicesKey;
435 DWORD dwError;
436 DWORD pcbBytesNeeded = 0;
437 DWORD dwServicesReturned = 0;
438
439 DPRINT("RCloseServiceHandle() called\n");
440
441 DPRINT("hSCObject = %p\n", *hSCObject);
442
443 if (*hSCObject == 0)
444 return ERROR_INVALID_HANDLE;
445
446 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
447 hService = ScmGetServiceFromHandle(*hSCObject);
448
449 if (hManager != NULL)
450 {
451 DPRINT("Found manager handle\n");
452
453 /* FIXME: add handle cleanup code */
454
455 HeapFree(GetProcessHeap(), 0, hManager);
456 hManager = NULL;
457
458 DPRINT("RCloseServiceHandle() done\n");
459 return ERROR_SUCCESS;
460 }
461 else if (hService != NULL)
462 {
463 DPRINT("Found service handle\n");
464
465 /* Get the pointer to the service record */
466 lpService = hService->ServiceEntry;
467
468 /* FIXME: add handle cleanup code */
469
470 /* Free the handle */
471 HeapFree(GetProcessHeap(), 0, hService);
472 hService = NULL;
473
474 ASSERT(lpService->dwRefCount > 0);
475
476 lpService->dwRefCount--;
477 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
478 lpService->dwRefCount);
479
480 if (lpService->dwRefCount == 0)
481 {
482 /* If this service has been marked for deletion */
483 if (lpService->bDeleted)
484 {
485 /* Open the Services Reg key */
486 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
487 L"System\\CurrentControlSet\\Services",
488 0,
489 KEY_SET_VALUE | KEY_READ,
490 &hServicesKey);
491 if (dwError != ERROR_SUCCESS)
492 {
493 DPRINT("Failed to open services key\n");
494 return dwError;
495 }
496
497 /* Call the internal function with NULL, just to get bytes we need */
498 Int_EnumDependentServicesW(hServicesKey,
499 lpService,
500 SERVICE_ACTIVE,
501 NULL,
502 &pcbBytesNeeded,
503 &dwServicesReturned);
504
505 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
506 if (pcbBytesNeeded)
507 {
508 DPRINT("Deletion failed due to running dependencies.\n");
509 RegCloseKey(hServicesKey);
510 return ERROR_SUCCESS;
511 }
512
513 /* There are no references and no runnning dependencies,
514 it is now safe to delete the service */
515
516 /* Delete the Service Key */
517 dwError = RegDeleteKeyW(hServicesKey,
518 lpService->lpServiceName);
519
520 RegCloseKey(hServicesKey);
521
522 if (dwError != ERROR_SUCCESS)
523 {
524 DPRINT("Failed to Delete the Service Registry key\n");
525 return dwError;
526 }
527
528 /* Delete the Service */
529 ScmDeleteServiceRecord(lpService);
530 }
531 }
532
533 DPRINT("RCloseServiceHandle() done\n");
534 return ERROR_SUCCESS;
535 }
536
537 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
538
539 return ERROR_INVALID_HANDLE;
540 }
541
542
543 /* Function 1 */
544 DWORD RControlService(
545 SC_RPC_HANDLE hService,
546 DWORD dwControl,
547 LPSERVICE_STATUS lpServiceStatus)
548 {
549 PSERVICE_HANDLE hSvc;
550 PSERVICE lpService;
551 ACCESS_MASK DesiredAccess;
552 DWORD dwError = ERROR_SUCCESS;
553 DWORD pcbBytesNeeded = 0;
554 DWORD dwServicesReturned = 0;
555 DWORD dwControlsAccepted;
556 DWORD dwCurrentState;
557 HKEY hServicesKey = NULL;
558
559 DPRINT("RControlService() called\n");
560
561 if (ScmShutdown)
562 return ERROR_SHUTDOWN_IN_PROGRESS;
563
564 /* Check the service handle */
565 hSvc = ScmGetServiceFromHandle(hService);
566 if (hSvc == NULL)
567 {
568 DPRINT1("Invalid service handle!\n");
569 return ERROR_INVALID_HANDLE;
570 }
571
572
573 /* Check the service entry point */
574 lpService = hSvc->ServiceEntry;
575 if (lpService == NULL)
576 {
577 DPRINT1("lpService == NULL!\n");
578 return ERROR_INVALID_HANDLE;
579 }
580
581 /* Check access rights */
582 switch (dwControl)
583 {
584 case SERVICE_CONTROL_STOP:
585 DesiredAccess = SERVICE_STOP;
586 break;
587
588 case SERVICE_CONTROL_PAUSE:
589 case SERVICE_CONTROL_CONTINUE:
590 DesiredAccess = SERVICE_PAUSE_CONTINUE;
591 break;
592
593 case SERVICE_INTERROGATE:
594 DesiredAccess = SERVICE_INTERROGATE;
595 break;
596
597 default:
598 if (dwControl >= 128 && dwControl <= 255)
599 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
600 else
601 DesiredAccess = SERVICE_QUERY_CONFIG |
602 SERVICE_CHANGE_CONFIG |
603 SERVICE_QUERY_STATUS |
604 SERVICE_START |
605 SERVICE_PAUSE_CONTINUE;
606 break;
607 }
608
609 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
610 DesiredAccess))
611 return ERROR_ACCESS_DENIED;
612
613 if (dwControl == SERVICE_CONTROL_STOP)
614 {
615 /* Check if the service has dependencies running as windows
616 doesn't stop a service that does */
617
618 /* Open the Services Reg key */
619 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
620 L"System\\CurrentControlSet\\Services",
621 0,
622 KEY_READ,
623 &hServicesKey);
624 if (dwError != ERROR_SUCCESS)
625 {
626 DPRINT("Failed to open services key\n");
627 return dwError;
628 }
629
630 /* Call the internal function with NULL, just to get bytes we need */
631 Int_EnumDependentServicesW(hServicesKey,
632 lpService,
633 SERVICE_ACTIVE,
634 NULL,
635 &pcbBytesNeeded,
636 &dwServicesReturned);
637
638 RegCloseKey(hServicesKey);
639
640 /* If pcbBytesNeeded is not zero then there are services running that
641 are dependent on this service */
642 if (pcbBytesNeeded != 0)
643 {
644 DPRINT("Service has running dependencies. Failed to stop service.\n");
645 return ERROR_DEPENDENT_SERVICES_RUNNING;
646 }
647 }
648
649 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
650 {
651 /* Send control code to the driver */
652 dwError = ScmControlDriver(lpService,
653 dwControl,
654 lpServiceStatus);
655 }
656 else
657 {
658 dwControlsAccepted = lpService->Status.dwControlsAccepted;
659 dwCurrentState = lpService->Status.dwCurrentState;
660
661 /* Check the current state before sending a control request */
662 switch (dwCurrentState)
663 {
664 case SERVICE_STOP_PENDING:
665 case SERVICE_STOPPED:
666 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
667
668 case SERVICE_START_PENDING:
669 switch (dwControl)
670 {
671 case SERVICE_CONTROL_STOP:
672 break;
673
674 case SERVICE_CONTROL_INTERROGATE:
675 RtlCopyMemory(lpServiceStatus,
676 &lpService->Status,
677 sizeof(SERVICE_STATUS));
678 return ERROR_SUCCESS;
679
680 default:
681 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
682 }
683 break;
684 }
685
686 /* Check if the control code is acceptable to the service */
687 switch (dwControl)
688 {
689 case SERVICE_CONTROL_STOP:
690 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
691 return ERROR_INVALID_SERVICE_CONTROL;
692 break;
693
694 case SERVICE_CONTROL_PAUSE:
695 case SERVICE_CONTROL_CONTINUE:
696 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
697 return ERROR_INVALID_SERVICE_CONTROL;
698 break;
699 }
700
701 /* Send control code to the service */
702 dwError = ScmControlService(lpService,
703 dwControl);
704
705 /* Return service status information */
706 RtlCopyMemory(lpServiceStatus,
707 &lpService->Status,
708 sizeof(SERVICE_STATUS));
709 }
710
711 if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
712 dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
713
714 if (dwError == ERROR_SUCCESS &&
715 dwControl == SERVICE_CONTROL_STOP &&
716 lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
717 {
718 lpService->ProcessId = 0; /* FIXME */
719 lpService->ThreadId = 0;
720 }
721
722
723 return dwError;
724 }
725
726
727 /* Function 2 */
728 DWORD RDeleteService(
729 SC_RPC_HANDLE hService)
730 {
731 PSERVICE_HANDLE hSvc;
732 PSERVICE lpService;
733 DWORD dwError;
734
735 DPRINT("RDeleteService() called\n");
736
737 if (ScmShutdown)
738 return ERROR_SHUTDOWN_IN_PROGRESS;
739
740 hSvc = ScmGetServiceFromHandle(hService);
741 if (hSvc == NULL)
742 {
743 DPRINT1("Invalid service handle!\n");
744 return ERROR_INVALID_HANDLE;
745 }
746
747 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
748 DELETE))
749 return ERROR_ACCESS_DENIED;
750
751 lpService = hSvc->ServiceEntry;
752 if (lpService == NULL)
753 {
754 DPRINT("lpService == NULL!\n");
755 return ERROR_INVALID_HANDLE;
756 }
757
758 /* FIXME: Acquire service database lock exclusively */
759
760 if (lpService->bDeleted)
761 {
762 DPRINT("The service has already been marked for delete!\n");
763 return ERROR_SERVICE_MARKED_FOR_DELETE;
764 }
765
766 /* Mark service for delete */
767 lpService->bDeleted = TRUE;
768
769 dwError = ScmMarkServiceForDelete(lpService);
770
771 /* FIXME: Release service database lock */
772
773 DPRINT("RDeleteService() done\n");
774
775 return dwError;
776 }
777
778
779 /* Function 3 */
780 DWORD RLockServiceDatabase(
781 SC_RPC_HANDLE hSCManager,
782 LPSC_RPC_LOCK lpLock)
783 {
784 PMANAGER_HANDLE hMgr;
785
786 DPRINT("RLockServiceDatabase() called\n");
787
788 *lpLock = 0;
789
790 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
791 if (hMgr == NULL)
792 {
793 DPRINT1("Invalid service manager handle!\n");
794 return ERROR_INVALID_HANDLE;
795 }
796
797 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
798 SC_MANAGER_LOCK))
799 return ERROR_ACCESS_DENIED;
800
801 // return ScmLockDatabase(0, hMgr->0xC, hLock);
802
803 /* FIXME: Lock the database */
804 *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
805
806 return ERROR_SUCCESS;
807 }
808
809
810 /* Function 4 */
811 DWORD RQueryServiceObjectSecurity(
812 SC_RPC_HANDLE hService,
813 SECURITY_INFORMATION dwSecurityInformation,
814 LPBYTE lpSecurityDescriptor,
815 DWORD cbBufSize,
816 LPBOUNDED_DWORD_256K pcbBytesNeeded)
817 {
818 PSERVICE_HANDLE hSvc;
819 PSERVICE lpService;
820 ULONG DesiredAccess = 0;
821 NTSTATUS Status;
822 DWORD dwBytesNeeded;
823 DWORD dwError;
824
825
826 SECURITY_DESCRIPTOR ObjectDescriptor;
827
828 DPRINT("RQueryServiceObjectSecurity() called\n");
829
830 hSvc = ScmGetServiceFromHandle(hService);
831 if (hSvc == NULL)
832 {
833 DPRINT1("Invalid service handle!\n");
834 return ERROR_INVALID_HANDLE;
835 }
836
837 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
838 GROUP_SECURITY_INFORMATION |
839 OWNER_SECURITY_INFORMATION))
840 DesiredAccess |= READ_CONTROL;
841
842 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
843 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
844
845 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
846 DesiredAccess))
847 {
848 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
849 return ERROR_ACCESS_DENIED;
850 }
851
852 lpService = hSvc->ServiceEntry;
853 if (lpService == NULL)
854 {
855 DPRINT("lpService == NULL!\n");
856 return ERROR_INVALID_HANDLE;
857 }
858
859 /* FIXME: Lock the service list */
860
861 /* hack */
862 Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
863
864 Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
865 dwSecurityInformation,
866 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
867 cbBufSize,
868 &dwBytesNeeded);
869
870 /* FIXME: Unlock the service list */
871
872 if (NT_SUCCESS(Status))
873 {
874 *pcbBytesNeeded = dwBytesNeeded;
875 dwError = STATUS_SUCCESS;
876 }
877 else if (Status == STATUS_BUFFER_TOO_SMALL)
878 {
879 *pcbBytesNeeded = dwBytesNeeded;
880 dwError = ERROR_INSUFFICIENT_BUFFER;
881 }
882 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
883 {
884 dwError = ERROR_GEN_FAILURE;
885 }
886 else
887 {
888 dwError = RtlNtStatusToDosError(Status);
889 }
890
891 return dwError;
892 }
893
894
895 /* Function 5 */
896 DWORD RSetServiceObjectSecurity(
897 SC_RPC_HANDLE hService,
898 DWORD dwSecurityInformation,
899 LPBYTE lpSecurityDescriptor,
900 DWORD dwSecuityDescriptorSize)
901 {
902 PSERVICE_HANDLE hSvc;
903 PSERVICE lpService;
904 ULONG DesiredAccess = 0;
905 /* HANDLE hToken = NULL; */
906 HKEY hServiceKey;
907 /* NTSTATUS Status; */
908 DWORD dwError;
909
910 DPRINT("RSetServiceObjectSecurity() called\n");
911
912 hSvc = ScmGetServiceFromHandle(hService);
913 if (hSvc == NULL)
914 {
915 DPRINT1("Invalid service handle!\n");
916 return ERROR_INVALID_HANDLE;
917 }
918
919 if (dwSecurityInformation == 0 ||
920 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
921 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
922 return ERROR_INVALID_PARAMETER;
923
924 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
925 return ERROR_INVALID_PARAMETER;
926
927 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
928 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
929
930 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
931 DesiredAccess |= WRITE_DAC;
932
933 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
934 DesiredAccess |= WRITE_OWNER;
935
936 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
937 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
938 return ERROR_INVALID_PARAMETER;
939
940 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
941 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
942 return ERROR_INVALID_PARAMETER;
943
944 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
945 DesiredAccess))
946 {
947 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
948 return ERROR_ACCESS_DENIED;
949 }
950
951 lpService = hSvc->ServiceEntry;
952 if (lpService == NULL)
953 {
954 DPRINT("lpService == NULL!\n");
955 return ERROR_INVALID_HANDLE;
956 }
957
958 if (lpService->bDeleted)
959 return ERROR_SERVICE_MARKED_FOR_DELETE;
960
961 #if 0
962 RpcImpersonateClient(NULL);
963
964 Status = NtOpenThreadToken(NtCurrentThread(),
965 8,
966 TRUE,
967 &hToken);
968 if (!NT_SUCCESS(Status))
969 return RtlNtStatusToDosError(Status);
970
971 RpcRevertToSelf();
972
973 /* FIXME: Lock service database */
974
975 Status = RtlSetSecurityObject(dwSecurityInformation,
976 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
977 &lpService->lpSecurityDescriptor,
978 &ScmServiceMapping,
979 hToken);
980 if (!NT_SUCCESS(Status))
981 {
982 dwError = RtlNtStatusToDosError(Status);
983 goto Done;
984 }
985 #endif
986
987 dwError = ScmOpenServiceKey(lpService->lpServiceName,
988 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
989 &hServiceKey);
990 if (dwError != ERROR_SUCCESS)
991 goto Done;
992
993 UNIMPLEMENTED;
994 dwError = ERROR_SUCCESS;
995 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
996 // lpService->lpSecurityDescriptor);
997
998 RegFlushKey(hServiceKey);
999 RegCloseKey(hServiceKey);
1000
1001 Done:
1002
1003 #if 0
1004 if (hToken != NULL)
1005 NtClose(hToken);
1006 #endif
1007
1008 /* FIXME: Unlock service database */
1009
1010 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1011
1012 return dwError;
1013 }
1014
1015
1016 /* Function 6 */
1017 DWORD RQueryServiceStatus(
1018 SC_RPC_HANDLE hService,
1019 LPSERVICE_STATUS lpServiceStatus)
1020 {
1021 PSERVICE_HANDLE hSvc;
1022 PSERVICE lpService;
1023
1024 DPRINT("RQueryServiceStatus() called\n");
1025
1026 if (ScmShutdown)
1027 return ERROR_SHUTDOWN_IN_PROGRESS;
1028
1029 hSvc = ScmGetServiceFromHandle(hService);
1030 if (hSvc == NULL)
1031 {
1032 DPRINT1("Invalid service handle!\n");
1033 return ERROR_INVALID_HANDLE;
1034 }
1035
1036 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1037 SERVICE_QUERY_STATUS))
1038 {
1039 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1040 return ERROR_ACCESS_DENIED;
1041 }
1042
1043 lpService = hSvc->ServiceEntry;
1044 if (lpService == NULL)
1045 {
1046 DPRINT("lpService == NULL!\n");
1047 return ERROR_INVALID_HANDLE;
1048 }
1049
1050 ScmLockDatabaseShared();
1051
1052 /* Return service status information */
1053 RtlCopyMemory(lpServiceStatus,
1054 &lpService->Status,
1055 sizeof(SERVICE_STATUS));
1056
1057 ScmUnlockDatabase();
1058
1059 return ERROR_SUCCESS;
1060 }
1061
1062
1063 static BOOL
1064 ScmIsValidServiceState(DWORD dwCurrentState)
1065 {
1066 switch (dwCurrentState)
1067 {
1068 case SERVICE_STOPPED:
1069 case SERVICE_START_PENDING:
1070 case SERVICE_STOP_PENDING:
1071 case SERVICE_RUNNING:
1072 case SERVICE_CONTINUE_PENDING:
1073 case SERVICE_PAUSE_PENDING:
1074 case SERVICE_PAUSED:
1075 return TRUE;
1076
1077 default:
1078 return FALSE;
1079 }
1080 }
1081
1082
1083 /* Function 7 */
1084 DWORD RSetServiceStatus(
1085 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1086 LPSERVICE_STATUS lpServiceStatus)
1087 {
1088 PSERVICE lpService;
1089
1090 DPRINT("RSetServiceStatus() called\n");
1091 DPRINT("hServiceStatus = %p\n", hServiceStatus);
1092 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1093 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1094 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1095 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1096 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1097 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1098 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1099
1100 if (hServiceStatus == 0)
1101 {
1102 DPRINT("hServiceStatus == NULL!\n");
1103 return ERROR_INVALID_HANDLE;
1104 }
1105
1106 lpService = (PSERVICE)hServiceStatus;
1107 if (lpService == NULL)
1108 {
1109 DPRINT("lpService == NULL!\n");
1110 return ERROR_INVALID_HANDLE;
1111 }
1112
1113 /* Check current state */
1114 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1115 {
1116 DPRINT("Invalid service state!\n");
1117 return ERROR_INVALID_DATA;
1118 }
1119
1120 /* Check service type */
1121 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1122 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1123 {
1124 DPRINT("Invalid service type!\n");
1125 return ERROR_INVALID_DATA;
1126 }
1127
1128 /* Check accepted controls */
1129 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1130 {
1131 DPRINT("Invalid controls accepted!\n");
1132 return ERROR_INVALID_DATA;
1133 }
1134
1135 ScmLockDatabaseExclusive();
1136
1137 RtlCopyMemory(&lpService->Status,
1138 lpServiceStatus,
1139 sizeof(SERVICE_STATUS));
1140
1141 ScmUnlockDatabase();
1142
1143 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1144 DPRINT("RSetServiceStatus() done\n");
1145
1146 return ERROR_SUCCESS;
1147 }
1148
1149
1150 /* Function 8 */
1151 DWORD RUnlockServiceDatabase(
1152 LPSC_RPC_LOCK Lock)
1153 {
1154 UNIMPLEMENTED;
1155 return ERROR_SUCCESS;
1156 }
1157
1158
1159 /* Function 9 */
1160 DWORD RNotifyBootConfigStatus(
1161 SVCCTL_HANDLEW lpMachineName,
1162 DWORD BootAcceptable)
1163 {
1164 UNIMPLEMENTED;
1165 return ERROR_CALL_NOT_IMPLEMENTED;
1166 }
1167
1168
1169 /* Function 10 */
1170 DWORD RI_ScSetServiceBitsW(
1171 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1172 DWORD dwServiceBits,
1173 int bSetBitsOn,
1174 int bUpdateImmediately,
1175 wchar_t *lpString)
1176 {
1177 UNIMPLEMENTED;
1178 return ERROR_CALL_NOT_IMPLEMENTED;
1179 }
1180
1181
1182 /* Function 11 */
1183 DWORD RChangeServiceConfigW(
1184 SC_RPC_HANDLE hService,
1185 DWORD dwServiceType,
1186 DWORD dwStartType,
1187 DWORD dwErrorControl,
1188 LPWSTR lpBinaryPathName,
1189 LPWSTR lpLoadOrderGroup,
1190 LPDWORD lpdwTagId,
1191 LPBYTE lpDependencies,
1192 DWORD dwDependSize,
1193 LPWSTR lpServiceStartName,
1194 LPBYTE lpPassword,
1195 DWORD dwPwSize,
1196 LPWSTR lpDisplayName)
1197 {
1198 DWORD dwError = ERROR_SUCCESS;
1199 PSERVICE_HANDLE hSvc;
1200 PSERVICE lpService = NULL;
1201 HKEY hServiceKey = NULL;
1202 LPWSTR lpDisplayNameW = NULL;
1203
1204 DPRINT("RChangeServiceConfigW() called\n");
1205 DPRINT("dwServiceType = %lu\n", dwServiceType);
1206 DPRINT("dwStartType = %lu\n", dwStartType);
1207 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1208 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1209 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1210 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1211
1212 if (ScmShutdown)
1213 return ERROR_SHUTDOWN_IN_PROGRESS;
1214
1215 hSvc = ScmGetServiceFromHandle(hService);
1216 if (hSvc == NULL)
1217 {
1218 DPRINT1("Invalid service handle!\n");
1219 return ERROR_INVALID_HANDLE;
1220 }
1221
1222 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1223 SERVICE_CHANGE_CONFIG))
1224 {
1225 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1226 return ERROR_ACCESS_DENIED;
1227 }
1228
1229 lpService = hSvc->ServiceEntry;
1230 if (lpService == NULL)
1231 {
1232 DPRINT("lpService == NULL!\n");
1233 return ERROR_INVALID_HANDLE;
1234 }
1235
1236 /* FIXME: Lock database exclusively */
1237
1238 if (lpService->bDeleted)
1239 {
1240 /* FIXME: Unlock database */
1241 DPRINT("The service has already been marked for delete!\n");
1242 return ERROR_SERVICE_MARKED_FOR_DELETE;
1243 }
1244
1245 /* Open the service key */
1246 dwError = ScmOpenServiceKey(lpService->szServiceName,
1247 KEY_SET_VALUE,
1248 &hServiceKey);
1249 if (dwError != ERROR_SUCCESS)
1250 goto done;
1251
1252 /* Write service data to the registry */
1253 /* Set the display name */
1254 if (lpDisplayName != NULL && *lpDisplayName != 0)
1255 {
1256 RegSetValueExW(hServiceKey,
1257 L"DisplayName",
1258 0,
1259 REG_SZ,
1260 (LPBYTE)lpDisplayName,
1261 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1262
1263 /* Update the display name */
1264 lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
1265 0,
1266 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1267 if (lpDisplayNameW == NULL)
1268 {
1269 dwError = ERROR_NOT_ENOUGH_MEMORY;
1270 goto done;
1271 }
1272
1273 if (lpService->lpDisplayName != lpService->lpServiceName)
1274 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1275
1276 lpService->lpDisplayName = lpDisplayNameW;
1277 }
1278
1279 if (dwServiceType != SERVICE_NO_CHANGE)
1280 {
1281 /* Set the service type */
1282 dwError = RegSetValueExW(hServiceKey,
1283 L"Type",
1284 0,
1285 REG_DWORD,
1286 (LPBYTE)&dwServiceType,
1287 sizeof(DWORD));
1288 if (dwError != ERROR_SUCCESS)
1289 goto done;
1290
1291 lpService->Status.dwServiceType = dwServiceType;
1292 }
1293
1294 if (dwStartType != SERVICE_NO_CHANGE)
1295 {
1296 /* Set the start value */
1297 dwError = RegSetValueExW(hServiceKey,
1298 L"Start",
1299 0,
1300 REG_DWORD,
1301 (LPBYTE)&dwStartType,
1302 sizeof(DWORD));
1303 if (dwError != ERROR_SUCCESS)
1304 goto done;
1305
1306 lpService->dwStartType = dwStartType;
1307 }
1308
1309 if (dwErrorControl != SERVICE_NO_CHANGE)
1310 {
1311 /* Set the error control value */
1312 dwError = RegSetValueExW(hServiceKey,
1313 L"ErrorControl",
1314 0,
1315 REG_DWORD,
1316 (LPBYTE)&dwErrorControl,
1317 sizeof(DWORD));
1318 if (dwError != ERROR_SUCCESS)
1319 goto done;
1320
1321 lpService->dwErrorControl = dwErrorControl;
1322 }
1323
1324 #if 0
1325 /* FIXME: set the new ImagePath value */
1326
1327 /* Set the image path */
1328 if (dwServiceType & SERVICE_WIN32)
1329 {
1330 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1331 {
1332 dwError = RegSetValueExW(hServiceKey,
1333 L"ImagePath",
1334 0,
1335 REG_EXPAND_SZ,
1336 (LPBYTE)lpBinaryPathName,
1337 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1338 if (dwError != ERROR_SUCCESS)
1339 goto done;
1340 }
1341 }
1342 else if (dwServiceType & SERVICE_DRIVER)
1343 {
1344 if (lpImagePath != NULL && *lpImagePath != 0)
1345 {
1346 dwError = RegSetValueExW(hServiceKey,
1347 L"ImagePath",
1348 0,
1349 REG_EXPAND_SZ,
1350 (LPBYTE)lpImagePath,
1351 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
1352 if (dwError != ERROR_SUCCESS)
1353 goto done;
1354 }
1355 }
1356 #endif
1357
1358 /* Set the group name */
1359 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1360 {
1361 dwError = RegSetValueExW(hServiceKey,
1362 L"Group",
1363 0,
1364 REG_SZ,
1365 (LPBYTE)lpLoadOrderGroup,
1366 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1367 if (dwError != ERROR_SUCCESS)
1368 goto done;
1369
1370 dwError = ScmSetServiceGroup(lpService,
1371 lpLoadOrderGroup);
1372 if (dwError != ERROR_SUCCESS)
1373 goto done;
1374 }
1375
1376 if (lpdwTagId != NULL)
1377 {
1378 dwError = ScmAssignNewTag(lpService);
1379 if (dwError != ERROR_SUCCESS)
1380 goto done;
1381
1382 dwError = RegSetValueExW(hServiceKey,
1383 L"Tag",
1384 0,
1385 REG_DWORD,
1386 (LPBYTE)&lpService->dwTag,
1387 sizeof(DWORD));
1388 if (dwError != ERROR_SUCCESS)
1389 goto done;
1390
1391 *lpdwTagId = lpService->dwTag;
1392 }
1393
1394 /* Write dependencies */
1395 if (lpDependencies != NULL && *lpDependencies != 0)
1396 {
1397 dwError = ScmWriteDependencies(hServiceKey,
1398 (LPWSTR)lpDependencies,
1399 dwDependSize);
1400 if (dwError != ERROR_SUCCESS)
1401 goto done;
1402 }
1403
1404 if (lpPassword != NULL)
1405 {
1406 /* FIXME: Write password */
1407 }
1408
1409 /* FIXME: Unlock database */
1410
1411 done:
1412 if (hServiceKey != NULL)
1413 RegCloseKey(hServiceKey);
1414
1415 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1416
1417 return dwError;
1418 }
1419
1420
1421 /* Create a path suitable for the bootloader out of the full path */
1422 DWORD
1423 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1424 {
1425 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1426 WCHAR Dest;
1427 WCHAR *Expanded;
1428 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1429 OBJECT_ATTRIBUTES ObjectAttributes;
1430 NTSTATUS Status;
1431 HANDLE SymbolicLinkHandle;
1432
1433 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1434
1435 ServiceNameLen = wcslen(CanonName);
1436
1437 /* First check, if it's already good */
1438 if (ServiceNameLen > 12 &&
1439 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1440 {
1441 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1442 if (*RelativeName == NULL)
1443 {
1444 DPRINT("Error allocating memory for boot driver name!\n");
1445 return ERROR_NOT_ENOUGH_MEMORY;
1446 }
1447
1448 /* Copy it */
1449 wcscpy(*RelativeName, CanonName);
1450
1451 DPRINT("Bootdriver name %S\n", *RelativeName);
1452 return ERROR_SUCCESS;
1453 }
1454
1455 /* If it has %SystemRoot% prefix, substitute it to \System*/
1456 if (ServiceNameLen > 13 &&
1457 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1458 {
1459 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1460 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1461
1462 if (*RelativeName == NULL)
1463 {
1464 DPRINT("Error allocating memory for boot driver name!\n");
1465 return ERROR_NOT_ENOUGH_MEMORY;
1466 }
1467
1468 /* Copy it */
1469 wcscpy(*RelativeName, L"\\SystemRoot\\");
1470 wcscat(*RelativeName, CanonName + 13);
1471
1472 DPRINT("Bootdriver name %S\n", *RelativeName);
1473 return ERROR_SUCCESS;
1474 }
1475
1476 /* Get buffer size needed for expanding env strings */
1477 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1478
1479 if (BufferSize <= 1)
1480 {
1481 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1482 return ERROR_INVALID_ENVIRONMENT;
1483 }
1484
1485 /* Allocate memory, since the size is known now */
1486 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1487 if (!Expanded)
1488 {
1489 DPRINT("Error allocating memory for boot driver name!\n");
1490 return ERROR_NOT_ENOUGH_MEMORY;
1491 }
1492
1493 /* Expand it */
1494 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1495 BufferSize)
1496 {
1497 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1498 LocalFree(Expanded);
1499 return ERROR_NOT_ENOUGH_MEMORY;
1500 }
1501
1502 /* Convert to NY-style path */
1503 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1504 {
1505 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1506 return ERROR_INVALID_ENVIRONMENT;
1507 }
1508
1509 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1510
1511 /* No need to keep the dos-path anymore */
1512 LocalFree(Expanded);
1513
1514 /* Copy it to the allocated place */
1515 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1516 if (!Expanded)
1517 {
1518 DPRINT("Error allocating memory for boot driver name!\n");
1519 return ERROR_NOT_ENOUGH_MEMORY;
1520 }
1521
1522 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1523 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1524 Expanded[ExpandedLen] = 0;
1525
1526 if (ServiceNameLen > ExpandedLen &&
1527 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
1528 {
1529 /* Only \SystemRoot\ is missing */
1530 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1531 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1532 if (*RelativeName == NULL)
1533 {
1534 DPRINT("Error allocating memory for boot driver name!\n");
1535 LocalFree(Expanded);
1536 return ERROR_NOT_ENOUGH_MEMORY;
1537 }
1538
1539 wcscpy(*RelativeName, L"\\SystemRoot\\");
1540 wcscat(*RelativeName, CanonName + ExpandedLen);
1541
1542 RtlFreeUnicodeString(&NtPathName);
1543 return ERROR_SUCCESS;
1544 }
1545
1546 /* The most complex case starts here */
1547 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1548 InitializeObjectAttributes(&ObjectAttributes,
1549 &SystemRoot,
1550 OBJ_CASE_INSENSITIVE,
1551 NULL,
1552 NULL);
1553
1554 /* Open this symlink */
1555 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1556
1557 if (NT_SUCCESS(Status))
1558 {
1559 LinkTarget.Length = 0;
1560 LinkTarget.MaximumLength = 0;
1561
1562 DPRINT("Opened symbolic link object\n");
1563
1564 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1565 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1566 {
1567 /* Check if required buffer size is sane */
1568 if (BufferSize > 0xFFFD)
1569 {
1570 DPRINT("Too large buffer required\n");
1571 *RelativeName = 0;
1572
1573 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1574 LocalFree(Expanded);
1575 return ERROR_NOT_ENOUGH_MEMORY;
1576 }
1577
1578 /* Alloc the string */
1579 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1580 if (!LinkTarget.Buffer)
1581 {
1582 DPRINT("Unable to alloc buffer\n");
1583 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1584 LocalFree(Expanded);
1585 return ERROR_NOT_ENOUGH_MEMORY;
1586 }
1587
1588 /* Do a real query now */
1589 LinkTarget.Length = BufferSize;
1590 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1591
1592 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1593 if (NT_SUCCESS(Status))
1594 {
1595 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1596
1597 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1598 if ((ServiceNameLen > ExpandedLen) &&
1599 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1600 {
1601 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1602 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1603
1604 if (*RelativeName == NULL)
1605 {
1606 DPRINT("Unable to alloc buffer\n");
1607 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1608 LocalFree(Expanded);
1609 RtlFreeUnicodeString(&NtPathName);
1610 return ERROR_NOT_ENOUGH_MEMORY;
1611 }
1612
1613 /* Copy it over, substituting the first part
1614 with SystemRoot */
1615 wcscpy(*RelativeName, L"\\SystemRoot\\");
1616 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1617
1618 /* Cleanup */
1619 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1620 LocalFree(Expanded);
1621 RtlFreeUnicodeString(&NtPathName);
1622
1623 /* Return success */
1624 return ERROR_SUCCESS;
1625 }
1626 else
1627 {
1628 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1629 LocalFree(Expanded);
1630 RtlFreeUnicodeString(&NtPathName);
1631 return ERROR_INVALID_PARAMETER;
1632 }
1633 }
1634 else
1635 {
1636 DPRINT("Error, Status = %08X\n", Status);
1637 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1638 LocalFree(Expanded);
1639 RtlFreeUnicodeString(&NtPathName);
1640 return ERROR_INVALID_PARAMETER;
1641 }
1642 }
1643 else
1644 {
1645 DPRINT("Error, Status = %08X\n", Status);
1646 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1647 LocalFree(Expanded);
1648 RtlFreeUnicodeString(&NtPathName);
1649 return ERROR_INVALID_PARAMETER;
1650 }
1651 }
1652 else
1653 {
1654 DPRINT("Error, Status = %08X\n", Status);
1655 LocalFree(Expanded);
1656 return ERROR_INVALID_PARAMETER;
1657 }
1658
1659 /* Failure */
1660 *RelativeName = NULL;
1661 return ERROR_INVALID_PARAMETER;
1662 }
1663
1664 DWORD
1665 ScmCanonDriverImagePath(DWORD dwStartType,
1666 const wchar_t *lpServiceName,
1667 wchar_t **lpCanonName)
1668 {
1669 DWORD ServiceNameLen, Result;
1670 UNICODE_STRING NtServiceName;
1671 WCHAR *RelativeName;
1672 const WCHAR *SourceName = lpServiceName;
1673
1674 /* Calculate the length of the service's name */
1675 ServiceNameLen = wcslen(lpServiceName);
1676
1677 /* 12 is wcslen(L"\\SystemRoot\\") */
1678 if (ServiceNameLen > 12 &&
1679 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1680 {
1681 /* SystemRoot prefix is already included */
1682
1683 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1684
1685 if (*lpCanonName == NULL)
1686 {
1687 DPRINT("Error allocating memory for canonized service name!\n");
1688 return ERROR_NOT_ENOUGH_MEMORY;
1689 }
1690
1691 /* If it's a boot-time driver, it must be systemroot relative */
1692 if (dwStartType == SERVICE_BOOT_START)
1693 SourceName += 12;
1694
1695 /* Copy it */
1696 wcscpy(*lpCanonName, SourceName);
1697
1698 DPRINT("Canonicalized name %S\n", *lpCanonName);
1699 return NO_ERROR;
1700 }
1701
1702 /* Check if it has %SystemRoot% (len=13) */
1703 if (ServiceNameLen > 13 &&
1704 !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1705 {
1706 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1707 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1708
1709 if (*lpCanonName == NULL)
1710 {
1711 DPRINT("Error allocating memory for canonized service name!\n");
1712 return ERROR_NOT_ENOUGH_MEMORY;
1713 }
1714
1715 /* If it's a boot-time driver, it must be systemroot relative */
1716 if (dwStartType == SERVICE_BOOT_START)
1717 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1718
1719 wcscat(*lpCanonName, lpServiceName + 13);
1720
1721 DPRINT("Canonicalized name %S\n", *lpCanonName);
1722 return NO_ERROR;
1723 }
1724
1725 /* Check if it's a relative path name */
1726 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1727 {
1728 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1729
1730 if (*lpCanonName == NULL)
1731 {
1732 DPRINT("Error allocating memory for canonized service name!\n");
1733 return ERROR_NOT_ENOUGH_MEMORY;
1734 }
1735
1736 /* Just copy it over without changing */
1737 wcscpy(*lpCanonName, lpServiceName);
1738
1739 return NO_ERROR;
1740 }
1741
1742 /* It seems to be a DOS path, convert it */
1743 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1744 {
1745 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
1746 return ERROR_INVALID_PARAMETER;
1747 }
1748
1749 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1750
1751 if (*lpCanonName == NULL)
1752 {
1753 DPRINT("Error allocating memory for canonized service name!\n");
1754 RtlFreeUnicodeString(&NtServiceName);
1755 return ERROR_NOT_ENOUGH_MEMORY;
1756 }
1757
1758 /* Copy the string */
1759 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1760
1761 /* The unicode string is not needed anymore */
1762 RtlFreeUnicodeString(&NtServiceName);
1763
1764 if (dwStartType != SERVICE_BOOT_START)
1765 {
1766 DPRINT("Canonicalized name %S\n", *lpCanonName);
1767 return NO_ERROR;
1768 }
1769
1770 /* The service is boot-started, so must be relative */
1771 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1772 if (Result)
1773 {
1774 /* There is a problem, free name and return */
1775 LocalFree(*lpCanonName);
1776 DPRINT("Error converting named!\n");
1777 return Result;
1778 }
1779
1780 ASSERT(RelativeName);
1781
1782 /* Copy that string */
1783 wcscpy(*lpCanonName, RelativeName + 12);
1784
1785 /* Free the allocated buffer */
1786 LocalFree(RelativeName);
1787
1788 DPRINT("Canonicalized name %S\n", *lpCanonName);
1789
1790 /* Success */
1791 return NO_ERROR;
1792 }
1793
1794
1795 /* Function 12 */
1796 DWORD RCreateServiceW(
1797 SC_RPC_HANDLE hSCManager,
1798 LPCWSTR lpServiceName,
1799 LPCWSTR lpDisplayName,
1800 DWORD dwDesiredAccess,
1801 DWORD dwServiceType,
1802 DWORD dwStartType,
1803 DWORD dwErrorControl,
1804 LPCWSTR lpBinaryPathName,
1805 LPCWSTR lpLoadOrderGroup,
1806 LPDWORD lpdwTagId,
1807 LPBYTE lpDependencies,
1808 DWORD dwDependSize,
1809 LPCWSTR lpServiceStartName,
1810 LPBYTE lpPassword,
1811 DWORD dwPwSize,
1812 LPSC_RPC_HANDLE lpServiceHandle)
1813 {
1814 PMANAGER_HANDLE hManager;
1815 DWORD dwError = ERROR_SUCCESS;
1816 PSERVICE lpService = NULL;
1817 SC_HANDLE hServiceHandle = NULL;
1818 LPWSTR lpImagePath = NULL;
1819 HKEY hServiceKey = NULL;
1820 LPWSTR lpObjectName;
1821
1822 DPRINT("RCreateServiceW() called\n");
1823 DPRINT("lpServiceName = %S\n", lpServiceName);
1824 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1825 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1826 DPRINT("dwServiceType = %lu\n", dwServiceType);
1827 DPRINT("dwStartType = %lu\n", dwStartType);
1828 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1829 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1830 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1831
1832 if (ScmShutdown)
1833 return ERROR_SHUTDOWN_IN_PROGRESS;
1834
1835 hManager = ScmGetServiceManagerFromHandle(hSCManager);
1836 if (hManager == NULL)
1837 {
1838 DPRINT1("Invalid service manager handle!\n");
1839 return ERROR_INVALID_HANDLE;
1840 }
1841
1842 /* Check access rights */
1843 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1844 SC_MANAGER_CREATE_SERVICE))
1845 {
1846 DPRINT("Insufficient access rights! 0x%lx\n",
1847 hManager->Handle.DesiredAccess);
1848 return ERROR_ACCESS_DENIED;
1849 }
1850
1851 if (wcslen(lpServiceName) == 0)
1852 {
1853 return ERROR_INVALID_NAME;
1854 }
1855
1856 if (wcslen(lpBinaryPathName) == 0)
1857 {
1858 return ERROR_INVALID_PARAMETER;
1859 }
1860
1861 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1862 (lpServiceStartName))
1863 {
1864 return ERROR_INVALID_PARAMETER;
1865 }
1866
1867 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
1868 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1869 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
1870 {
1871 return ERROR_INVALID_PARAMETER;
1872 }
1873
1874 if (dwStartType > SERVICE_DISABLED)
1875 {
1876 return ERROR_INVALID_PARAMETER;
1877 }
1878
1879 lpService = ScmGetServiceEntryByName(lpServiceName);
1880 if (lpService)
1881 {
1882 /* check if it is marked for deletion */
1883 if (lpService->bDeleted)
1884 return ERROR_SERVICE_MARKED_FOR_DELETE;
1885 /* Return Error exist */
1886 return ERROR_SERVICE_EXISTS;
1887 }
1888
1889 if (lpDisplayName != NULL &&
1890 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
1891 return ERROR_DUPLICATE_SERVICE_NAME;
1892
1893 if (dwServiceType & SERVICE_DRIVER)
1894 {
1895 dwError = ScmCanonDriverImagePath(dwStartType,
1896 lpBinaryPathName,
1897 &lpImagePath);
1898 if (dwError != ERROR_SUCCESS)
1899 goto done;
1900 }
1901 else
1902 {
1903 if (dwStartType == SERVICE_BOOT_START ||
1904 dwStartType == SERVICE_SYSTEM_START)
1905 {
1906 return ERROR_INVALID_PARAMETER;
1907 }
1908 }
1909
1910 /* Allocate a new service entry */
1911 dwError = ScmCreateNewServiceRecord(lpServiceName,
1912 &lpService);
1913 if (dwError != ERROR_SUCCESS)
1914 goto done;
1915
1916 /* Fill the new service entry */
1917 lpService->Status.dwServiceType = dwServiceType;
1918 lpService->dwStartType = dwStartType;
1919 lpService->dwErrorControl = dwErrorControl;
1920
1921 /* Fill the display name */
1922 if (lpDisplayName != NULL &&
1923 *lpDisplayName != 0 &&
1924 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1925 {
1926 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1927 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1928 if (lpService->lpDisplayName == NULL)
1929 {
1930 dwError = ERROR_NOT_ENOUGH_MEMORY;
1931 goto done;
1932 }
1933 wcscpy(lpService->lpDisplayName, lpDisplayName);
1934 }
1935
1936 /* Assign the service to a group */
1937 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1938 {
1939 dwError = ScmSetServiceGroup(lpService,
1940 lpLoadOrderGroup);
1941 if (dwError != ERROR_SUCCESS)
1942 goto done;
1943 }
1944
1945 /* Assign a new tag */
1946 if (lpdwTagId != NULL)
1947 {
1948 dwError = ScmAssignNewTag(lpService);
1949 if (dwError != ERROR_SUCCESS)
1950 goto done;
1951 }
1952
1953 /* Write service data to the registry */
1954 /* Create the service key */
1955 dwError = ScmCreateServiceKey(lpServiceName,
1956 KEY_WRITE,
1957 &hServiceKey);
1958 if (dwError != ERROR_SUCCESS)
1959 goto done;
1960
1961 /* Set the display name */
1962 if (lpDisplayName != NULL && *lpDisplayName != 0)
1963 {
1964 RegSetValueExW(hServiceKey,
1965 L"DisplayName",
1966 0,
1967 REG_SZ,
1968 (LPBYTE)lpDisplayName,
1969 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1970 }
1971
1972 /* Set the service type */
1973 dwError = RegSetValueExW(hServiceKey,
1974 L"Type",
1975 0,
1976 REG_DWORD,
1977 (LPBYTE)&dwServiceType,
1978 sizeof(DWORD));
1979 if (dwError != ERROR_SUCCESS)
1980 goto done;
1981
1982 /* Set the start value */
1983 dwError = RegSetValueExW(hServiceKey,
1984 L"Start",
1985 0,
1986 REG_DWORD,
1987 (LPBYTE)&dwStartType,
1988 sizeof(DWORD));
1989 if (dwError != ERROR_SUCCESS)
1990 goto done;
1991
1992 /* Set the error control value */
1993 dwError = RegSetValueExW(hServiceKey,
1994 L"ErrorControl",
1995 0,
1996 REG_DWORD,
1997 (LPBYTE)&dwErrorControl,
1998 sizeof(DWORD));
1999 if (dwError != ERROR_SUCCESS)
2000 goto done;
2001
2002 /* Set the image path */
2003 if (dwServiceType & SERVICE_WIN32)
2004 {
2005 dwError = RegSetValueExW(hServiceKey,
2006 L"ImagePath",
2007 0,
2008 REG_EXPAND_SZ,
2009 (LPBYTE)lpBinaryPathName,
2010 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
2011 if (dwError != ERROR_SUCCESS)
2012 goto done;
2013 }
2014 else if (dwServiceType & SERVICE_DRIVER)
2015 {
2016 dwError = RegSetValueExW(hServiceKey,
2017 L"ImagePath",
2018 0,
2019 REG_EXPAND_SZ,
2020 (LPBYTE)lpImagePath,
2021 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2022 if (dwError != ERROR_SUCCESS)
2023 goto done;
2024 }
2025
2026 /* Set the group name */
2027 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2028 {
2029 dwError = RegSetValueExW(hServiceKey,
2030 L"Group",
2031 0,
2032 REG_SZ,
2033 (LPBYTE)lpLoadOrderGroup,
2034 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
2035 if (dwError != ERROR_SUCCESS)
2036 goto done;
2037 }
2038
2039 if (lpdwTagId != NULL)
2040 {
2041 dwError = RegSetValueExW(hServiceKey,
2042 L"Tag",
2043 0,
2044 REG_DWORD,
2045 (LPBYTE)&lpService->dwTag,
2046 sizeof(DWORD));
2047 if (dwError != ERROR_SUCCESS)
2048 goto done;
2049 }
2050
2051 /* Write dependencies */
2052 if (lpDependencies != NULL && *lpDependencies != 0)
2053 {
2054 dwError = ScmWriteDependencies(hServiceKey,
2055 (LPWSTR)lpDependencies,
2056 dwDependSize);
2057 if (dwError != ERROR_SUCCESS)
2058 goto done;
2059 }
2060
2061 /* Write service start name */
2062 if (dwServiceType & SERVICE_WIN32)
2063 {
2064 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2065 dwError = RegSetValueExW(hServiceKey,
2066 L"ObjectName",
2067 0,
2068 REG_SZ,
2069 (LPBYTE)lpObjectName,
2070 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
2071 if (dwError != ERROR_SUCCESS)
2072 goto done;
2073 }
2074
2075 if (lpPassword != NULL)
2076 {
2077 /* FIXME: Write password */
2078 }
2079
2080 dwError = ScmCreateServiceHandle(lpService,
2081 &hServiceHandle);
2082 if (dwError != ERROR_SUCCESS)
2083 goto done;
2084
2085 dwError = ScmCheckAccess(hServiceHandle,
2086 dwDesiredAccess);
2087 if (dwError != ERROR_SUCCESS)
2088 goto done;
2089
2090 lpService->dwRefCount = 1;
2091 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2092
2093 done:;
2094 if (hServiceKey != NULL)
2095 RegCloseKey(hServiceKey);
2096
2097 if (dwError == ERROR_SUCCESS)
2098 {
2099 DPRINT("hService %p\n", hServiceHandle);
2100 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2101
2102 if (lpdwTagId != NULL)
2103 *lpdwTagId = lpService->dwTag;
2104 }
2105 else
2106 {
2107 /* Release the display name buffer */
2108 if (lpService->lpServiceName != NULL)
2109 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2110
2111 if (hServiceHandle)
2112 {
2113 /* Remove the service handle */
2114 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2115 }
2116
2117 if (lpService != NULL)
2118 {
2119 /* FIXME: remove the service entry */
2120 }
2121 }
2122
2123 if (lpImagePath != NULL)
2124 HeapFree(GetProcessHeap(), 0, lpImagePath);
2125
2126 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2127
2128 return dwError;
2129 }
2130
2131
2132 /* Function 13 */
2133 DWORD REnumDependentServicesW(
2134 SC_RPC_HANDLE hService,
2135 DWORD dwServiceState,
2136 LPBYTE lpServices,
2137 DWORD cbBufSize,
2138 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2139 LPBOUNDED_DWORD_256K lpServicesReturned)
2140 {
2141 DWORD dwError = ERROR_SUCCESS;
2142 DWORD dwServicesReturned = 0;
2143 DWORD dwServiceCount;
2144 HKEY hServicesKey = NULL;
2145 PSERVICE_HANDLE hSvc;
2146 PSERVICE lpService = NULL;
2147 PSERVICE *lpServicesArray = NULL;
2148 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2149 LPWSTR lpStr;
2150
2151 *pcbBytesNeeded = 0;
2152 *lpServicesReturned = 0;
2153
2154 DPRINT("REnumDependentServicesW() called\n");
2155
2156 hSvc = ScmGetServiceFromHandle(hService);
2157 if (hSvc == NULL)
2158 {
2159 DPRINT1("Invalid service handle!\n");
2160 return ERROR_INVALID_HANDLE;
2161 }
2162
2163 lpService = hSvc->ServiceEntry;
2164
2165 /* Check access rights */
2166 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2167 SC_MANAGER_ENUMERATE_SERVICE))
2168 {
2169 DPRINT("Insufficient access rights! 0x%lx\n",
2170 hSvc->Handle.DesiredAccess);
2171 return ERROR_ACCESS_DENIED;
2172 }
2173
2174 /* Open the Services Reg key */
2175 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2176 L"System\\CurrentControlSet\\Services",
2177 0,
2178 KEY_READ,
2179 &hServicesKey);
2180 if (dwError != ERROR_SUCCESS)
2181 return dwError;
2182
2183 /* First determine the bytes needed and get the number of dependent services */
2184 dwError = Int_EnumDependentServicesW(hServicesKey,
2185 lpService,
2186 dwServiceState,
2187 NULL,
2188 pcbBytesNeeded,
2189 &dwServicesReturned);
2190 if (dwError != ERROR_SUCCESS)
2191 goto Done;
2192
2193 /* If buffer size is less than the bytes needed or pointer is null */
2194 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2195 {
2196 dwError = ERROR_MORE_DATA;
2197 goto Done;
2198 }
2199
2200 /* Allocate memory for array of service pointers */
2201 lpServicesArray = HeapAlloc(GetProcessHeap(),
2202 0,
2203 (dwServicesReturned + 1) * sizeof(PSERVICE));
2204 if (!lpServicesArray)
2205 {
2206 DPRINT("Could not allocate a buffer!!\n");
2207 dwError = ERROR_NOT_ENOUGH_MEMORY;
2208 goto Done;
2209 }
2210
2211 dwServicesReturned = 0;
2212 *pcbBytesNeeded = 0;
2213
2214 dwError = Int_EnumDependentServicesW(hServicesKey,
2215 lpService,
2216 dwServiceState,
2217 lpServicesArray,
2218 pcbBytesNeeded,
2219 &dwServicesReturned);
2220 if (dwError != ERROR_SUCCESS)
2221 {
2222 goto Done;
2223 }
2224
2225 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2226 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2227
2228 /* Copy EnumDepenedentService to Buffer */
2229 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2230 {
2231 lpService = lpServicesArray[dwServiceCount];
2232
2233 /* Copy status info */
2234 memcpy(&lpServicesPtr->ServiceStatus,
2235 &lpService->Status,
2236 sizeof(SERVICE_STATUS));
2237
2238 /* Copy display name */
2239 wcscpy(lpStr, lpService->lpDisplayName);
2240 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2241 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2242
2243 /* Copy service name */
2244 wcscpy(lpStr, lpService->lpServiceName);
2245 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2246 lpStr += (wcslen(lpService->lpServiceName) + 1);
2247
2248 lpServicesPtr ++;
2249 }
2250
2251 *lpServicesReturned = dwServicesReturned;
2252
2253 Done:
2254 if (lpServicesArray != NULL)
2255 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2256
2257 RegCloseKey(hServicesKey);
2258
2259 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2260
2261 return dwError;
2262 }
2263
2264
2265 /* Function 14 */
2266 DWORD REnumServicesStatusW(
2267 SC_RPC_HANDLE hSCManager,
2268 DWORD dwServiceType,
2269 DWORD dwServiceState,
2270 LPBYTE lpBuffer,
2271 DWORD dwBufSize,
2272 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2273 LPBOUNDED_DWORD_256K lpServicesReturned,
2274 LPBOUNDED_DWORD_256K lpResumeHandle)
2275 {
2276 PMANAGER_HANDLE hManager;
2277 PSERVICE lpService;
2278 DWORD dwError = ERROR_SUCCESS;
2279 PLIST_ENTRY ServiceEntry;
2280 PSERVICE CurrentService;
2281 DWORD dwState;
2282 DWORD dwRequiredSize;
2283 DWORD dwServiceCount;
2284 DWORD dwSize;
2285 DWORD dwLastResumeCount = 0;
2286 LPENUM_SERVICE_STATUSW lpStatusPtr;
2287 LPWSTR lpStringPtr;
2288
2289 DPRINT("REnumServicesStatusW() called\n");
2290
2291 if (ScmShutdown)
2292 return ERROR_SHUTDOWN_IN_PROGRESS;
2293
2294 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2295 if (hManager == NULL)
2296 {
2297 DPRINT1("Invalid service manager handle!\n");
2298 return ERROR_INVALID_HANDLE;
2299 }
2300
2301
2302 *pcbBytesNeeded = 0;
2303 *lpServicesReturned = 0;
2304
2305 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2306 {
2307 DPRINT("Not a valid Service Type!\n");
2308 return ERROR_INVALID_PARAMETER;
2309 }
2310
2311 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2312 {
2313 DPRINT("Not a valid Service State!\n");
2314 return ERROR_INVALID_PARAMETER;
2315 }
2316
2317 /* Check access rights */
2318 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2319 SC_MANAGER_ENUMERATE_SERVICE))
2320 {
2321 DPRINT("Insufficient access rights! 0x%lx\n",
2322 hManager->Handle.DesiredAccess);
2323 return ERROR_ACCESS_DENIED;
2324 }
2325
2326 if (lpResumeHandle)
2327 dwLastResumeCount = *lpResumeHandle;
2328
2329 /* FIXME: Lock the service list shared */
2330
2331 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2332 if (lpService == NULL)
2333 {
2334 dwError = ERROR_SUCCESS;
2335 goto Done;
2336 }
2337
2338 dwRequiredSize = 0;
2339 dwServiceCount = 0;
2340
2341 for (ServiceEntry = &lpService->ServiceListEntry;
2342 ServiceEntry != &ServiceListHead;
2343 ServiceEntry = ServiceEntry->Flink)
2344 {
2345 CurrentService = CONTAINING_RECORD(ServiceEntry,
2346 SERVICE,
2347 ServiceListEntry);
2348
2349 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2350 continue;
2351
2352 dwState = SERVICE_ACTIVE;
2353 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2354 dwState = SERVICE_INACTIVE;
2355
2356 if ((dwState & dwServiceState) == 0)
2357 continue;
2358
2359 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2360 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2361 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2362
2363 if (dwRequiredSize + dwSize > dwBufSize)
2364 {
2365 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2366 break;
2367 }
2368
2369 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2370 dwRequiredSize += dwSize;
2371 dwServiceCount++;
2372 dwLastResumeCount = CurrentService->dwResumeCount;
2373 }
2374
2375 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2376 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2377
2378 for (;
2379 ServiceEntry != &ServiceListHead;
2380 ServiceEntry = ServiceEntry->Flink)
2381 {
2382 CurrentService = CONTAINING_RECORD(ServiceEntry,
2383 SERVICE,
2384 ServiceListEntry);
2385
2386 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2387 continue;
2388
2389 dwState = SERVICE_ACTIVE;
2390 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2391 dwState = SERVICE_INACTIVE;
2392
2393 if ((dwState & dwServiceState) == 0)
2394 continue;
2395
2396 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2397 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2398 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2399
2400 dwError = ERROR_MORE_DATA;
2401 }
2402
2403 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2404
2405 if (lpResumeHandle)
2406 *lpResumeHandle = dwLastResumeCount;
2407
2408 *lpServicesReturned = dwServiceCount;
2409 *pcbBytesNeeded = dwRequiredSize;
2410
2411 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2412 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2413 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2414
2415 dwRequiredSize = 0;
2416 for (ServiceEntry = &lpService->ServiceListEntry;
2417 ServiceEntry != &ServiceListHead;
2418 ServiceEntry = ServiceEntry->Flink)
2419 {
2420 CurrentService = CONTAINING_RECORD(ServiceEntry,
2421 SERVICE,
2422 ServiceListEntry);
2423
2424 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2425 continue;
2426
2427 dwState = SERVICE_ACTIVE;
2428 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2429 dwState = SERVICE_INACTIVE;
2430
2431 if ((dwState & dwServiceState) == 0)
2432 continue;
2433
2434 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2435 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2436 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2437
2438 if (dwRequiredSize + dwSize > dwBufSize)
2439 break;
2440
2441 /* Copy the service name */
2442 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2443 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2444 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2445
2446 /* Copy the display name */
2447 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2448 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2449 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2450
2451 /* Copy the status information */
2452 memcpy(&lpStatusPtr->ServiceStatus,
2453 &CurrentService->Status,
2454 sizeof(SERVICE_STATUS));
2455
2456 lpStatusPtr++;
2457 dwRequiredSize += dwSize;
2458 }
2459
2460 if (dwError == 0)
2461 {
2462 *pcbBytesNeeded = 0;
2463 if (lpResumeHandle) *lpResumeHandle = 0;
2464 }
2465
2466 Done:;
2467 /* FIXME: Unlock the service list */
2468
2469 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2470
2471 return dwError;
2472 }
2473
2474
2475 /* Function 15 */
2476 DWORD ROpenSCManagerW(
2477 LPWSTR lpMachineName,
2478 LPWSTR lpDatabaseName,
2479 DWORD dwDesiredAccess,
2480 LPSC_RPC_HANDLE lpScHandle)
2481 {
2482 DWORD dwError;
2483 SC_HANDLE hHandle;
2484
2485 DPRINT("ROpenSCManagerW() called\n");
2486 DPRINT("lpMachineName = %p\n", lpMachineName);
2487 DPRINT("lpMachineName: %S\n", lpMachineName);
2488 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2489 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2490 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2491
2492 if (ScmShutdown)
2493 return ERROR_SHUTDOWN_IN_PROGRESS;
2494
2495 if (!lpScHandle)
2496 return ERROR_INVALID_PARAMETER;
2497
2498 dwError = ScmCreateManagerHandle(lpDatabaseName,
2499 &hHandle);
2500 if (dwError != ERROR_SUCCESS)
2501 {
2502 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2503 return dwError;
2504 }
2505
2506 /* Check the desired access */
2507 dwError = ScmCheckAccess(hHandle,
2508 dwDesiredAccess | SC_MANAGER_CONNECT);
2509 if (dwError != ERROR_SUCCESS)
2510 {
2511 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2512 HeapFree(GetProcessHeap(), 0, hHandle);
2513 return dwError;
2514 }
2515
2516 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2517 DPRINT("*hScm = %p\n", *lpScHandle);
2518
2519 DPRINT("ROpenSCManagerW() done\n");
2520
2521 return ERROR_SUCCESS;
2522 }
2523
2524
2525 /* Function 16 */
2526 DWORD ROpenServiceW(
2527 SC_RPC_HANDLE hSCManager,
2528 LPWSTR lpServiceName,
2529 DWORD dwDesiredAccess,
2530 LPSC_RPC_HANDLE lpServiceHandle)
2531 {
2532 PSERVICE lpService;
2533 PMANAGER_HANDLE hManager;
2534 SC_HANDLE hHandle;
2535 DWORD dwError;
2536
2537 DPRINT("ROpenServiceW() called\n");
2538 DPRINT("hSCManager = %p\n", hSCManager);
2539 DPRINT("lpServiceName = %p\n", lpServiceName);
2540 DPRINT("lpServiceName: %S\n", lpServiceName);
2541 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2542
2543 if (ScmShutdown)
2544 return ERROR_SHUTDOWN_IN_PROGRESS;
2545
2546 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2547 if (hManager == NULL)
2548 {
2549 DPRINT1("Invalid service manager handle!\n");
2550 return ERROR_INVALID_HANDLE;
2551 }
2552
2553 if (!lpServiceHandle)
2554 return ERROR_INVALID_PARAMETER;
2555
2556 if (!lpServiceName)
2557 return ERROR_INVALID_ADDRESS;
2558
2559 /* FIXME: Lock the service list */
2560
2561 /* Get service database entry */
2562 lpService = ScmGetServiceEntryByName(lpServiceName);
2563 if (lpService == NULL)
2564 {
2565 DPRINT("Could not find a service!\n");
2566 return ERROR_SERVICE_DOES_NOT_EXIST;
2567 }
2568
2569 /* Create a service handle */
2570 dwError = ScmCreateServiceHandle(lpService,
2571 &hHandle);
2572 if (dwError != ERROR_SUCCESS)
2573 {
2574 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2575 return dwError;
2576 }
2577
2578 /* Check the desired access */
2579 dwError = ScmCheckAccess(hHandle,
2580 dwDesiredAccess);
2581 if (dwError != ERROR_SUCCESS)
2582 {
2583 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2584 HeapFree(GetProcessHeap(), 0, hHandle);
2585 return dwError;
2586 }
2587
2588 lpService->dwRefCount++;
2589 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2590
2591 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2592 DPRINT("*hService = %p\n", *lpServiceHandle);
2593
2594 DPRINT("ROpenServiceW() done\n");
2595
2596 return ERROR_SUCCESS;
2597 }
2598
2599
2600 /* Function 17 */
2601 DWORD RQueryServiceConfigW(
2602 SC_RPC_HANDLE hService,
2603 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2604 DWORD cbBufSize,
2605 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2606 {
2607 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2608 DWORD dwError = ERROR_SUCCESS;
2609 PSERVICE_HANDLE hSvc;
2610 PSERVICE lpService = NULL;
2611 HKEY hServiceKey = NULL;
2612 LPWSTR lpImagePath = NULL;
2613 LPWSTR lpServiceStartName = NULL;
2614 LPWSTR lpDependencies = NULL;
2615 DWORD dwDependenciesLength = 0;
2616 DWORD dwRequiredSize;
2617 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2618 WCHAR lpEmptyString[] = {0,0};
2619 LPWSTR lpStr;
2620
2621 DPRINT("RQueryServiceConfigW() called\n");
2622
2623 if (ScmShutdown)
2624 return ERROR_SHUTDOWN_IN_PROGRESS;
2625
2626 hSvc = ScmGetServiceFromHandle(hService);
2627 if (hSvc == NULL)
2628 {
2629 DPRINT1("Invalid service handle!\n");
2630 return ERROR_INVALID_HANDLE;
2631 }
2632
2633 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2634 SERVICE_QUERY_CONFIG))
2635 {
2636 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2637 return ERROR_ACCESS_DENIED;
2638 }
2639
2640 lpService = hSvc->ServiceEntry;
2641 if (lpService == NULL)
2642 {
2643 DPRINT("lpService == NULL!\n");
2644 return ERROR_INVALID_HANDLE;
2645 }
2646
2647 /* FIXME: Lock the service database shared */
2648
2649 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2650 KEY_READ,
2651 &hServiceKey);
2652 if (dwError != ERROR_SUCCESS)
2653 goto Done;
2654
2655 /* Read the image path */
2656 dwError = ScmReadString(hServiceKey,
2657 L"ImagePath",
2658 &lpImagePath);
2659 if (dwError != ERROR_SUCCESS)
2660 goto Done;
2661
2662 /* Read the service start name */
2663 ScmReadString(hServiceKey,
2664 L"ObjectName",
2665 &lpServiceStartName);
2666
2667 /* Read the dependencies */
2668 ScmReadDependencies(hServiceKey,
2669 &lpDependencies,
2670 &dwDependenciesLength);
2671
2672 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2673
2674 if (lpImagePath != NULL)
2675 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2676 else
2677 dwRequiredSize += 2 * sizeof(WCHAR);
2678
2679 if (lpService->lpGroup != NULL)
2680 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2681 else
2682 dwRequiredSize += 2 * sizeof(WCHAR);
2683
2684 if (lpDependencies != NULL)
2685 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2686 else
2687 dwRequiredSize += 2 * sizeof(WCHAR);
2688
2689 if (lpServiceStartName != NULL)
2690 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2691 else
2692 dwRequiredSize += 2 * sizeof(WCHAR);
2693
2694 if (lpService->lpDisplayName != NULL)
2695 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2696 else
2697 dwRequiredSize += 2 * sizeof(WCHAR);
2698
2699 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2700 {
2701 dwError = ERROR_INSUFFICIENT_BUFFER;
2702 }
2703 else
2704 {
2705 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2706 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2707 lpConfig->dwStartType = lpService->dwStartType;
2708 lpConfig->dwErrorControl = lpService->dwErrorControl;
2709 lpConfig->dwTagId = lpService->dwTag;
2710
2711 lpStr = (LPWSTR)(lpConfig + 1);
2712
2713 /* Append the image path */
2714 if (lpImagePath != NULL)
2715 {
2716 wcscpy(lpStr, lpImagePath);
2717 }
2718 else
2719 {
2720 wcscpy(lpStr, lpEmptyString);
2721 }
2722
2723 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2724 lpStr += (wcslen(lpStr) + 1);
2725
2726 /* Append the group name */
2727 if (lpService->lpGroup != NULL)
2728 {
2729 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2730 }
2731 else
2732 {
2733 wcscpy(lpStr, lpEmptyString);
2734 }
2735
2736 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2737 lpStr += (wcslen(lpStr) + 1);
2738
2739 /* Append Dependencies */
2740 if (lpDependencies != NULL)
2741 {
2742 memcpy(lpStr,
2743 lpDependencies,
2744 dwDependenciesLength * sizeof(WCHAR));
2745 }
2746 else
2747 {
2748 wcscpy(lpStr, lpEmptyString);
2749 }
2750
2751 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2752 if (lpDependencies != NULL)
2753 lpStr += dwDependenciesLength * sizeof(WCHAR);
2754 else
2755 lpStr += (wcslen(lpStr) + 1);
2756
2757 /* Append the service start name */
2758 if (lpServiceStartName != NULL)
2759 {
2760 wcscpy(lpStr, lpServiceStartName);
2761 }
2762 else
2763 {
2764 wcscpy(lpStr, lpEmptyString);
2765 }
2766
2767 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2768 lpStr += (wcslen(lpStr) + 1);
2769
2770 /* Append the display name */
2771 if (lpService->lpDisplayName != NULL)
2772 {
2773 wcscpy(lpStr, lpService->lpDisplayName);
2774 }
2775 else
2776 {
2777 wcscpy(lpStr, lpEmptyString);
2778 }
2779
2780 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2781 }
2782
2783 if (pcbBytesNeeded != NULL)
2784 *pcbBytesNeeded = dwRequiredSize;
2785
2786 Done:;
2787 if (lpImagePath != NULL)
2788 HeapFree(GetProcessHeap(), 0, lpImagePath);
2789
2790 if (lpServiceStartName != NULL)
2791 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2792
2793 if (lpDependencies != NULL)
2794 HeapFree(GetProcessHeap(), 0, lpDependencies);
2795
2796 if (hServiceKey != NULL)
2797 RegCloseKey(hServiceKey);
2798
2799 /* FIXME: Unlock the service database */
2800
2801 DPRINT("RQueryServiceConfigW() done\n");
2802
2803 return dwError;
2804 }
2805
2806
2807 /* Function 18 */
2808 DWORD RQueryServiceLockStatusW(
2809 SC_RPC_HANDLE hSCManager,
2810 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2811 DWORD cbBufSize,
2812 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2813 {
2814 UNIMPLEMENTED;
2815 return ERROR_CALL_NOT_IMPLEMENTED;
2816 }
2817
2818
2819 /* Function 19 */
2820 DWORD RStartServiceW(
2821 SC_RPC_HANDLE hService,
2822 DWORD argc,
2823 LPSTRING_PTRSW argv)
2824 {
2825 DWORD dwError = ERROR_SUCCESS;
2826 PSERVICE_HANDLE hSvc;
2827 PSERVICE lpService = NULL;
2828
2829 DPRINT("RStartServiceW() called\n");
2830
2831 if (ScmShutdown)
2832 return ERROR_SHUTDOWN_IN_PROGRESS;
2833
2834 hSvc = ScmGetServiceFromHandle(hService);
2835 if (hSvc == NULL)
2836 {
2837 DPRINT1("Invalid service handle!\n");
2838 return ERROR_INVALID_HANDLE;
2839 }
2840
2841 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2842 SERVICE_START))
2843 {
2844 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2845 return ERROR_ACCESS_DENIED;
2846 }
2847
2848 lpService = hSvc->ServiceEntry;
2849 if (lpService == NULL)
2850 {
2851 DPRINT("lpService == NULL!\n");
2852 return ERROR_INVALID_HANDLE;
2853 }
2854
2855 if (lpService->dwStartType == SERVICE_DISABLED)
2856 return ERROR_SERVICE_DISABLED;
2857
2858 if (lpService->bDeleted)
2859 return ERROR_SERVICE_MARKED_FOR_DELETE;
2860
2861 if (argv) {
2862 UNIMPLEMENTED;
2863 argv = NULL;
2864 }
2865
2866 /* Start the service */
2867 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2868
2869 return dwError;
2870 }
2871
2872
2873 /* Function 20 */
2874 DWORD RGetServiceDisplayNameW(
2875 SC_RPC_HANDLE hSCManager,
2876 LPCWSTR lpServiceName,
2877 LPWSTR lpDisplayName,
2878 DWORD *lpcchBuffer)
2879 {
2880 // PMANAGER_HANDLE hManager;
2881 PSERVICE lpService;
2882 DWORD dwLength;
2883 DWORD dwError;
2884
2885 DPRINT("RGetServiceDisplayNameW() called\n");
2886 DPRINT("hSCManager = %p\n", hSCManager);
2887 DPRINT("lpServiceName: %S\n", lpServiceName);
2888 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2889 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2890
2891 // hManager = (PMANAGER_HANDLE)hSCManager;
2892 // if (hManager->Handle.Tag != MANAGER_TAG)
2893 // {
2894 // DPRINT("Invalid manager handle!\n");
2895 // return ERROR_INVALID_HANDLE;
2896 // }
2897
2898 /* Get service database entry */
2899 lpService = ScmGetServiceEntryByName(lpServiceName);
2900 if (lpService == NULL)
2901 {
2902 DPRINT("Could not find a service!\n");
2903
2904 /* If the service could not be found and lpcchBuffer is less than 2, windows
2905 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2906 if (*lpcchBuffer < 2)
2907 {
2908 *lpcchBuffer = 2;
2909 if (lpDisplayName != NULL)
2910 {
2911 *lpDisplayName = '\0';
2912 }
2913 }
2914
2915 return ERROR_SERVICE_DOES_NOT_EXIST;
2916 }
2917
2918 if (!lpService->lpDisplayName)
2919 {
2920 dwLength = wcslen(lpService->lpServiceName);
2921
2922 if (lpDisplayName != NULL &&
2923 *lpcchBuffer > dwLength)
2924 {
2925 wcscpy(lpDisplayName, lpService->lpServiceName);
2926 }
2927 }
2928 else
2929 {
2930 dwLength = wcslen(lpService->lpDisplayName);
2931
2932 if (lpDisplayName != NULL &&
2933 *lpcchBuffer > dwLength)
2934 {
2935 wcscpy(lpDisplayName, lpService->lpDisplayName);
2936 }
2937 }
2938
2939 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2940
2941 *lpcchBuffer = dwLength;
2942
2943 return dwError;
2944 }
2945
2946
2947 /* Function 21 */
2948 DWORD RGetServiceKeyNameW(
2949 SC_RPC_HANDLE hSCManager,
2950 LPCWSTR lpDisplayName,
2951 LPWSTR lpServiceName,
2952 DWORD *lpcchBuffer)
2953 {
2954 // PMANAGER_HANDLE hManager;
2955 PSERVICE lpService;
2956 DWORD dwLength;
2957 DWORD dwError;
2958
2959 DPRINT("RGetServiceKeyNameW() called\n");
2960 DPRINT("hSCManager = %p\n", hSCManager);
2961 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2962 DPRINT("lpServiceName: %p\n", lpServiceName);
2963 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2964
2965 // hManager = (PMANAGER_HANDLE)hSCManager;
2966 // if (hManager->Handle.Tag != MANAGER_TAG)
2967 // {
2968 // DPRINT("Invalid manager handle!\n");
2969 // return ERROR_INVALID_HANDLE;
2970 // }
2971
2972 /* Get service database entry */
2973 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2974 if (lpService == NULL)
2975 {
2976 DPRINT("Could not find a service!\n");
2977
2978 /* If the service could not be found and lpcchBuffer is less than 2, windows
2979 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2980 if (*lpcchBuffer < 2)
2981 {
2982 *lpcchBuffer = 2;
2983 if (lpServiceName != NULL)
2984 {
2985 *lpServiceName = '\0';
2986 }
2987 }
2988
2989 return ERROR_SERVICE_DOES_NOT_EXIST;
2990 }
2991
2992 dwLength = wcslen(lpService->lpServiceName);
2993
2994 if (lpServiceName != NULL &&
2995 *lpcchBuffer > dwLength)
2996 {
2997 wcscpy(lpServiceName, lpService->lpServiceName);
2998 *lpcchBuffer = dwLength;
2999 return ERROR_SUCCESS;
3000 }
3001
3002 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3003
3004 *lpcchBuffer = dwLength;
3005
3006 return dwError;
3007 }
3008
3009
3010 /* Function 22 */
3011 DWORD RI_ScSetServiceBitsA(
3012 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3013 DWORD dwServiceBits,
3014 int bSetBitsOn,
3015 int bUpdateImmediately,
3016 char *lpString)
3017 {
3018 UNIMPLEMENTED;
3019 return ERROR_CALL_NOT_IMPLEMENTED;
3020 }
3021
3022
3023 /* Function 23 */
3024 DWORD RChangeServiceConfigA(
3025 SC_RPC_HANDLE hService,
3026 DWORD dwServiceType,
3027 DWORD dwStartType,
3028 DWORD dwErrorControl,
3029 LPSTR lpBinaryPathName,
3030 LPSTR lpLoadOrderGroup,
3031 LPDWORD lpdwTagId,
3032 LPSTR lpDependencies,
3033 DWORD dwDependSize,
3034 LPSTR lpServiceStartName,
3035 LPBYTE lpPassword,
3036 DWORD dwPwSize,
3037 LPSTR lpDisplayName)
3038 {
3039 DWORD dwError = ERROR_SUCCESS;
3040 PSERVICE_HANDLE hSvc;
3041 PSERVICE lpService = NULL;
3042 HKEY hServiceKey = NULL;
3043 LPWSTR lpDisplayNameW = NULL;
3044 // LPWSTR lpBinaryPathNameW = NULL;
3045 LPWSTR lpLoadOrderGroupW = NULL;
3046 LPWSTR lpDependenciesW = NULL;
3047 // LPWSTR lpPasswordW = NULL;
3048
3049 DPRINT("RChangeServiceConfigA() called\n");
3050 DPRINT("dwServiceType = %lu\n", dwServiceType);
3051 DPRINT("dwStartType = %lu\n", dwStartType);
3052 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3053 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3054 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3055 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3056
3057 if (ScmShutdown)
3058 return ERROR_SHUTDOWN_IN_PROGRESS;
3059
3060 hSvc = ScmGetServiceFromHandle(hService);
3061 if (hSvc == NULL)
3062 {
3063 DPRINT1("Invalid service handle!\n");
3064 return ERROR_INVALID_HANDLE;
3065 }
3066
3067 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3068 SERVICE_CHANGE_CONFIG))
3069 {
3070 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3071 return ERROR_ACCESS_DENIED;
3072 }
3073
3074 lpService = hSvc->ServiceEntry;
3075 if (lpService == NULL)
3076 {
3077 DPRINT("lpService == NULL!\n");
3078 return ERROR_INVALID_HANDLE;
3079 }
3080
3081 /* FIXME: Lock database exclusively */
3082
3083 if (lpService->bDeleted)
3084 {
3085 /* FIXME: Unlock database */
3086 DPRINT("The service has already been marked for delete!\n");
3087 return ERROR_SERVICE_MARKED_FOR_DELETE;
3088 }
3089
3090 /* Open the service key */
3091 dwError = ScmOpenServiceKey(lpService->szServiceName,
3092 KEY_SET_VALUE,
3093 &hServiceKey);
3094 if (dwError != ERROR_SUCCESS)
3095 goto done;
3096
3097 /* Write service data to the registry */
3098
3099 if (lpDisplayName != NULL && *lpDisplayName != 0)
3100 {
3101 /* Set the display name */
3102 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3103 0,
3104 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3105 if (lpDisplayNameW == NULL)
3106 {
3107 dwError = ERROR_NOT_ENOUGH_MEMORY;
3108 goto done;
3109 }
3110
3111 MultiByteToWideChar(CP_ACP,
3112 0,
3113 lpDisplayName,
3114 -1,
3115 lpDisplayNameW,
3116 strlen(lpDisplayName) + 1);
3117
3118 RegSetValueExW(hServiceKey,
3119 L"DisplayName",
3120 0,
3121 REG_SZ,
3122 (LPBYTE)lpDisplayNameW,
3123 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3124
3125 /* Update lpService->lpDisplayName */
3126 if (lpService->lpDisplayName)
3127 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3128
3129 lpService->lpDisplayName = lpDisplayNameW;
3130 }
3131
3132 if (dwServiceType != SERVICE_NO_CHANGE)
3133 {
3134 /* Set the service type */
3135 dwError = RegSetValueExW(hServiceKey,
3136 L"Type",
3137 0,
3138 REG_DWORD,
3139 (LPBYTE)&dwServiceType,
3140 sizeof(DWORD));
3141 if (dwError != ERROR_SUCCESS)
3142 goto done;
3143
3144 lpService->Status.dwServiceType = dwServiceType;
3145 }
3146
3147 if (dwStartType != SERVICE_NO_CHANGE)
3148 {
3149 /* Set the start value */
3150 dwError = RegSetValueExW(hServiceKey,
3151 L"Start",
3152 0,
3153 REG_DWORD,
3154 (LPBYTE)&dwStartType,
3155 sizeof(DWORD));
3156 if (dwError != ERROR_SUCCESS)
3157 goto done;
3158
3159 lpService->dwStartType = dwStartType;
3160 }
3161
3162 if (dwErrorControl != SERVICE_NO_CHANGE)
3163 {
3164 /* Set the error control value */
3165 dwError = RegSetValueExW(hServiceKey,
3166 L"ErrorControl",
3167 0,
3168 REG_DWORD,
3169 (LPBYTE)&dwErrorControl,
3170 sizeof(DWORD));
3171 if (dwError != ERROR_SUCCESS)
3172 goto done;
3173
3174 lpService->dwErrorControl = dwErrorControl;
3175 }
3176
3177 #if 0
3178 /* FIXME: set the new ImagePath value */
3179
3180 /* Set the image path */
3181 if (dwServiceType & SERVICE_WIN32)
3182 {
3183 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3184 {
3185 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3186 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
3187 dwError = RegSetValueExW(hServiceKey,
3188 L"ImagePath",
3189 0,
3190 REG_EXPAND_SZ,
3191 (LPBYTE)lpBinaryPathNameW,
3192 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3193 if (dwError != ERROR_SUCCESS)
3194 goto done;
3195 }
3196 }
3197 else if (dwServiceType & SERVICE_DRIVER)
3198 {
3199 if (lpImagePath != NULL && *lpImagePath != 0)
3200 {
3201 dwError = RegSetValueExW(hServiceKey,
3202 L"ImagePath",
3203 0,
3204 REG_EXPAND_SZ,
3205 (LPBYTE)lpImagePath,
3206 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3207 if (dwError != ERROR_SUCCESS)
3208 goto done;
3209 }
3210 }
3211 #endif
3212
3213 /* Set the group name */
3214 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3215 {
3216 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3217 0,
3218 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3219 if (lpLoadOrderGroupW == NULL)
3220 {
3221 dwError = ERROR_NOT_ENOUGH_MEMORY;
3222 goto done;
3223 }
3224
3225 MultiByteToWideChar(CP_ACP,
3226 0,
3227 lpLoadOrderGroup,
3228 -1,
3229 lpLoadOrderGroupW,
3230 strlen(lpLoadOrderGroup) + 1);
3231
3232 dwError = RegSetValueExW(hServiceKey,
3233 L"Group",
3234 0,
3235 REG_SZ,
3236 (LPBYTE)lpLoadOrderGroupW,
3237 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3238 if (dwError != ERROR_SUCCESS)
3239 {
3240 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3241 goto done;
3242 }
3243
3244 dwError = ScmSetServiceGroup(lpService,
3245 lpLoadOrderGroupW);
3246
3247 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3248
3249 if (dwError != ERROR_SUCCESS)
3250 goto done;
3251 }
3252
3253 if (lpdwTagId != NULL)
3254 {
3255 dwError = ScmAssignNewTag(lpService);
3256 if (dwError != ERROR_SUCCESS)
3257 goto done;
3258
3259 dwError = RegSetValueExW(hServiceKey,
3260 L"Tag",
3261 0,
3262 REG_DWORD,
3263 (LPBYTE)&lpService->dwTag,
3264 sizeof(DWORD));
3265 if (dwError != ERROR_SUCCESS)
3266 goto done;
3267
3268 *lpdwTagId = lpService->dwTag;
3269 }
3270
3271 /* Write dependencies */
3272 if (lpDependencies != NULL && *lpDependencies != 0)
3273 {
3274 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3275 0,
3276 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3277 if (lpDependenciesW == NULL)
3278 {
3279 dwError = ERROR_NOT_ENOUGH_MEMORY;
3280 goto done;
3281 }
3282
3283 MultiByteToWideChar(CP_ACP,
3284 0,
3285 lpDependencies,
3286 dwDependSize,
3287 lpDependenciesW,
3288 strlen(lpDependencies) + 1);
3289
3290 dwError = ScmWriteDependencies(hServiceKey,
3291 (LPWSTR)lpDependenciesW,
3292 dwDependSize);
3293
3294 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3295 }
3296
3297 if (lpPassword != NULL)
3298 {
3299 /* FIXME: Write password */
3300 }
3301
3302 /* FIXME: Unlock database */
3303
3304 done:
3305 if (hServiceKey != NULL)
3306 RegCloseKey(hServiceKey);
3307
3308 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3309
3310 return dwError;
3311 }
3312
3313
3314 /* Function 24 */
3315 DWORD RCreateServiceA(
3316 SC_RPC_HANDLE hSCManager,
3317 LPSTR lpServiceName,
3318 LPSTR lpDisplayName,
3319 DWORD dwDesiredAccess,
3320 DWORD dwServiceType,
3321 DWORD dwStartType,
3322 DWORD dwErrorControl,
3323 LPSTR lpBinaryPathName,
3324 LPSTR lpLoadOrderGroup,
3325 LPDWORD lpdwTagId,
3326 LPBYTE lpDependencies,
3327 DWORD dwDependSize,
3328 LPSTR lpServiceStartName,
3329 LPBYTE lpPassword,
3330 DWORD dwPwSize,
3331 LPSC_RPC_HANDLE lpServiceHandle)
3332 {
3333 DWORD dwError = ERROR_SUCCESS;
3334 LPWSTR lpServiceNameW = NULL;
3335 LPWSTR lpDisplayNameW = NULL;
3336 LPWSTR lpBinaryPathNameW = NULL;
3337 LPWSTR lpLoadOrderGroupW = NULL;
3338 LPWSTR lpDependenciesW = NULL;
3339 LPWSTR lpServiceStartNameW = NULL;
3340 DWORD dwDependenciesLength = 0;
3341 DWORD dwLength;
3342 int len;
3343 LPSTR lpStr;
3344
3345 if (lpServiceName)
3346 {
3347 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3348 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3349 if (!lpServiceNameW)