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