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