- QueryServiceConfig2A/W: Fail if lpBuffer is NULL but cbBufSize is not 0.
[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 LPWSTR lpDisplayNameW = NULL;
805
806 DPRINT("RChangeServiceConfigW() called\n");
807 DPRINT("dwServiceType = %lu\n", dwServiceType);
808 DPRINT("dwStartType = %lu\n", dwStartType);
809 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
810 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
811 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
812 DPRINT("lpDisplayName = %S\n", lpDisplayName);
813
814 if (ScmShutdown)
815 return ERROR_SHUTDOWN_IN_PROGRESS;
816
817 hSvc = (PSERVICE_HANDLE)hService;
818 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
819 {
820 DPRINT1("Invalid handle tag!\n");
821 return ERROR_INVALID_HANDLE;
822 }
823
824 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
825 SERVICE_CHANGE_CONFIG))
826 {
827 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
828 return ERROR_ACCESS_DENIED;
829 }
830
831 lpService = hSvc->ServiceEntry;
832 if (lpService == NULL)
833 {
834 DPRINT1("lpService == NULL!\n");
835 return ERROR_INVALID_HANDLE;
836 }
837
838 /* FIXME: Lock database exclusively */
839
840 if (lpService->bDeleted)
841 {
842 /* FIXME: Unlock database */
843 DPRINT1("The service has already been marked for delete!\n");
844 return ERROR_SERVICE_MARKED_FOR_DELETE;
845 }
846
847 /* Open the service key */
848 dwError = ScmOpenServiceKey(lpService->szServiceName,
849 KEY_SET_VALUE,
850 &hServiceKey);
851 if (dwError != ERROR_SUCCESS)
852 goto done;
853
854 /* Write service data to the registry */
855 /* Set the display name */
856 if (lpDisplayName != NULL && *lpDisplayName != 0)
857 {
858 RegSetValueExW(hServiceKey,
859 L"DisplayName",
860 0,
861 REG_SZ,
862 (LPBYTE)lpDisplayName,
863 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
864
865 /* Update the display name */
866 lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
867 0,
868 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
869 if (lpDisplayNameW == NULL)
870 {
871 dwError = ERROR_NOT_ENOUGH_MEMORY;
872 goto done;
873 }
874
875 if (lpService->lpDisplayName != lpService->lpServiceName)
876 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
877
878 lpService->lpDisplayName = lpDisplayNameW;
879 }
880
881 if (dwServiceType != SERVICE_NO_CHANGE)
882 {
883 /* Set the service type */
884 dwError = RegSetValueExW(hServiceKey,
885 L"Type",
886 0,
887 REG_DWORD,
888 (LPBYTE)&dwServiceType,
889 sizeof(DWORD));
890 if (dwError != ERROR_SUCCESS)
891 goto done;
892
893 lpService->Status.dwServiceType = dwServiceType;
894 }
895
896 if (dwStartType != SERVICE_NO_CHANGE)
897 {
898 /* Set the start value */
899 dwError = RegSetValueExW(hServiceKey,
900 L"Start",
901 0,
902 REG_DWORD,
903 (LPBYTE)&dwStartType,
904 sizeof(DWORD));
905 if (dwError != ERROR_SUCCESS)
906 goto done;
907
908 lpService->dwStartType = dwStartType;
909 }
910
911 if (dwErrorControl != SERVICE_NO_CHANGE)
912 {
913 /* Set the error control value */
914 dwError = RegSetValueExW(hServiceKey,
915 L"ErrorControl",
916 0,
917 REG_DWORD,
918 (LPBYTE)&dwErrorControl,
919 sizeof(DWORD));
920 if (dwError != ERROR_SUCCESS)
921 goto done;
922
923 lpService->dwErrorControl = dwErrorControl;
924 }
925
926 #if 0
927 /* FIXME: set the new ImagePath value */
928
929 /* Set the image path */
930 if (dwServiceType & SERVICE_WIN32)
931 {
932 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
933 {
934 dwError = RegSetValueExW(hServiceKey,
935 L"ImagePath",
936 0,
937 REG_EXPAND_SZ,
938 (LPBYTE)lpBinaryPathName,
939 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
940 if (dwError != ERROR_SUCCESS)
941 goto done;
942 }
943 }
944 else if (dwServiceType & SERVICE_DRIVER)
945 {
946 if (lpImagePath != NULL && *lpImagePath != 0)
947 {
948 dwError = RegSetValueExW(hServiceKey,
949 L"ImagePath",
950 0,
951 REG_EXPAND_SZ,
952 (LPBYTE)lpImagePath,
953 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
954 if (dwError != ERROR_SUCCESS)
955 goto done;
956 }
957 }
958 #endif
959
960 /* Set the group name */
961 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
962 {
963 dwError = RegSetValueExW(hServiceKey,
964 L"Group",
965 0,
966 REG_SZ,
967 (LPBYTE)lpLoadOrderGroup,
968 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
969 if (dwError != ERROR_SUCCESS)
970 goto done;
971 /* FIXME: update lpService->lpServiceGroup */
972 }
973
974 if (lpdwTagId != NULL)
975 {
976 dwError = ScmAssignNewTag(lpService);
977 if (dwError != ERROR_SUCCESS)
978 goto done;
979
980 dwError = RegSetValueExW(hServiceKey,
981 L"Tag",
982 0,
983 REG_DWORD,
984 (LPBYTE)&lpService->dwTag,
985 sizeof(DWORD));
986 if (dwError != ERROR_SUCCESS)
987 goto done;
988
989 *lpdwTagId = lpService->dwTag;
990 }
991
992 /* Write dependencies */
993 if (lpDependencies != NULL && *lpDependencies != 0)
994 {
995 dwError = ScmWriteDependencies(hServiceKey,
996 (LPWSTR)lpDependencies,
997 dwDependSize);
998 if (dwError != ERROR_SUCCESS)
999 goto done;
1000 }
1001
1002 if (lpPassword != NULL)
1003 {
1004 /* FIXME: Write password */
1005 }
1006
1007 /* FIXME: Unlock database */
1008
1009 done:
1010 if (hServiceKey != NULL)
1011 RegCloseKey(hServiceKey);
1012
1013 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1014
1015 return dwError;
1016 }
1017
1018 /* Create a path suitable for the bootloader out of the full path */
1019 DWORD
1020 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1021 {
1022 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1023 WCHAR Dest;
1024 WCHAR *Expanded;
1025 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1026 OBJECT_ATTRIBUTES ObjectAttributes;
1027 NTSTATUS Status;
1028 HANDLE SymbolicLinkHandle;
1029
1030 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1031
1032 ServiceNameLen = wcslen(CanonName);
1033 /* First check, if it's already good */
1034 if (ServiceNameLen > 12 &&
1035 !wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1036 {
1037 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1038
1039 if (*RelativeName == NULL)
1040 {
1041 DPRINT1("Error allocating memory for boot driver name!\n");
1042 return ERROR_NOT_ENOUGH_MEMORY;
1043 }
1044
1045 /* Copy it */
1046 wcscpy(*RelativeName, CanonName);
1047
1048 DPRINT1("Bootdriver name %S\n", *RelativeName);
1049 return ERROR_SUCCESS;
1050 }
1051
1052 /* If it has %SystemRoot% prefix, substitute it to \System*/
1053 if (ServiceNameLen > 13 &&
1054 !wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1055 {
1056 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1057 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1058
1059 if (*RelativeName == NULL)
1060 {
1061 DPRINT1("Error allocating memory for boot driver name!\n");
1062 return ERROR_NOT_ENOUGH_MEMORY;
1063 }
1064
1065 /* Copy it */
1066 wcscpy(*RelativeName, L"\\SystemRoot\\");
1067 wcscat(*RelativeName, CanonName + 13);
1068
1069 DPRINT1("Bootdriver name %S\n", *RelativeName);
1070 return ERROR_SUCCESS;
1071 }
1072
1073 /* Get buffer size needed for expanding env strings */
1074 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1075
1076 if (BufferSize <= 1)
1077 {
1078 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1079 return ERROR_INVALID_ENVIRONMENT;
1080 }
1081
1082 /* Allocate memory, since the size is known now */
1083 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1084 if (!Expanded)
1085 {
1086 DPRINT1("Error allocating memory for boot driver name!\n");
1087 return ERROR_NOT_ENOUGH_MEMORY;
1088 }
1089
1090 /* Expand it */
1091 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1092 BufferSize)
1093 {
1094 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1095 LocalFree(Expanded);
1096 return ERROR_NOT_ENOUGH_MEMORY;
1097 }
1098
1099 /* Convert to NY-style path */
1100 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1101 {
1102 DPRINT1("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1103 return ERROR_INVALID_ENVIRONMENT;
1104 }
1105
1106 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1107
1108 /* No need to keep the dos-path anymore */
1109 LocalFree(Expanded);
1110
1111 /* Copy it to the allocated place */
1112 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1113 if (!Expanded)
1114 {
1115 DPRINT1("Error allocating memory for boot driver name!\n");
1116 return ERROR_NOT_ENOUGH_MEMORY;
1117 }
1118
1119 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1120 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1121 Expanded[ExpandedLen] = 0;
1122
1123 if (ServiceNameLen > ExpandedLen &&
1124 !wcsnicmp(Expanded, CanonName, ExpandedLen))
1125 {
1126 /* Only \SystemRoot\ is missing */
1127 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1128 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1129
1130 if (*RelativeName == NULL)
1131 {
1132 DPRINT1("Error allocating memory for boot driver name!\n");
1133 LocalFree(Expanded);
1134 return ERROR_NOT_ENOUGH_MEMORY;
1135 }
1136
1137 wcscpy(*RelativeName, L"\\SystemRoot\\");
1138 wcscat(*RelativeName, CanonName + ExpandedLen);
1139
1140 RtlFreeUnicodeString(&NtPathName);
1141 return ERROR_SUCCESS;
1142 }
1143
1144 /* The most complex case starts here */
1145 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1146 InitializeObjectAttributes(&ObjectAttributes,
1147 &SystemRoot,
1148 OBJ_CASE_INSENSITIVE,
1149 NULL,
1150 NULL);
1151
1152 /* Open this symlink */
1153 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1154
1155 if (NT_SUCCESS(Status))
1156 {
1157 LinkTarget.Length = 0;
1158 LinkTarget.MaximumLength = 0;
1159
1160 DPRINT("Opened symbolic link object\n");
1161
1162 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1163 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1164 {
1165 /* Check if required buffer size is sane */
1166 if (BufferSize > 0xFFFD)
1167 {
1168 DPRINT1("Too large buffer required\n");
1169 *RelativeName = 0;
1170
1171 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1172 LocalFree(Expanded);
1173 return ERROR_NOT_ENOUGH_MEMORY;
1174 }
1175
1176 /* Alloc the string */
1177 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1178 if (!LinkTarget.Buffer)
1179 {
1180 DPRINT1("Unable to alloc buffer\n");
1181 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1182 LocalFree(Expanded);
1183 return ERROR_NOT_ENOUGH_MEMORY;
1184 }
1185
1186 /* Do a real query now */
1187 LinkTarget.Length = BufferSize;
1188 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1189
1190 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1191 if (NT_SUCCESS(Status))
1192 {
1193 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1194
1195 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1196 if ((ServiceNameLen > ExpandedLen) &&
1197 !wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1198 {
1199 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1200 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1201
1202 if (*RelativeName == NULL)
1203 {
1204 DPRINT1("Unable to alloc buffer\n");
1205 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1206 LocalFree(Expanded);
1207 RtlFreeUnicodeString(&NtPathName);
1208 return ERROR_NOT_ENOUGH_MEMORY;
1209 }
1210
1211 /* Copy it over, substituting the first part
1212 with SystemRoot */
1213 wcscpy(*RelativeName, L"\\SystemRoot\\");
1214 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1215
1216 /* Cleanup */
1217 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1218 LocalFree(Expanded);
1219 RtlFreeUnicodeString(&NtPathName);
1220
1221 /* Return success */
1222 return ERROR_SUCCESS;
1223 }
1224 else
1225 {
1226 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1227 LocalFree(Expanded);
1228 RtlFreeUnicodeString(&NtPathName);
1229 return ERROR_INVALID_PARAMETER;
1230 }
1231 }
1232 else
1233 {
1234 DPRINT1("Error, Status = %08X\n", Status);
1235 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1236 LocalFree(Expanded);
1237 RtlFreeUnicodeString(&NtPathName);
1238 return ERROR_INVALID_PARAMETER;
1239 }
1240 }
1241 else
1242 {
1243 DPRINT1("Error, Status = %08X\n", Status);
1244 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1245 LocalFree(Expanded);
1246 RtlFreeUnicodeString(&NtPathName);
1247 return ERROR_INVALID_PARAMETER;
1248 }
1249 }
1250 else
1251 {
1252 DPRINT1("Error, Status = %08X\n", Status);
1253 LocalFree(Expanded);
1254 return ERROR_INVALID_PARAMETER;
1255 }
1256
1257 /* Failure */
1258 *RelativeName = NULL;
1259 return ERROR_INVALID_PARAMETER;
1260 }
1261
1262 DWORD
1263 ScmCanonDriverImagePath(DWORD dwStartType,
1264 wchar_t *lpServiceName,
1265 wchar_t **lpCanonName)
1266 {
1267 DWORD ServiceNameLen, Result;
1268 UNICODE_STRING NtServiceName;
1269 WCHAR *RelativeName;
1270 WCHAR *SourceName = lpServiceName;
1271
1272 /* Calculate the length of the service's name */
1273 ServiceNameLen = wcslen(lpServiceName);
1274
1275 /* 12 is wcslen(L"\\SystemRoot\\") */
1276 if (ServiceNameLen > 12 &&
1277 !wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1278 {
1279 /* SystemRoot prefix is already included */
1280
1281 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1282
1283 if (*lpCanonName == NULL)
1284 {
1285 DPRINT1("Error allocating memory for canonized service name!\n");
1286 return ERROR_NOT_ENOUGH_MEMORY;
1287 }
1288
1289 /* If it's a boot-time driver, it must be systemroot relative */
1290 if (dwStartType == SERVICE_BOOT_START)
1291 SourceName += 12;
1292
1293 /* Copy it */
1294 wcscpy(*lpCanonName, SourceName);
1295
1296 DPRINT("Canonicalized name %S\n", *lpCanonName);
1297 return NO_ERROR;
1298 }
1299
1300 /* Check if it has %SystemRoot% (len=13) */
1301 if (ServiceNameLen > 13 &&
1302 !wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1303 {
1304 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1305 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1306
1307 if (*lpCanonName == NULL)
1308 {
1309 DPRINT1("Error allocating memory for canonized service name!\n");
1310 return ERROR_NOT_ENOUGH_MEMORY;
1311 }
1312
1313 /* If it's a boot-time driver, it must be systemroot relative */
1314 if (dwStartType == SERVICE_BOOT_START)
1315 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1316
1317 wcscat(*lpCanonName, lpServiceName + 13);
1318
1319 DPRINT("Canonicalized name %S\n", *lpCanonName);
1320 return NO_ERROR;
1321 }
1322
1323 /* Check if it's a relative path name */
1324 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1325 {
1326 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1327
1328 if (*lpCanonName == NULL)
1329 {
1330 DPRINT1("Error allocating memory for canonized service name!\n");
1331 return ERROR_NOT_ENOUGH_MEMORY;
1332 }
1333
1334 /* Just copy it over without changing */
1335 wcscpy(*lpCanonName, lpServiceName);
1336
1337 return NO_ERROR;
1338 }
1339
1340 /* It seems to be a DOS path, convert it */
1341 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1342 {
1343 DPRINT1("RtlDosPathNameToNtPathName_U() failed!\n");
1344 return ERROR_INVALID_PARAMETER;
1345 }
1346
1347 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1348
1349 if (*lpCanonName == NULL)
1350 {
1351 DPRINT1("Error allocating memory for canonized service name!\n");
1352 RtlFreeUnicodeString(&NtServiceName);
1353 return ERROR_NOT_ENOUGH_MEMORY;
1354 }
1355
1356 /* Copy the string */
1357 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1358
1359 /* The unicode string is not needed anymore */
1360 RtlFreeUnicodeString(&NtServiceName);
1361
1362 if (dwStartType != SERVICE_BOOT_START)
1363 {
1364 DPRINT("Canonicalized name %S\n", *lpCanonName);
1365 return NO_ERROR;
1366 }
1367
1368 /* The service is boot-started, so must be relative */
1369 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1370 if (Result)
1371 {
1372 /* There is a problem, free name and return */
1373 LocalFree(*lpCanonName);
1374 DPRINT1("Error converting named!\n");
1375 return Result;
1376 }
1377
1378 ASSERT(RelativeName);
1379
1380 /* Copy that string */
1381 wcscpy(*lpCanonName, RelativeName + 12);
1382
1383 /* Free the allocated buffer */
1384 LocalFree(RelativeName);
1385
1386 DPRINT("Canonicalized name %S\n", *lpCanonName);
1387
1388 /* Success */
1389 return NO_ERROR;
1390 }
1391
1392
1393 /* Function 12 */
1394 DWORD RCreateServiceW(
1395 handle_t BindingHandle,
1396 SC_RPC_HANDLE hSCManager,
1397 LPWSTR lpServiceName,
1398 LPWSTR lpDisplayName,
1399 DWORD dwDesiredAccess,
1400 DWORD dwServiceType,
1401 DWORD dwStartType,
1402 DWORD dwErrorControl,
1403 LPWSTR lpBinaryPathName,
1404 LPWSTR lpLoadOrderGroup,
1405 LPDWORD lpdwTagId,
1406 LPBYTE lpDependencies,
1407 DWORD dwDependSize,
1408 LPWSTR lpServiceStartName,
1409 LPBYTE lpPassword,
1410 DWORD dwPwSize,
1411 LPSC_RPC_HANDLE lpServiceHandle)
1412 {
1413 PMANAGER_HANDLE hManager;
1414 DWORD dwError = ERROR_SUCCESS;
1415 PSERVICE lpService = NULL;
1416 SC_HANDLE hServiceHandle = NULL;
1417 LPWSTR lpImagePath = NULL;
1418 HKEY hServiceKey = NULL;
1419
1420 DPRINT("RCreateServiceW() called\n");
1421 DPRINT("lpServiceName = %S\n", lpServiceName);
1422 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1423 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1424 DPRINT("dwServiceType = %lu\n", dwServiceType);
1425 DPRINT("dwStartType = %lu\n", dwStartType);
1426 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1427 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1428 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1429
1430 if (ScmShutdown)
1431 return ERROR_SHUTDOWN_IN_PROGRESS;
1432
1433 hManager = (PMANAGER_HANDLE)hSCManager;
1434 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1435 {
1436 DPRINT1("Invalid manager handle!\n");
1437 return ERROR_INVALID_HANDLE;
1438 }
1439
1440 /* Check access rights */
1441 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1442 SC_MANAGER_CREATE_SERVICE))
1443 {
1444 DPRINT1("Insufficient access rights! 0x%lx\n",
1445 hManager->Handle.DesiredAccess);
1446 return ERROR_ACCESS_DENIED;
1447 }
1448
1449 /* Fail if the service already exists! */
1450 if (ScmGetServiceEntryByName(lpServiceName) != NULL)
1451 return ERROR_SERVICE_EXISTS;
1452
1453 if (dwServiceType & SERVICE_DRIVER)
1454 {
1455 dwError = ScmCanonDriverImagePath(dwStartType,
1456 lpBinaryPathName,
1457 &lpImagePath);
1458
1459 if (dwError != ERROR_SUCCESS)
1460 goto done;
1461 }
1462
1463 /* Allocate a new service entry */
1464 dwError = ScmCreateNewServiceRecord(lpServiceName,
1465 &lpService);
1466 if (dwError != ERROR_SUCCESS)
1467 goto done;
1468
1469 /* Fill the new service entry */
1470 lpService->Status.dwServiceType = dwServiceType;
1471 lpService->dwStartType = dwStartType;
1472 lpService->dwErrorControl = dwErrorControl;
1473
1474 /* Fill the display name */
1475 if (lpDisplayName != NULL &&
1476 *lpDisplayName != 0 &&
1477 wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1478 {
1479 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1480 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1481 if (lpService->lpDisplayName == NULL)
1482 {
1483 dwError = ERROR_NOT_ENOUGH_MEMORY;
1484 goto done;
1485 }
1486 wcscpy(lpService->lpDisplayName, lpDisplayName);
1487 }
1488
1489 /* Assign the service to a group */
1490 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1491 {
1492 dwError = ScmSetServiceGroup(lpService,
1493 lpLoadOrderGroup);
1494 if (dwError != ERROR_SUCCESS)
1495 goto done;
1496 }
1497
1498 /* Assign a new tag */
1499 if (lpdwTagId != NULL)
1500 {
1501 dwError = ScmAssignNewTag(lpService);
1502 if (dwError != ERROR_SUCCESS)
1503 goto done;
1504 }
1505
1506 /* Write service data to the registry */
1507 /* Create the service key */
1508 dwError = ScmCreateServiceKey(lpServiceName,
1509 KEY_WRITE,
1510 &hServiceKey);
1511 if (dwError != ERROR_SUCCESS)
1512 goto done;
1513
1514 /* Set the display name */
1515 if (lpDisplayName != NULL && *lpDisplayName != 0)
1516 {
1517 RegSetValueExW(hServiceKey,
1518 L"DisplayName",
1519 0,
1520 REG_SZ,
1521 (LPBYTE)lpDisplayName,
1522 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1523 }
1524
1525 /* Set the service type */
1526 dwError = RegSetValueExW(hServiceKey,
1527 L"Type",
1528 0,
1529 REG_DWORD,
1530 (LPBYTE)&dwServiceType,
1531 sizeof(DWORD));
1532 if (dwError != ERROR_SUCCESS)
1533 goto done;
1534
1535 /* Set the start value */
1536 dwError = RegSetValueExW(hServiceKey,
1537 L"Start",
1538 0,
1539 REG_DWORD,
1540 (LPBYTE)&dwStartType,
1541 sizeof(DWORD));
1542 if (dwError != ERROR_SUCCESS)
1543 goto done;
1544
1545 /* Set the error control value */
1546 dwError = RegSetValueExW(hServiceKey,
1547 L"ErrorControl",
1548 0,
1549 REG_DWORD,
1550 (LPBYTE)&dwErrorControl,
1551 sizeof(DWORD));
1552 if (dwError != ERROR_SUCCESS)
1553 goto done;
1554
1555 /* Set the image path */
1556 if (dwServiceType & SERVICE_WIN32)
1557 {
1558 dwError = RegSetValueExW(hServiceKey,
1559 L"ImagePath",
1560 0,
1561 REG_EXPAND_SZ,
1562 (LPBYTE)lpBinaryPathName,
1563 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1564 if (dwError != ERROR_SUCCESS)
1565 goto done;
1566 }
1567 else if (dwServiceType & SERVICE_DRIVER)
1568 {
1569 dwError = RegSetValueExW(hServiceKey,
1570 L"ImagePath",
1571 0,
1572 REG_EXPAND_SZ,
1573 (LPBYTE)lpImagePath,
1574 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
1575 if (dwError != ERROR_SUCCESS)
1576 goto done;
1577 }
1578
1579 /* Set the group name */
1580 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1581 {
1582 dwError = RegSetValueExW(hServiceKey,
1583 L"Group",
1584 0,
1585 REG_SZ,
1586 (LPBYTE)lpLoadOrderGroup,
1587 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1588 if (dwError != ERROR_SUCCESS)
1589 goto done;
1590 }
1591
1592 if (lpdwTagId != NULL)
1593 {
1594 dwError = RegSetValueExW(hServiceKey,
1595 L"Tag",
1596 0,
1597 REG_DWORD,
1598 (LPBYTE)&lpService->dwTag,
1599 sizeof(DWORD));
1600 if (dwError != ERROR_SUCCESS)
1601 goto done;
1602 }
1603
1604 /* Write dependencies */
1605 if (lpDependencies != NULL && *lpDependencies != 0)
1606 {
1607 dwError = ScmWriteDependencies(hServiceKey,
1608 (LPWSTR)lpDependencies,
1609 dwDependSize);
1610 if (dwError != ERROR_SUCCESS)
1611 goto done;
1612 }
1613
1614 if (lpPassword != NULL)
1615 {
1616 /* FIXME: Write password */
1617 }
1618
1619 dwError = ScmCreateServiceHandle(lpService,
1620 &hServiceHandle);
1621 if (dwError != ERROR_SUCCESS)
1622 goto done;
1623
1624 dwError = ScmCheckAccess(hServiceHandle,
1625 dwDesiredAccess);
1626 if (dwError != ERROR_SUCCESS)
1627 goto done;
1628
1629 done:;
1630 if (hServiceKey != NULL)
1631 RegCloseKey(hServiceKey);
1632
1633 if (dwError == ERROR_SUCCESS)
1634 {
1635 DPRINT("hService %p\n", hServiceHandle);
1636 *lpServiceHandle = (unsigned long)hServiceHandle; /* FIXME: 64 bit portability */
1637
1638 if (lpdwTagId != NULL)
1639 *lpdwTagId = lpService->dwTag;
1640 }
1641 else
1642 {
1643 /* Release the display name buffer */
1644 if (lpService->lpServiceName != NULL)
1645 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1646
1647 if (hServiceHandle)
1648 {
1649 /* Remove the service handle */
1650 HeapFree(GetProcessHeap(), 0, hServiceHandle);
1651 }
1652
1653 if (lpService != NULL)
1654 {
1655 /* FIXME: remove the service entry */
1656 }
1657 }
1658
1659 if (lpImagePath != NULL)
1660 HeapFree(GetProcessHeap(), 0, lpImagePath);
1661
1662 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
1663
1664 return dwError;
1665 }
1666
1667
1668 /* Function 13 */
1669 DWORD REnumDependentServicesW(
1670 handle_t BindingHandle,
1671 SC_RPC_HANDLE hService,
1672 DWORD dwServiceState,
1673 LPBYTE lpServices,
1674 DWORD cbBufSize,
1675 LPBOUNDED_DWORD_256K pcbBytesNeeded,
1676 LPBOUNDED_DWORD_256K lpServicesReturned)
1677 {
1678 DWORD dwError = ERROR_SUCCESS;
1679
1680 UNIMPLEMENTED;
1681 *pcbBytesNeeded = 0;
1682 *lpServicesReturned = 0;
1683
1684 DPRINT1("REnumDependentServicesW() done (Error %lu)\n", dwError);
1685
1686 return dwError;
1687 }
1688
1689
1690 /* Function 14 */
1691 DWORD REnumServicesStatusW(
1692 handle_t BindingHandle,
1693 SC_RPC_HANDLE hSCManager,
1694 DWORD dwServiceType,
1695 DWORD dwServiceState,
1696 LPBYTE lpBuffer,
1697 DWORD dwBufSize,
1698 LPBOUNDED_DWORD_256K pcbBytesNeeded,
1699 LPBOUNDED_DWORD_256K lpServicesReturned,
1700 LPBOUNDED_DWORD_256K lpResumeHandle)
1701 {
1702 PMANAGER_HANDLE hManager;
1703 PSERVICE lpService;
1704 DWORD dwError = ERROR_SUCCESS;
1705 PLIST_ENTRY ServiceEntry;
1706 PSERVICE CurrentService;
1707 DWORD dwState;
1708 DWORD dwRequiredSize;
1709 DWORD dwServiceCount;
1710 DWORD dwSize;
1711 DWORD dwLastResumeCount;
1712 LPENUM_SERVICE_STATUSW lpStatusPtr;
1713 LPWSTR lpStringPtr;
1714
1715 DPRINT("REnumServicesStatusW() called\n");
1716
1717 if (ScmShutdown)
1718 return ERROR_SHUTDOWN_IN_PROGRESS;
1719
1720 hManager = (PMANAGER_HANDLE)hSCManager;
1721 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1722 {
1723 DPRINT1("Invalid manager handle!\n");
1724 return ERROR_INVALID_HANDLE;
1725 }
1726
1727 /* Check access rights */
1728 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1729 SC_MANAGER_ENUMERATE_SERVICE))
1730 {
1731 DPRINT1("Insufficient access rights! 0x%lx\n",
1732 hManager->Handle.DesiredAccess);
1733 return ERROR_ACCESS_DENIED;
1734 }
1735
1736 *pcbBytesNeeded = 0;
1737 *lpServicesReturned = 0;
1738
1739 dwLastResumeCount = *lpResumeHandle;
1740
1741 /* FIXME: Lock the service list shared */
1742
1743 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
1744 if (lpService == NULL)
1745 {
1746 dwError = ERROR_SUCCESS;
1747 goto Done;
1748 }
1749
1750 dwRequiredSize = 0;
1751 dwServiceCount = 0;
1752
1753 for (ServiceEntry = &lpService->ServiceListEntry;
1754 ServiceEntry != &ServiceListHead;
1755 ServiceEntry = ServiceEntry->Flink)
1756 {
1757 CurrentService = CONTAINING_RECORD(ServiceEntry,
1758 SERVICE,
1759 ServiceListEntry);
1760
1761 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
1762 continue;
1763
1764 dwState = SERVICE_ACTIVE;
1765 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
1766 dwState = SERVICE_INACTIVE;
1767
1768 if ((dwState & dwServiceState) == 0)
1769 continue;
1770
1771 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
1772 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
1773 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
1774
1775 if (dwRequiredSize + dwSize <= dwBufSize)
1776 {
1777 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
1778 dwRequiredSize += dwSize;
1779 dwServiceCount++;
1780 dwLastResumeCount = CurrentService->dwResumeCount;
1781 }
1782 else
1783 {
1784 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
1785 break;
1786 }
1787
1788 }
1789
1790 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
1791 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
1792
1793 for (;
1794 ServiceEntry != &ServiceListHead;
1795 ServiceEntry = ServiceEntry->Flink)
1796 {
1797 CurrentService = CONTAINING_RECORD(ServiceEntry,
1798 SERVICE,
1799 ServiceListEntry);
1800
1801 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
1802 continue;
1803
1804 dwState = SERVICE_ACTIVE;
1805 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
1806 dwState = SERVICE_INACTIVE;
1807
1808 if ((dwState & dwServiceState) == 0)
1809 continue;
1810
1811 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
1812 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
1813 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
1814
1815 dwError = ERROR_MORE_DATA;
1816 }
1817
1818 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
1819
1820 *lpResumeHandle = dwLastResumeCount;
1821 *lpServicesReturned = dwServiceCount;
1822 *pcbBytesNeeded = dwRequiredSize;
1823
1824 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
1825 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
1826 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
1827
1828 dwRequiredSize = 0;
1829 for (ServiceEntry = &lpService->ServiceListEntry;
1830 ServiceEntry != &ServiceListHead;
1831 ServiceEntry = ServiceEntry->Flink)
1832 {
1833 CurrentService = CONTAINING_RECORD(ServiceEntry,
1834 SERVICE,
1835 ServiceListEntry);
1836
1837 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
1838 continue;
1839
1840 dwState = SERVICE_ACTIVE;
1841 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
1842 dwState = SERVICE_INACTIVE;
1843
1844 if ((dwState & dwServiceState) == 0)
1845 continue;
1846
1847 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
1848 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
1849 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
1850
1851 if (dwRequiredSize + dwSize <= dwBufSize)
1852 {
1853 /* Copy the service name */
1854 wcscpy(lpStringPtr,
1855 CurrentService->lpServiceName);
1856 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
1857 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
1858
1859 /* Copy the display name */
1860 wcscpy(lpStringPtr,
1861 CurrentService->lpDisplayName);
1862 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
1863 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
1864
1865 /* Copy the status information */
1866 memcpy(&lpStatusPtr->ServiceStatus,
1867 &CurrentService->Status,
1868 sizeof(SERVICE_STATUS));
1869
1870 lpStatusPtr++;
1871 dwRequiredSize += dwSize;
1872 }
1873 else
1874 {
1875 break;
1876 }
1877
1878 }
1879
1880 Done:;
1881 /* FIXME: Unlock the service list */
1882
1883 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
1884
1885 return dwError;
1886 }
1887
1888
1889 /* Function 15 */
1890 DWORD ROpenSCManagerW(
1891 handle_t BindingHandle,
1892 LPWSTR lpMachineName,
1893 LPWSTR lpDatabaseName,
1894 DWORD dwDesiredAccess,
1895 LPSC_RPC_HANDLE lpScHandle)
1896 {
1897 DWORD dwError;
1898 SC_HANDLE hHandle;
1899
1900 DPRINT("ROpenSCManagerW() called\n");
1901 DPRINT("lpMachineName = %p\n", lpMachineName);
1902 DPRINT("lpMachineName: %S\n", lpMachineName);
1903 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
1904 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
1905 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
1906
1907 if (ScmShutdown)
1908 return ERROR_SHUTDOWN_IN_PROGRESS;
1909
1910 if (!lpScHandle)
1911 return ERROR_INVALID_PARAMETER;
1912
1913 dwError = ScmCreateManagerHandle(lpDatabaseName,
1914 &hHandle);
1915 if (dwError != ERROR_SUCCESS)
1916 {
1917 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
1918 return dwError;
1919 }
1920
1921 /* Check the desired access */
1922 dwError = ScmCheckAccess(hHandle,
1923 dwDesiredAccess | SC_MANAGER_CONNECT);
1924 if (dwError != ERROR_SUCCESS)
1925 {
1926 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
1927 HeapFree(GetProcessHeap(), 0, hHandle);
1928 return dwError;
1929 }
1930
1931 *lpScHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
1932 DPRINT("*hScm = %p\n", *lpScHandle);
1933
1934 DPRINT("ROpenSCManagerW() done\n");
1935
1936 return ERROR_SUCCESS;
1937 }
1938
1939
1940 /* Function 16 */
1941 DWORD ROpenServiceW(
1942 handle_t BindingHandle,
1943 SC_RPC_HANDLE hSCManager,
1944 LPWSTR lpServiceName,
1945 DWORD dwDesiredAccess,
1946 LPSC_RPC_HANDLE lpServiceHandle)
1947 {
1948 PSERVICE lpService;
1949 PMANAGER_HANDLE hManager;
1950 SC_HANDLE hHandle;
1951 DWORD dwError;
1952
1953 DPRINT("ROpenServiceW() called\n");
1954 DPRINT("hSCManager = %p\n", hSCManager);
1955 DPRINT("lpServiceName = %p\n", lpServiceName);
1956 DPRINT("lpServiceName: %S\n", lpServiceName);
1957 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
1958
1959 if (ScmShutdown)
1960 return ERROR_SHUTDOWN_IN_PROGRESS;
1961
1962 if (!lpServiceHandle)
1963 return ERROR_INVALID_PARAMETER;
1964
1965 if (!lpServiceName)
1966 return ERROR_INVALID_ADDRESS;
1967
1968 hManager = (PMANAGER_HANDLE)hSCManager;
1969 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1970 {
1971 DPRINT1("Invalid manager handle!\n");
1972 return ERROR_INVALID_HANDLE;
1973 }
1974
1975 /* FIXME: Lock the service list */
1976
1977 /* Get service database entry */
1978 lpService = ScmGetServiceEntryByName(lpServiceName);
1979 if (lpService == NULL)
1980 {
1981 DPRINT("Could not find a service!\n");
1982 return ERROR_SERVICE_DOES_NOT_EXIST;
1983 }
1984
1985 /* Create a service handle */
1986 dwError = ScmCreateServiceHandle(lpService,
1987 &hHandle);
1988 if (dwError != ERROR_SUCCESS)
1989 {
1990 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
1991 return dwError;
1992 }
1993
1994 /* Check the desired access */
1995 dwError = ScmCheckAccess(hHandle,
1996 dwDesiredAccess);
1997 if (dwError != ERROR_SUCCESS)
1998 {
1999 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2000 HeapFree(GetProcessHeap(), 0, hHandle);
2001 return dwError;
2002 }
2003
2004 *lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
2005 DPRINT("*hService = %p\n", *lpServiceHandle);
2006
2007 DPRINT("ROpenServiceW() done\n");
2008
2009 return ERROR_SUCCESS;
2010 }
2011
2012
2013 /* Function 17 */
2014 DWORD RQueryServiceConfigW(
2015 handle_t BindingHandle,
2016 SC_RPC_HANDLE hService,
2017 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2018 DWORD cbBufSize,
2019 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2020 {
2021 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2022 DWORD dwError = ERROR_SUCCESS;
2023 PSERVICE_HANDLE hSvc;
2024 PSERVICE lpService = NULL;
2025 HKEY hServiceKey = NULL;
2026 LPWSTR lpImagePath = NULL;
2027 LPWSTR lpServiceStartName = NULL;
2028 DWORD dwRequiredSize;
2029 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2030 WCHAR lpEmptyString[] = {0,0};
2031 LPWSTR lpStr;
2032
2033 DPRINT("RQueryServiceConfigW() called\n");
2034
2035 if (ScmShutdown)
2036 return ERROR_SHUTDOWN_IN_PROGRESS;
2037
2038 hSvc = (PSERVICE_HANDLE)hService;
2039 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2040 {
2041 DPRINT1("Invalid handle tag!\n");
2042 return ERROR_INVALID_HANDLE;
2043 }
2044
2045 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2046 SERVICE_QUERY_CONFIG))
2047 {
2048 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2049 return ERROR_ACCESS_DENIED;
2050 }
2051
2052 lpService = hSvc->ServiceEntry;
2053 if (lpService == NULL)
2054 {
2055 DPRINT1("lpService == NULL!\n");
2056 return ERROR_INVALID_HANDLE;
2057 }
2058
2059 /* FIXME: Lock the service database shared */
2060
2061 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2062 KEY_READ,
2063 &hServiceKey);
2064 if (dwError != ERROR_SUCCESS)
2065 goto Done;
2066
2067 dwError = ScmReadString(hServiceKey,
2068 L"ImagePath",
2069 &lpImagePath);
2070 if (dwError != ERROR_SUCCESS)
2071 goto Done;
2072
2073 ScmReadString(hServiceKey,
2074 L"ObjectName",
2075 &lpServiceStartName);
2076
2077 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2078
2079 if (lpImagePath != NULL)
2080 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2081 else
2082 dwRequiredSize += 2 * sizeof(WCHAR);
2083
2084 if (lpService->lpGroup != NULL)
2085 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2086 else
2087 dwRequiredSize += 2 * sizeof(WCHAR);
2088
2089 /* FIXME: Add Dependencies length*/
2090
2091 if (lpServiceStartName != NULL)
2092 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2093 else
2094 dwRequiredSize += 2 * sizeof(WCHAR);
2095
2096 if (lpService->lpDisplayName != NULL)
2097 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2098 else
2099 dwRequiredSize += 2 * sizeof(WCHAR);
2100
2101 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2102 {
2103 dwError = ERROR_INSUFFICIENT_BUFFER;
2104 }
2105 else
2106 {
2107 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2108 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2109 lpConfig->dwStartType = lpService->dwStartType;
2110 lpConfig->dwErrorControl = lpService->dwErrorControl;
2111 lpConfig->dwTagId = lpService->dwTag;
2112
2113 lpStr = (LPWSTR)(lpConfig + 1);
2114
2115 if (lpImagePath != NULL)
2116 {
2117 wcscpy(lpStr, lpImagePath);
2118 }
2119 else
2120 {
2121 wcscpy(lpStr, lpEmptyString);
2122 }
2123
2124 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2125 lpStr += (wcslen(lpStr) + 1);
2126
2127 if (lpService->lpGroup != NULL)
2128 {
2129 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2130 }
2131 else
2132 {
2133 wcscpy(lpStr, lpEmptyString);
2134 }
2135
2136 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2137 lpStr += (wcslen(lpStr) + 1);
2138
2139 /* FIXME: Append Dependencies */
2140 wcscpy(lpStr, lpEmptyString);
2141
2142 lpStr += (wcslen(lpStr) + 1);
2143 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2144
2145 if (lpServiceStartName != NULL)
2146 {
2147 wcscpy(lpStr, lpServiceStartName);
2148 }
2149 else
2150 {
2151 wcscpy(lpStr, lpEmptyString);
2152 }
2153
2154 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2155 lpStr += (wcslen(lpStr) + 1);
2156
2157 if (lpService->lpDisplayName != NULL)
2158 {
2159 wcscpy(lpStr, lpService->lpDisplayName);
2160 }
2161 else
2162 {
2163 wcscpy(lpStr, lpEmptyString);
2164 }
2165
2166 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2167 }
2168
2169 if (pcbBytesNeeded != NULL)
2170 *pcbBytesNeeded = dwRequiredSize;
2171
2172 Done:;
2173 if (lpImagePath != NULL)
2174 HeapFree(GetProcessHeap(), 0, lpImagePath);
2175
2176 if (lpServiceStartName != NULL)
2177 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2178
2179 if (hServiceKey != NULL)
2180 RegCloseKey(hServiceKey);
2181
2182 /* FIXME: Unlock the service database */
2183
2184 DPRINT("RQueryServiceConfigW() done\n");
2185
2186 return dwError;
2187 }
2188
2189
2190 /* Function 18 */
2191 DWORD RQueryServiceLockStatusW(
2192 handle_t BindingHandle,
2193 SC_RPC_HANDLE hSCManager,
2194 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2195 DWORD cbBufSize,
2196 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2197 {
2198 UNIMPLEMENTED;
2199 return ERROR_CALL_NOT_IMPLEMENTED;
2200 }
2201
2202
2203 /* Function 19 */
2204 DWORD RStartServiceW(
2205 handle_t BindingHandle,
2206 SC_RPC_HANDLE hService,
2207 DWORD argc,
2208 LPSTRING_PTRSW argv)
2209 {
2210 DWORD dwError = ERROR_SUCCESS;
2211 PSERVICE_HANDLE hSvc;
2212 PSERVICE lpService = NULL;
2213
2214 DPRINT("RStartServiceW() called\n");
2215
2216 if (ScmShutdown)
2217 return ERROR_SHUTDOWN_IN_PROGRESS;
2218
2219 hSvc = (PSERVICE_HANDLE)hService;
2220 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2221 {
2222 DPRINT1("Invalid handle tag!\n");
2223 return ERROR_INVALID_HANDLE;
2224 }
2225
2226 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2227 SERVICE_START))
2228 {
2229 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2230 return ERROR_ACCESS_DENIED;
2231 }
2232
2233 lpService = hSvc->ServiceEntry;
2234 if (lpService == NULL)
2235 {
2236 DPRINT1("lpService == NULL!\n");
2237 return ERROR_INVALID_HANDLE;
2238 }
2239
2240 if (lpService->dwStartType == SERVICE_DISABLED)
2241 return ERROR_SERVICE_DISABLED;
2242
2243 if (lpService->bDeleted)
2244 return ERROR_SERVICE_MARKED_FOR_DELETE;
2245
2246 if (argv) {
2247 UNIMPLEMENTED;
2248 argv = NULL;
2249 }
2250
2251 /* Start the service */
2252 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2253
2254 return dwError;
2255 }
2256
2257
2258 /* Function 20 */
2259 DWORD RGetServiceDisplayNameW(
2260 handle_t BindingHandle,
2261 SC_RPC_HANDLE hSCManager,
2262 LPWSTR lpServiceName,
2263 LPWSTR lpDisplayName,
2264 DWORD *lpcchBuffer)
2265 {
2266 // PMANAGER_HANDLE hManager;
2267 PSERVICE lpService;
2268 DWORD dwLength;
2269 DWORD dwError;
2270
2271 DPRINT("RGetServiceDisplayNameW() called\n");
2272 DPRINT("hSCManager = %p\n", hSCManager);
2273 DPRINT("lpServiceName: %S\n", lpServiceName);
2274 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2275 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2276
2277 // hManager = (PMANAGER_HANDLE)hSCManager;
2278 // if (hManager->Handle.Tag != MANAGER_TAG)
2279 // {
2280 // DPRINT1("Invalid manager handle!\n");
2281 // return ERROR_INVALID_HANDLE;
2282 // }
2283
2284 /* Get service database entry */
2285 lpService = ScmGetServiceEntryByName(lpServiceName);
2286 if (lpService == NULL)
2287 {
2288 DPRINT1("Could not find a service!\n");
2289
2290 /* If the service could not be found and lpcchBuffer is 0, windows
2291 puts null in lpDisplayName and puts 1 in lpcchBuffer */
2292 if (*lpcchBuffer == 0)
2293 {
2294 *lpcchBuffer = 1;
2295 *lpDisplayName = '\0';
2296 }
2297
2298 return ERROR_SERVICE_DOES_NOT_EXIST;
2299 }
2300
2301 if (!lpService->lpDisplayName)
2302 {
2303 dwLength = wcslen(lpService->lpServiceName);
2304
2305 if (lpServiceName != NULL &&
2306 *lpcchBuffer > dwLength)
2307 {
2308 wcscpy(lpDisplayName, lpService->lpServiceName);
2309 }
2310 }
2311 else
2312 {
2313 dwLength = wcslen(lpService->lpDisplayName);
2314
2315 if (lpDisplayName != NULL &&
2316 *lpcchBuffer > dwLength)
2317 {
2318 wcscpy(lpDisplayName, lpService->lpDisplayName);
2319 }
2320 }
2321
2322 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2323
2324 *lpcchBuffer = dwLength;
2325
2326 return dwError;
2327 }
2328
2329
2330 /* Function 21 */
2331 DWORD RGetServiceKeyNameW(
2332 handle_t BindingHandle,
2333 SC_RPC_HANDLE hSCManager,
2334 LPWSTR lpDisplayName,
2335 LPWSTR lpServiceName,
2336 DWORD *lpcchBuffer)
2337 {
2338 // PMANAGER_HANDLE hManager;
2339 PSERVICE lpService;
2340 DWORD dwLength;
2341 DWORD dwError;
2342
2343 DPRINT("RGetServiceKeyNameW() called\n");
2344 DPRINT("hSCManager = %p\n", hSCManager);
2345 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2346 DPRINT("lpServiceName: %p\n", lpServiceName);
2347 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2348
2349 // hManager = (PMANAGER_HANDLE)hSCManager;
2350 // if (hManager->Handle.Tag != MANAGER_TAG)
2351 // {
2352 // DPRINT1("Invalid manager handle!\n");
2353 // return ERROR_INVALID_HANDLE;
2354 // }
2355
2356 /* Get service database entry */
2357 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2358 if (lpService == NULL)
2359 {
2360 DPRINT1("Could not find a service!\n");
2361
2362 /* If the service could not be found and lpcchBuffer is 0, windows
2363 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2364 if (*lpcchBuffer == 0)
2365 {
2366 *lpcchBuffer = 2;
2367 *lpServiceName = '\0';
2368 }
2369
2370 return ERROR_SERVICE_DOES_NOT_EXIST;
2371 }
2372
2373 dwLength = wcslen(lpService->lpServiceName);
2374
2375 if (lpServiceName != NULL &&
2376 *lpcchBuffer > dwLength)
2377 {
2378 wcscpy(lpServiceName, lpService->lpServiceName);
2379 *lpcchBuffer = dwLength;
2380 return ERROR_SUCCESS;
2381 }
2382
2383 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2384
2385 *lpcchBuffer = dwLength * 2;
2386
2387 return dwError;
2388 }
2389
2390
2391 /* Function 22 */
2392 DWORD RSetServiceBitsA(
2393 handle_t BindingHandle,
2394 SC_RPC_HANDLE hServiceStatus,
2395 DWORD dwServiceBits,
2396 int bSetBitsOn,
2397 int bUpdateImmediately,
2398 char *lpString)
2399 {
2400 UNIMPLEMENTED;
2401 return ERROR_CALL_NOT_IMPLEMENTED;
2402 }
2403
2404
2405 /* Function 23 */
2406 DWORD RChangeServiceConfigA(
2407 handle_t BindingHandle,
2408 SC_RPC_HANDLE hService,
2409 DWORD dwServiceType,
2410 DWORD dwStartType,
2411 DWORD dwErrorControl,
2412 LPSTR lpBinaryPathName,
2413 LPSTR lpLoadOrderGroup,
2414 LPDWORD lpdwTagId,
2415 LPSTR lpDependencies,
2416 DWORD dwDependSize,
2417 LPSTR lpServiceStartName,
2418 LPBYTE lpPassword,
2419 DWORD dwPwSize,
2420 LPSTR lpDisplayName)
2421 {
2422 DWORD dwError = ERROR_SUCCESS;
2423 PSERVICE_HANDLE hSvc;
2424 PSERVICE lpService = NULL;
2425 HKEY hServiceKey = NULL;
2426 LPWSTR lpDisplayNameW = NULL;
2427 // LPWSTR lpBinaryPathNameW = NULL;
2428 LPWSTR lpLoadOrderGroupW = NULL;
2429 LPWSTR lpDependenciesW = NULL;
2430 // LPWSTR lpPasswordW = NULL;
2431
2432 DPRINT("RChangeServiceConfigA() called\n");
2433 DPRINT("dwServiceType = %lu\n", dwServiceType);
2434 DPRINT("dwStartType = %lu\n", dwStartType);
2435 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2436 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2437 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2438 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2439
2440 if (ScmShutdown)
2441 return ERROR_SHUTDOWN_IN_PROGRESS;
2442
2443 hSvc = (PSERVICE_HANDLE)hService;
2444 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2445 {
2446 DPRINT1("Invalid handle tag!\n");
2447 return ERROR_INVALID_HANDLE;
2448 }
2449
2450 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2451 SERVICE_CHANGE_CONFIG))
2452 {
2453 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2454 return ERROR_ACCESS_DENIED;
2455 }
2456
2457 lpService = hSvc->ServiceEntry;
2458 if (lpService == NULL)
2459 {
2460 DPRINT1("lpService == NULL!\n");
2461 return ERROR_INVALID_HANDLE;
2462 }
2463
2464 /* FIXME: Lock database exclusively */
2465
2466 if (lpService->bDeleted)
2467 {
2468 /* FIXME: Unlock database */
2469 DPRINT1("The service has already been marked for delete!\n");
2470 return ERROR_SERVICE_MARKED_FOR_DELETE;
2471 }
2472
2473 /* Open the service key */
2474 dwError = ScmOpenServiceKey(lpService->szServiceName,
2475 KEY_SET_VALUE,
2476 &hServiceKey);
2477 if (dwError != ERROR_SUCCESS)
2478 goto done;
2479
2480 /* Write service data to the registry */
2481
2482 if (lpDisplayName != NULL && *lpDisplayName != 0)
2483 {
2484 /* Set the display name */
2485 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2486 0,
2487 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
2488 if (lpDisplayNameW == NULL)
2489 {
2490 dwError = ERROR_NOT_ENOUGH_MEMORY;
2491 goto done;
2492 }
2493
2494 MultiByteToWideChar(CP_ACP,
2495 0,
2496 lpDisplayName,
2497 -1,
2498 lpDisplayNameW,
2499 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2500
2501 RegSetValueExW(hServiceKey,
2502 L"DisplayName",
2503 0,
2504 REG_SZ,
2505 (LPBYTE)lpDisplayNameW,
2506 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2507
2508 /* Update lpService->lpDisplayName */
2509 if (lpService->lpDisplayName)
2510 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2511
2512 lpService->lpDisplayName = lpDisplayNameW;
2513 }
2514
2515 if (dwServiceType != SERVICE_NO_CHANGE)
2516 {
2517 /* Set the service type */
2518 dwError = RegSetValueExW(hServiceKey,
2519 L"Type",
2520 0,
2521 REG_DWORD,
2522 (LPBYTE)&dwServiceType,
2523 sizeof(DWORD));
2524 if (dwError != ERROR_SUCCESS)
2525 goto done;
2526
2527 lpService->Status.dwServiceType = dwServiceType;
2528 }
2529
2530 if (dwStartType != SERVICE_NO_CHANGE)
2531 {
2532 /* Set the start value */
2533 dwError = RegSetValueExW(hServiceKey,
2534 L"Start",
2535 0,
2536 REG_DWORD,
2537 (LPBYTE)&dwStartType,
2538 sizeof(DWORD));
2539 if (dwError != ERROR_SUCCESS)
2540 goto done;
2541
2542 lpService->dwStartType = dwStartType;
2543 }
2544
2545 if (dwErrorControl != SERVICE_NO_CHANGE)
2546 {
2547 /* Set the error control value */
2548 dwError = RegSetValueExW(hServiceKey,
2549 L"ErrorControl",
2550 0,
2551 REG_DWORD,
2552 (LPBYTE)&dwErrorControl,
2553 sizeof(DWORD));
2554 if (dwError != ERROR_SUCCESS)
2555 goto done;
2556
2557 lpService->dwErrorControl = dwErrorControl;
2558 }
2559
2560 #if 0
2561 /* FIXME: set the new ImagePath value */
2562
2563 /* Set the image path */
2564 if (dwServiceType & SERVICE_WIN32)
2565 {
2566 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2567 {
2568 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
2569 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, (wcslen(lpBinaryPathNameW)+1) * sizeof(WCHAR));
2570 dwError = RegSetValueExW(hServiceKey,
2571 L"ImagePath",
2572 0,
2573 REG_EXPAND_SZ,
2574 (LPBYTE)lpBinaryPathNameW,
2575 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
2576 if (dwError != ERROR_SUCCESS)
2577 goto done;
2578 }
2579 }
2580 else if (dwServiceType & SERVICE_DRIVER)
2581 {
2582 if (lpImagePath != NULL && *lpImagePath != 0)
2583 {
2584 dwError = RegSetValueExW(hServiceKey,
2585 L"ImagePath",
2586 0,
2587 REG_EXPAND_SZ,
2588 (LPBYTE)lpImagePath,
2589 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
2590 if (dwError != ERROR_SUCCESS)
2591 goto done;
2592 }
2593 }
2594 #endif
2595
2596 /* Set the group name */
2597 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2598 {
2599 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
2600 0,
2601 (strlen(lpLoadOrderGroup)+1) * sizeof(WCHAR));
2602 if (lpLoadOrderGroupW == NULL)
2603 {
2604 dwError = ERROR_NOT_ENOUGH_MEMORY;
2605 goto done;
2606 }
2607
2608 MultiByteToWideChar(CP_ACP,
2609 0,
2610 lpLoadOrderGroup,
2611 -1,
2612 lpLoadOrderGroupW,
2613 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
2614
2615 dwError = RegSetValueExW(hServiceKey,
2616 L"Group",
2617 0,
2618 REG_SZ,
2619 (LPBYTE)lpLoadOrderGroupW,
2620 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
2621 if (dwError != ERROR_SUCCESS)
2622 goto done;
2623
2624 /* FIXME: Update lpService->lpServiceGroup */
2625
2626 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
2627 }
2628
2629 if (lpdwTagId != NULL)
2630 {
2631 dwError = ScmAssignNewTag(lpService);
2632 if (dwError != ERROR_SUCCESS)
2633 goto done;
2634
2635 dwError = RegSetValueExW(hServiceKey,
2636 L"Tag",
2637 0,
2638 REG_DWORD,
2639 (LPBYTE)&lpService->dwTag,
2640 sizeof(DWORD));
2641 if (dwError != ERROR_SUCCESS)
2642 goto done;
2643
2644 *lpdwTagId = lpService->dwTag;
2645 }
2646
2647 /* Write dependencies */
2648 if (lpDependencies != NULL && *lpDependencies != 0)
2649 {
2650 lpDependenciesW = HeapAlloc(GetProcessHeap(),
2651 0,
2652 (strlen(lpDependencies)+1) * sizeof(WCHAR));
2653 if (lpDependenciesW == NULL)
2654 {
2655 dwError = ERROR_NOT_ENOUGH_MEMORY;
2656 goto done;
2657 }
2658
2659 MultiByteToWideChar(CP_ACP,
2660 0,
2661 lpDependencies,
2662 dwDependSize,
2663 lpDependenciesW,
2664 (wcslen(lpDependenciesW)+1) * sizeof(WCHAR));
2665
2666 dwError = ScmWriteDependencies(hServiceKey,
2667 (LPWSTR)lpDependenciesW,
2668 dwDependSize);
2669
2670 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
2671 }
2672
2673 if (lpPassword != NULL)
2674 {
2675 /* FIXME: Write password */
2676 }
2677
2678 /* FIXME: Unlock database */
2679
2680 done:
2681 if (hServiceKey != NULL)
2682 RegCloseKey(hServiceKey);
2683
2684 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
2685
2686 return dwError;
2687 }
2688
2689
2690 /* Function 24 */
2691 DWORD RCreateServiceA(
2692 handle_t BindingHandle,
2693 SC_RPC_HANDLE hSCManager,
2694 LPSTR lpServiceName,
2695 LPSTR lpDisplayName,
2696 DWORD dwDesiredAccess,
2697 DWORD dwServiceType,
2698 DWORD dwStartType,
2699 DWORD dwErrorControl,
2700 LPSTR lpBinaryPathName,
2701 LPSTR lpLoadOrderGroup,
2702 LPDWORD lpdwTagId,
2703 LPBYTE lpDependencies,
2704 DWORD dwDependSize,
2705 LPSTR lpServiceStartName,
2706 LPBYTE lpPassword,
2707 DWORD dwPwSize,
2708 LPSC_RPC_HANDLE lpServiceHandle)
2709 {
2710 UNIMPLEMENTED;
2711 return ERROR_CALL_NOT_IMPLEMENTED;
2712 }
2713
2714
2715 /* Function 25 */
2716 DWORD REnumDependentServicesA(
2717 handle_t BindingHandle,
2718 SC_RPC_HANDLE hService,
2719 DWORD dwServiceState,
2720 LPBYTE lpServices,
2721 DWORD cbBufSize,
2722 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2723 LPBOUNDED_DWORD_256K lpServicesReturned)
2724 {
2725 UNIMPLEMENTED;
2726 *pcbBytesNeeded = 0;
2727 *lpServicesReturned = 0;
2728 return ERROR_CALL_NOT_IMPLEMENTED;
2729 }
2730
2731
2732 /* Function 26 */
2733 DWORD REnumServicesStatusA(
2734 handle_t BindingHandle,
2735 SC_RPC_HANDLE hSCManager,
2736 DWORD dwServiceType,
2737 DWORD dwServiceState,
2738 LPBYTE lpBuffer,
2739 DWORD dwBufSize,
2740 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2741 LPBOUNDED_DWORD_256K lpServicesReturned,
2742 LPBOUNDED_DWORD_256K lpResumeHandle)
2743 {
2744 UNIMPLEMENTED;
2745 return ERROR_CALL_NOT_IMPLEMENTED;
2746 }
2747
2748
2749 /* Function 27 */
2750 DWORD ROpenSCManagerA(
2751 handle_t BindingHandle,
2752 LPSTR lpMachineName,
2753 LPSTR lpDatabaseName,
2754 DWORD dwDesiredAccess,
2755 LPSC_RPC_HANDLE lpScHandle)
2756 {
2757 UNICODE_STRING MachineName;
2758 UNICODE_STRING DatabaseName;
2759 DWORD dwError;
2760
2761 DPRINT("ROpenSCManagerA() called\n");
2762
2763 if (lpMachineName)
2764 RtlCreateUnicodeStringFromAsciiz(&MachineName,
2765 lpMachineName);
2766
2767 if (lpDatabaseName)
2768 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
2769 lpDatabaseName);
2770
2771 dwError = ROpenSCManagerW(BindingHandle,
2772 lpMachineName ? MachineName.Buffer : NULL,
2773 lpDatabaseName ? DatabaseName.Buffer : NULL,
2774 dwDesiredAccess,
2775 lpScHandle);
2776
2777 if (lpMachineName)
2778 RtlFreeUnicodeString(&MachineName);
2779
2780 if (lpDatabaseName)
2781 RtlFreeUnicodeString(&DatabaseName);
2782
2783 return dwError;
2784 }
2785
2786
2787 /* Function 28 */
2788 DWORD ROpenServiceA(
2789 handle_t BindingHandle,
2790 SC_RPC_HANDLE hSCManager,
2791 LPSTR lpServiceName,
2792 DWORD dwDesiredAccess,
2793 LPSC_RPC_HANDLE lpServiceHandle)
2794 {
2795 UNICODE_STRING ServiceName;
2796 DWORD dwError;
2797
2798 DPRINT("ROpenServiceA() called\n");
2799
2800 if (lpServiceName)
2801 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
2802 lpServiceName);
2803
2804 dwError = ROpenServiceW(BindingHandle,
2805 hSCManager,
2806 ServiceName.Buffer,
2807 dwDesiredAccess,
2808 lpServiceHandle);
2809
2810 if (lpServiceName)
2811 RtlFreeUnicodeString(&ServiceName);
2812
2813 return dwError;
2814 }
2815
2816
2817 /* Function 29 */
2818 DWORD RQueryServiceConfigA(
2819 handle_t BindingHandle,
2820 SC_RPC_HANDLE hService,
2821 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
2822 DWORD cbBufSize,
2823 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2824 {
2825 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
2826 DWORD dwError = ERROR_SUCCESS;
2827 PSERVICE_HANDLE hSvc;
2828 PSERVICE lpService = NULL;
2829 HKEY hServiceKey = NULL;
2830 LPWSTR lpImagePath = NULL;
2831 LPWSTR lpServiceStartName = NULL;
2832 DWORD dwRequiredSize;
2833 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
2834 CHAR lpEmptyString[]={0,0};
2835 LPSTR lpStr;
2836
2837 DPRINT("RQueryServiceConfigA() called\n");
2838
2839 if (ScmShutdown)
2840 return ERROR_SHUTDOWN_IN_PROGRESS;
2841
2842 hSvc = (PSERVICE_HANDLE)hService;
2843 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2844 {
2845 DPRINT1("Invalid handle tag!\n");
2846 return ERROR_INVALID_HANDLE;
2847 }
2848
2849 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2850 SERVICE_QUERY_CONFIG))
2851 {
2852 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2853 return ERROR_ACCESS_DENIED;
2854 }
2855
2856 lpService = hSvc->ServiceEntry;
2857 if (lpService == NULL)
2858 {
2859 DPRINT1("lpService == NULL!\n");
2860 return ERROR_INVALID_HANDLE;
2861 }
2862
2863 /* FIXME: Lock the service database shared */
2864
2865 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2866 KEY_READ,
2867 &hServiceKey);
2868 if (dwError != ERROR_SUCCESS)
2869 goto Done;
2870
2871 dwError = ScmReadString(hServiceKey,
2872 L"ImagePath",
2873 &lpImagePath);
2874 if (dwError != ERROR_SUCCESS)
2875 goto Done;
2876
2877 ScmReadString(hServiceKey,
2878 L"ObjectName",
2879 &lpServiceStartName);
2880
2881 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2882
2883 if (lpImagePath != NULL)
2884 dwRequiredSize += wcslen(lpImagePath) + 1;
2885 else
2886 dwRequiredSize += 2;
2887
2888 if (lpService->lpGroup != NULL)
2889 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
2890 else
2891 dwRequiredSize += 2;
2892
2893 /* FIXME: Add Dependencies length*/
2894 dwRequiredSize += 2;
2895
2896 if (lpServiceStartName != NULL)
2897 dwRequiredSize += wcslen(lpServiceStartName) + 1;
2898 else
2899 dwRequiredSize += 2;
2900
2901 if (lpService->lpDisplayName != NULL)
2902 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
2903 else
2904 dwRequiredSize += 2;
2905
2906 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2907 {
2908 dwError = ERROR_INSUFFICIENT_BUFFER;
2909 }
2910 else
2911 {
2912 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
2913 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2914 lpConfig->dwStartType = lpService->dwStartType;
2915 lpConfig->dwErrorControl = lpService->dwErrorControl;
2916 lpConfig->dwTagId = lpService->dwTag;
2917
2918 lpStr = (LPSTR)(lpServiceConfig + 1);
2919
2920 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
2921 Verified in WINXP*/
2922
2923 if (lpImagePath)
2924 {
2925 WideCharToMultiByte(CP_ACP,
2926 0,
2927 lpImagePath,
2928 -1,
2929 lpStr,
2930 wcslen(lpImagePath),
2931 0,
2932 0);
2933 }
2934 else
2935 {
2936 strcpy(lpStr, lpEmptyString);
2937 }
2938
2939 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2940 lpStr += (strlen((LPSTR)lpStr) + 1);
2941
2942 if (lpService->lpGroup)
2943 {
2944 WideCharToMultiByte(CP_ACP,
2945 0,
2946 lpService->lpGroup->lpGroupName,
2947 -1,
2948 lpStr,
2949 wcslen(lpService->lpGroup->lpGroupName),
2950 0,
2951 0);
2952 }
2953 else
2954 {
2955 strcpy(lpStr, lpEmptyString);
2956 }
2957
2958 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2959 lpStr += (strlen(lpStr) + 1);
2960
2961 /* FIXME: Append Dependencies */
2962 strcpy(lpStr, lpEmptyString);
2963
2964 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2965 lpStr += (strlen(lpStr) + 1);
2966
2967 if (lpServiceStartName)
2968 {
2969 WideCharToMultiByte(CP_ACP,
2970 0,
2971 lpServiceStartName,
2972 -1,
2973 lpStr,
2974 wcslen(lpServiceStartName),
2975 0,
2976 0);
2977 }
2978 else
2979 {
2980 strcpy(lpStr, lpEmptyString);
2981 }
2982
2983 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2984 lpStr += (strlen(lpStr) + 1);
2985
2986 if (lpService->lpDisplayName)
2987 {
2988 WideCharToMultiByte(CP_ACP,
2989 0,
2990 lpService->lpDisplayName,
2991 -1,
2992 lpStr,
2993 wcslen(lpService->lpDisplayName),
2994 0,
2995 0);
2996 }
2997 else
2998 {
2999 strcpy(lpStr, lpEmptyString);
3000 }
3001
3002 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3003 }
3004
3005 if (pcbBytesNeeded != NULL)
3006 *pcbBytesNeeded = dwRequiredSize;
3007
3008 Done:;
3009 if (lpImagePath != NULL)
3010 HeapFree(GetProcessHeap(), 0, lpImagePath);
3011
3012 if (lpServiceStartName != NULL)
3013 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3014
3015 if (hServiceKey != NULL)
3016 RegCloseKey(hServiceKey);
3017
3018 /* FIXME: Unlock the service database */
3019
3020 DPRINT("RQueryServiceConfigA() done\n");
3021
3022 return dwError;
3023 }
3024
3025
3026 /* Function 30 */
3027 DWORD RQueryServiceLockStatusA(
3028 handle_t BindingHandle,
3029 SC_RPC_HANDLE hSCManager,
3030 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
3031 DWORD cbBufSize,
3032 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3033 {
3034 UNIMPLEMENTED;
3035 return ERROR_CALL_NOT_IMPLEMENTED;
3036 }
3037
3038
3039 /* Function 31 */
3040 DWORD RStartServiceA(
3041 handle_t BindingHandle,
3042 SC_RPC_HANDLE hService,
3043 DWORD argc,
3044 LPSTRING_PTRSA argv)
3045 {
3046 DWORD dwError = ERROR_SUCCESS;
3047 PSERVICE_HANDLE hSvc;
3048 PSERVICE lpService = NULL;
3049
3050 DPRINT1("RStartServiceA() called\n");
3051
3052 if (ScmShutdown)
3053 return ERROR_SHUTDOWN_IN_PROGRESS;
3054
3055 hSvc = (PSERVICE_HANDLE)hService;
3056 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3057 {
3058 DPRINT1("Invalid handle tag!\n");
3059 return ERROR_INVALID_HANDLE;
3060 }
3061
3062 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3063 SERVICE_START))
3064 {
3065 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3066 return ERROR_ACCESS_DENIED;
3067 }
3068
3069 lpService = hSvc->ServiceEntry;
3070 if (lpService == NULL)
3071 {
3072 DPRINT1("lpService == NULL!\n");
3073 return ERROR_INVALID_HANDLE;
3074 }
3075
3076 if (lpService->dwStartType == SERVICE_DISABLED)
3077 return ERROR_SERVICE_DISABLED;
3078
3079 if (lpService->bDeleted)
3080 return ERROR_SERVICE_MARKED_FOR_DELETE;
3081
3082 /* FIXME: Convert argument vector to Unicode */
3083
3084 /* Start the service */
3085 dwError = ScmStartService(lpService, 0, NULL);
3086
3087 /* FIXME: Free argument vector */
3088
3089 return dwError;
3090 }
3091
3092
3093 /* Function 32 */
3094 DWORD RGetServiceDisplayNameA(
3095 handle_t BindingHandle,
3096 SC_RPC_HANDLE hSCManager,
3097 LPSTR lpServiceName,
3098 LPSTR lpDisplayName,
3099 LPBOUNDED_DWORD_4K lpcchBuffer)
3100 {
3101 // PMANAGER_HANDLE hManager;
3102 PSERVICE lpService;
3103 DWORD dwLength;
3104 DWORD dwError;
3105 LPWSTR lpServiceNameW;
3106
3107 DPRINT("RGetServiceDisplayNameA() called\n");
3108 DPRINT("hSCManager = %p\n", hSCManager);
3109 DPRINT("lpServiceName: %s\n", lpServiceName);
3110 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3111 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3112
3113 // hManager = (PMANAGER_HANDLE)hSCManager;
3114 // if (hManager->Handle.Tag != MANAGER_TAG)
3115 // {
3116 // DPRINT1("Invalid manager handle!\n");
3117 // return ERROR_INVALID_HANDLE;
3118 // }
3119
3120 dwLength = strlen(lpServiceName) + 1;
3121 lpServiceNameW = HeapAlloc(GetProcessHeap(),
3122 HEAP_ZERO_MEMORY,
3123 dwLength * sizeof(WCHAR));
3124 if (!lpServiceNameW)
3125 return ERROR_NOT_ENOUGH_MEMORY;
3126
3127 MultiByteToWideChar(CP_ACP,
3128 0,
3129 lpServiceName,
3130 strlen(lpServiceName),
3131 lpServiceNameW,
3132 dwLength);
3133
3134 lpService = ScmGetServiceEntryByName(lpServiceNameW);
3135
3136 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3137
3138 if (lpService == NULL)
3139 {
3140 DPRINT1("Could not find a service!\n");
3141
3142 /* If the service could not be found and lpcchBuffer is 0, windows
3143 puts null in lpDisplayName and puts 1 in lpcchBuffer */
3144 if (*lpcchBuffer == 0)
3145 {
3146 *lpcchBuffer = 1;
3147 *lpDisplayName = '\0';
3148 }
3149 return ERROR_SERVICE_DOES_NOT_EXIST;
3150 }
3151
3152 if (!lpService->lpDisplayName)
3153 {
3154 dwLength = wcslen(lpService->lpServiceName);
3155 if (lpServiceName != NULL &&
3156 *lpcchBuffer > dwLength)
3157 {
3158 WideCharToMultiByte(CP_ACP,
3159 0,
3160 lpService->lpServiceName,
3161 wcslen(lpService->lpServiceName),
3162 lpDisplayName,
3163 *lpcchBuffer,
3164 NULL,
3165 NULL);
3166 return ERROR_SUCCESS;
3167 }
3168 }
3169 else
3170 {
3171 dwLength = wcslen(lpService->lpDisplayName);
3172 if (lpDisplayName != NULL &&
3173 *lpcchBuffer > dwLength)
3174 {
3175 WideCharToMultiByte(CP_ACP,
3176 0,
3177 lpService->lpDisplayName,
3178 wcslen(lpService->lpDisplayName),
3179 lpDisplayName,
3180 *lpcchBuffer,
3181 NULL,
3182 NULL);
3183 return ERROR_SUCCESS;
3184 }
3185 }
3186
3187 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3188
3189 *lpcchBuffer = dwLength * 2;
3190
3191 return dwError;
3192 }
3193
3194
3195 /* Function 33 */
3196 DWORD RGetServiceKeyNameA(
3197 handle_t BindingHandle,
3198 SC_RPC_HANDLE hSCManager,
3199 LPSTR lpDisplayName,
3200 LPSTR lpServiceName,
3201 LPBOUNDED_DWORD_4K lpcchBuffer)
3202 {
3203 PSERVICE lpService;
3204 DWORD dwLength;
3205 DWORD dwError;
3206 LPWSTR lpDisplayNameW;
3207
3208 DPRINT("RGetServiceKeyNameA() called\n");
3209 DPRINT("hSCManager = %p\n", hSCManager);
3210 DPRINT("lpDisplayName: %s\n", lpDisplayName);
3211 DPRINT("lpServiceName: %p\n", lpServiceName);
3212 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3213
3214 dwLength = strlen(lpDisplayName) + 1;
3215 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3216 HEAP_ZERO_MEMORY,
3217 dwLength * sizeof(WCHAR));
3218 if (!lpDisplayNameW)
3219 return ERROR_NOT_ENOUGH_MEMORY;
3220
3221 MultiByteToWideChar(CP_ACP,
3222 0,
3223 lpDisplayName,
3224 strlen(lpDisplayName),
3225 lpDisplayNameW,
3226 dwLength);
3227
3228 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
3229
3230 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3231
3232 if (lpService == NULL)
3233 {
3234 DPRINT1("Could not find the service!\n");
3235
3236 /* If the service could not be found and lpcchBuffer is 0,
3237 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
3238 if (*lpcchBuffer == 0)
3239 {
3240 *lpcchBuffer = 1;
3241 *lpServiceName = '\0';
3242 }
3243
3244 return ERROR_SERVICE_DOES_NOT_EXIST;
3245 }
3246
3247 dwLength = wcslen(lpService->lpServiceName);
3248 if (lpService != NULL &&
3249 *lpcchBuffer > dwLength)
3250 {
3251 WideCharToMultiByte(CP_ACP,
3252 0,
3253 lpService->lpServiceName,
3254 wcslen(lpService->lpServiceName),
3255 lpServiceName,
3256 dwLength,
3257 NULL,
3258 NULL);
3259 return ERROR_SUCCESS;
3260 }
3261
3262 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3263
3264 *lpcchBuffer = dwLength * 2;
3265
3266 return dwError;
3267 }
3268
3269
3270 /* Function 34 */
3271 DWORD RGetCurrentGroupStateW(
3272 handle_t BindingHandle)
3273 {
3274 UNIMPLEMENTED;
3275 return ERROR_CALL_NOT_IMPLEMENTED;
3276 }
3277
3278
3279 /* Function 35 */
3280 DWORD REnumServiceGroupW(
3281 handle_t BindingHandle,
3282 SC_RPC_HANDLE hSCManager,
3283 DWORD dwServiceType,
3284 DWORD dwServiceState,