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