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