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