RSetServiceStatus:
[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 = (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 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 SC_RPC_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((ULONG)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 SC_RPC_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;
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 /* Check access rights */
2220 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2221 SC_MANAGER_ENUMERATE_SERVICE))
2222 {
2223 DPRINT1("Insufficient access rights! 0x%lx\n",
2224 hManager->Handle.DesiredAccess);
2225 return ERROR_ACCESS_DENIED;
2226 }
2227
2228 *pcbBytesNeeded = 0;
2229 *lpServicesReturned = 0;
2230
2231 dwLastResumeCount = *lpResumeHandle;
2232
2233 /* FIXME: Lock the service list shared */
2234
2235 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2236 if (lpService == NULL)
2237 {
2238 dwError = ERROR_SUCCESS;
2239 goto Done;
2240 }
2241
2242 dwRequiredSize = 0;
2243 dwServiceCount = 0;
2244
2245 for (ServiceEntry = &lpService->ServiceListEntry;
2246 ServiceEntry != &ServiceListHead;
2247 ServiceEntry = ServiceEntry->Flink)
2248 {
2249 CurrentService = CONTAINING_RECORD(ServiceEntry,
2250 SERVICE,
2251 ServiceListEntry);
2252
2253 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2254 continue;
2255
2256 dwState = SERVICE_ACTIVE;
2257 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2258 dwState = SERVICE_INACTIVE;
2259
2260 if ((dwState & dwServiceState) == 0)
2261 continue;
2262
2263 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2264 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2265 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2266
2267 if (dwRequiredSize + dwSize > dwBufSize)
2268 {
2269 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2270 break;
2271 }
2272
2273 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2274 dwRequiredSize += dwSize;
2275 dwServiceCount++;
2276 dwLastResumeCount = CurrentService->dwResumeCount;
2277 }
2278
2279 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2280 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2281
2282 for (;
2283 ServiceEntry != &ServiceListHead;
2284 ServiceEntry = ServiceEntry->Flink)
2285 {
2286 CurrentService = CONTAINING_RECORD(ServiceEntry,
2287 SERVICE,
2288 ServiceListEntry);
2289
2290 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2291 continue;
2292
2293 dwState = SERVICE_ACTIVE;
2294 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2295 dwState = SERVICE_INACTIVE;
2296
2297 if ((dwState & dwServiceState) == 0)
2298 continue;
2299
2300 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2301 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2302 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2303
2304 dwError = ERROR_MORE_DATA;
2305 }
2306
2307 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2308
2309 *lpResumeHandle = dwLastResumeCount;
2310 *lpServicesReturned = dwServiceCount;
2311 *pcbBytesNeeded = dwRequiredSize;
2312
2313 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2314 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2315 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2316
2317 dwRequiredSize = 0;
2318 for (ServiceEntry = &lpService->ServiceListEntry;
2319 ServiceEntry != &ServiceListHead;
2320 ServiceEntry = ServiceEntry->Flink)
2321 {
2322 CurrentService = CONTAINING_RECORD(ServiceEntry,
2323 SERVICE,
2324 ServiceListEntry);
2325
2326 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2327 continue;
2328
2329 dwState = SERVICE_ACTIVE;
2330 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2331 dwState = SERVICE_INACTIVE;
2332
2333 if ((dwState & dwServiceState) == 0)
2334 continue;
2335
2336 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2337 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2338 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2339
2340 if (dwRequiredSize + dwSize > dwBufSize)
2341 break;
2342
2343 /* Copy the service name */
2344 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2345 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2346 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2347
2348 /* Copy the display name */
2349 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2350 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2351 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2352
2353 /* Copy the status information */
2354 memcpy(&lpStatusPtr->ServiceStatus,
2355 &CurrentService->Status,
2356 sizeof(SERVICE_STATUS));
2357
2358 lpStatusPtr++;
2359 dwRequiredSize += dwSize;
2360 }
2361
2362 Done:;
2363 /* FIXME: Unlock the service list */
2364
2365 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2366
2367 return dwError;
2368 }
2369
2370
2371 /* Function 15 */
2372 DWORD ROpenSCManagerW(
2373 handle_t BindingHandle,
2374 LPWSTR lpMachineName,
2375 LPWSTR lpDatabaseName,
2376 DWORD dwDesiredAccess,
2377 LPSC_RPC_HANDLE lpScHandle)
2378 {
2379 DWORD dwError;
2380 SC_HANDLE hHandle;
2381
2382 DPRINT("ROpenSCManagerW() called\n");
2383 DPRINT("lpMachineName = %p\n", lpMachineName);
2384 DPRINT("lpMachineName: %S\n", lpMachineName);
2385 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2386 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2387 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2388
2389 if (ScmShutdown)
2390 return ERROR_SHUTDOWN_IN_PROGRESS;
2391
2392 if (!lpScHandle)
2393 return ERROR_INVALID_PARAMETER;
2394
2395 dwError = ScmCreateManagerHandle(lpDatabaseName,
2396 &hHandle);
2397 if (dwError != ERROR_SUCCESS)
2398 {
2399 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2400 return dwError;
2401 }
2402
2403 /* Check the desired access */
2404 dwError = ScmCheckAccess(hHandle,
2405 dwDesiredAccess | SC_MANAGER_CONNECT);
2406 if (dwError != ERROR_SUCCESS)
2407 {
2408 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2409 HeapFree(GetProcessHeap(), 0, hHandle);
2410 return dwError;
2411 }
2412
2413 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2414 DPRINT("*hScm = %p\n", *lpScHandle);
2415
2416 DPRINT("ROpenSCManagerW() done\n");
2417
2418 return ERROR_SUCCESS;
2419 }
2420
2421
2422 /* Function 16 */
2423 DWORD ROpenServiceW(
2424 handle_t BindingHandle,
2425 SC_RPC_HANDLE hSCManager,
2426 LPWSTR lpServiceName,
2427 DWORD dwDesiredAccess,
2428 LPSC_RPC_HANDLE lpServiceHandle)
2429 {
2430 PSERVICE lpService;
2431 PMANAGER_HANDLE hManager;
2432 SC_HANDLE hHandle;
2433 DWORD dwError;
2434
2435 DPRINT("ROpenServiceW() called\n");
2436 DPRINT("hSCManager = %p\n", hSCManager);
2437 DPRINT("lpServiceName = %p\n", lpServiceName);
2438 DPRINT("lpServiceName: %S\n", lpServiceName);
2439 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2440
2441 if (ScmShutdown)
2442 return ERROR_SHUTDOWN_IN_PROGRESS;
2443
2444 if (!lpServiceHandle)
2445 return ERROR_INVALID_PARAMETER;
2446
2447 if (!lpServiceName)
2448 return ERROR_INVALID_ADDRESS;
2449
2450 hManager = (PMANAGER_HANDLE)hSCManager;
2451 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2452 {
2453 DPRINT1("Invalid manager handle!\n");
2454 return ERROR_INVALID_HANDLE;
2455 }
2456
2457 /* FIXME: Lock the service list */
2458
2459 /* Get service database entry */
2460 lpService = ScmGetServiceEntryByName(lpServiceName);
2461 if (lpService == NULL)
2462 {
2463 DPRINT("Could not find a service!\n");
2464 return ERROR_SERVICE_DOES_NOT_EXIST;
2465 }
2466
2467 /* Create a service handle */
2468 dwError = ScmCreateServiceHandle(lpService,
2469 &hHandle);
2470 if (dwError != ERROR_SUCCESS)
2471 {
2472 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2473 return dwError;
2474 }
2475
2476 /* Check the desired access */
2477 dwError = ScmCheckAccess(hHandle,
2478 dwDesiredAccess);
2479 if (dwError != ERROR_SUCCESS)
2480 {
2481 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2482 HeapFree(GetProcessHeap(), 0, hHandle);
2483 return dwError;
2484 }
2485
2486 lpService->dwRefCount++;
2487 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2488
2489 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2490 DPRINT("*hService = %p\n", *lpServiceHandle);
2491
2492 DPRINT("ROpenServiceW() done\n");
2493
2494 return ERROR_SUCCESS;
2495 }
2496
2497
2498 /* Function 17 */
2499 DWORD RQueryServiceConfigW(
2500 handle_t BindingHandle,
2501 SC_RPC_HANDLE hService,
2502 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2503 DWORD cbBufSize,
2504 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2505 {
2506 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2507 DWORD dwError = ERROR_SUCCESS;
2508 PSERVICE_HANDLE hSvc;
2509 PSERVICE lpService = NULL;
2510 HKEY hServiceKey = NULL;
2511 LPWSTR lpImagePath = NULL;
2512 LPWSTR lpServiceStartName = NULL;
2513 DWORD dwRequiredSize;
2514 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2515 WCHAR lpEmptyString[] = {0,0};
2516 LPWSTR lpStr;
2517
2518 DPRINT("RQueryServiceConfigW() called\n");
2519
2520 if (ScmShutdown)
2521 return ERROR_SHUTDOWN_IN_PROGRESS;
2522
2523 hSvc = (PSERVICE_HANDLE)hService;
2524 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2525 {
2526 DPRINT1("Invalid handle tag!\n");
2527 return ERROR_INVALID_HANDLE;
2528 }
2529
2530 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2531 SERVICE_QUERY_CONFIG))
2532 {
2533 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2534 return ERROR_ACCESS_DENIED;
2535 }
2536
2537 lpService = hSvc->ServiceEntry;
2538 if (lpService == NULL)
2539 {
2540 DPRINT1("lpService == NULL!\n");
2541 return ERROR_INVALID_HANDLE;
2542 }
2543
2544 /* FIXME: Lock the service database shared */
2545
2546 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2547 KEY_READ,
2548 &hServiceKey);
2549 if (dwError != ERROR_SUCCESS)
2550 goto Done;
2551
2552 dwError = ScmReadString(hServiceKey,
2553 L"ImagePath",
2554 &lpImagePath);
2555 if (dwError != ERROR_SUCCESS)
2556 goto Done;
2557
2558 ScmReadString(hServiceKey,
2559 L"ObjectName",
2560 &lpServiceStartName);
2561
2562 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2563
2564 if (lpImagePath != NULL)
2565 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2566 else
2567 dwRequiredSize += 2 * sizeof(WCHAR);
2568
2569 if (lpService->lpGroup != NULL)
2570 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2571 else
2572 dwRequiredSize += 2 * sizeof(WCHAR);
2573
2574 /* FIXME: Add Dependencies length*/
2575
2576 if (lpServiceStartName != NULL)
2577 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2578 else
2579 dwRequiredSize += 2 * sizeof(WCHAR);
2580
2581 if (lpService->lpDisplayName != NULL)
2582 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2583 else
2584 dwRequiredSize += 2 * sizeof(WCHAR);
2585
2586 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2587 {
2588 dwError = ERROR_INSUFFICIENT_BUFFER;
2589 }
2590 else
2591 {
2592 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2593 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2594 lpConfig->dwStartType = lpService->dwStartType;
2595 lpConfig->dwErrorControl = lpService->dwErrorControl;
2596 lpConfig->dwTagId = lpService->dwTag;
2597
2598 lpStr = (LPWSTR)(lpConfig + 1);
2599
2600 if (lpImagePath != NULL)
2601 {
2602 wcscpy(lpStr, lpImagePath);
2603 }
2604 else
2605 {
2606 wcscpy(lpStr, lpEmptyString);
2607 }
2608
2609 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2610 lpStr += (wcslen(lpStr) + 1);
2611
2612 if (lpService->lpGroup != NULL)
2613 {
2614 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2615 }
2616 else
2617 {
2618 wcscpy(lpStr, lpEmptyString);
2619 }
2620
2621 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2622 lpStr += (wcslen(lpStr) + 1);
2623
2624 /* FIXME: Append Dependencies */
2625 wcscpy(lpStr, lpEmptyString);
2626
2627 lpStr += (wcslen(lpStr) + 1);
2628 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2629
2630 if (lpServiceStartName != NULL)
2631 {
2632 wcscpy(lpStr, lpServiceStartName);
2633 }
2634 else
2635 {
2636 wcscpy(lpStr, lpEmptyString);
2637 }
2638
2639 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2640 lpStr += (wcslen(lpStr) + 1);
2641
2642 if (lpService->lpDisplayName != NULL)
2643 {
2644 wcscpy(lpStr, lpService->lpDisplayName);
2645 }
2646 else
2647 {
2648 wcscpy(lpStr, lpEmptyString);
2649 }
2650
2651 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2652 }
2653
2654 if (pcbBytesNeeded != NULL)
2655 *pcbBytesNeeded = dwRequiredSize;
2656
2657 Done:;
2658 if (lpImagePath != NULL)
2659 HeapFree(GetProcessHeap(), 0, lpImagePath);
2660
2661 if (lpServiceStartName != NULL)
2662 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2663
2664 if (hServiceKey != NULL)
2665 RegCloseKey(hServiceKey);
2666
2667 /* FIXME: Unlock the service database */
2668
2669 DPRINT("RQueryServiceConfigW() done\n");
2670
2671 return dwError;
2672 }
2673
2674
2675 /* Function 18 */
2676 DWORD RQueryServiceLockStatusW(
2677 handle_t BindingHandle,
2678 SC_RPC_HANDLE hSCManager,
2679 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2680 DWORD cbBufSize,
2681 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2682 {
2683 UNIMPLEMENTED;
2684 return ERROR_CALL_NOT_IMPLEMENTED;
2685 }
2686
2687
2688 /* Function 19 */
2689 DWORD RStartServiceW(
2690 handle_t BindingHandle,
2691 SC_RPC_HANDLE hService,
2692 DWORD argc,
2693 LPSTRING_PTRSW argv)
2694 {
2695 DWORD dwError = ERROR_SUCCESS;
2696 PSERVICE_HANDLE hSvc;
2697 PSERVICE lpService = NULL;
2698
2699 DPRINT("RStartServiceW() called\n");
2700
2701 if (ScmShutdown)
2702 return ERROR_SHUTDOWN_IN_PROGRESS;
2703
2704 hSvc = (PSERVICE_HANDLE)hService;
2705 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2706 {
2707 DPRINT1("Invalid handle tag!\n");
2708 return ERROR_INVALID_HANDLE;
2709 }
2710
2711 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2712 SERVICE_START))
2713 {
2714 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2715 return ERROR_ACCESS_DENIED;
2716 }
2717
2718 lpService = hSvc->ServiceEntry;
2719 if (lpService == NULL)
2720 {
2721 DPRINT1("lpService == NULL!\n");
2722 return ERROR_INVALID_HANDLE;
2723 }
2724
2725 if (lpService->dwStartType == SERVICE_DISABLED)
2726 return ERROR_SERVICE_DISABLED;
2727
2728 if (lpService->bDeleted)
2729 return ERROR_SERVICE_MARKED_FOR_DELETE;
2730
2731 if (argv) {
2732 UNIMPLEMENTED;
2733 argv = NULL;
2734 }
2735
2736 /* Start the service */
2737 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2738
2739 return dwError;
2740 }
2741
2742
2743 /* Function 20 */
2744 DWORD RGetServiceDisplayNameW(
2745 handle_t BindingHandle,
2746 SC_RPC_HANDLE hSCManager,
2747 LPWSTR lpServiceName,
2748 LPWSTR lpDisplayName,
2749 DWORD *lpcchBuffer)
2750 {
2751 // PMANAGER_HANDLE hManager;
2752 PSERVICE lpService;
2753 DWORD dwLength;
2754 DWORD dwError;
2755
2756 DPRINT("RGetServiceDisplayNameW() called\n");
2757 DPRINT("hSCManager = %p\n", hSCManager);
2758 DPRINT("lpServiceName: %S\n", lpServiceName);
2759 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2760 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2761
2762 // hManager = (PMANAGER_HANDLE)hSCManager;
2763 // if (hManager->Handle.Tag != MANAGER_TAG)
2764 // {
2765 // DPRINT1("Invalid manager handle!\n");
2766 // return ERROR_INVALID_HANDLE;
2767 // }
2768
2769 /* Get service database entry */
2770 lpService = ScmGetServiceEntryByName(lpServiceName);
2771 if (lpService == NULL)
2772 {
2773 DPRINT1("Could not find a service!\n");
2774
2775 /* If the service could not be found and lpcchBuffer is 0, windows
2776 puts null in lpDisplayName and puts 1 in lpcchBuffer */
2777 if (*lpcchBuffer == 0)
2778 {
2779 *lpcchBuffer = 1;
2780 *lpDisplayName = '\0';
2781 }
2782
2783 return ERROR_SERVICE_DOES_NOT_EXIST;
2784 }
2785
2786 if (!lpService->lpDisplayName)
2787 {
2788 dwLength = wcslen(lpService->lpServiceName);
2789
2790 if (lpServiceName != NULL &&
2791 *lpcchBuffer > dwLength)
2792 {
2793 wcscpy(lpDisplayName, lpService->lpServiceName);
2794 }
2795 }
2796 else
2797 {
2798 dwLength = wcslen(lpService->lpDisplayName);
2799
2800 if (lpDisplayName != NULL &&
2801 *lpcchBuffer > dwLength)
2802 {
2803 wcscpy(lpDisplayName, lpService->lpDisplayName);
2804 }
2805 }
2806
2807 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2808
2809 *lpcchBuffer = dwLength;
2810
2811 return dwError;
2812 }
2813
2814
2815 /* Function 21 */
2816 DWORD RGetServiceKeyNameW(
2817 handle_t BindingHandle,
2818 SC_RPC_HANDLE hSCManager,
2819 LPWSTR lpDisplayName,
2820 LPWSTR lpServiceName,
2821 DWORD *lpcchBuffer)
2822 {
2823 // PMANAGER_HANDLE hManager;
2824 PSERVICE lpService;
2825 DWORD dwLength;
2826 DWORD dwError;
2827
2828 DPRINT("RGetServiceKeyNameW() called\n");
2829 DPRINT("hSCManager = %p\n", hSCManager);
2830 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2831 DPRINT("lpServiceName: %p\n", lpServiceName);
2832 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2833
2834 // hManager = (PMANAGER_HANDLE)hSCManager;
2835 // if (hManager->Handle.Tag != MANAGER_TAG)
2836 // {
2837 // DPRINT1("Invalid manager handle!\n");
2838 // return ERROR_INVALID_HANDLE;
2839 // }
2840
2841 /* Get service database entry */
2842 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2843 if (lpService == NULL)
2844 {
2845 DPRINT1("Could not find a service!\n");
2846
2847 /* If the service could not be found and lpcchBuffer is 0, windows
2848 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2849 if (*lpcchBuffer == 0)
2850 {
2851 *lpcchBuffer = 2;
2852 *lpServiceName = '\0';
2853 }
2854
2855 return ERROR_SERVICE_DOES_NOT_EXIST;
2856 }
2857
2858 dwLength = wcslen(lpService->lpServiceName);
2859
2860 if (lpServiceName != NULL &&
2861 *lpcchBuffer > dwLength)
2862 {
2863 wcscpy(lpServiceName, lpService->lpServiceName);
2864 *lpcchBuffer = dwLength;
2865 return ERROR_SUCCESS;
2866 }
2867
2868 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2869
2870 *lpcchBuffer = dwLength * 2;
2871
2872 return dwError;
2873 }
2874
2875
2876 /* Function 22 */
2877 DWORD RI_ScSetServiceBitsA(
2878 handle_t BindingHandle,
2879 SC_RPC_HANDLE hServiceStatus,
2880 DWORD dwServiceBits,
2881 int bSetBitsOn,
2882 int bUpdateImmediately,
2883 char *lpString)
2884 {
2885 UNIMPLEMENTED;
2886 return ERROR_CALL_NOT_IMPLEMENTED;
2887 }
2888
2889
2890 /* Function 23 */
2891 DWORD RChangeServiceConfigA(
2892 handle_t BindingHandle,
2893 SC_RPC_HANDLE hService,
2894 DWORD dwServiceType,
2895 DWORD dwStartType,
2896 DWORD dwErrorControl,
2897 LPSTR lpBinaryPathName,
2898 LPSTR lpLoadOrderGroup,
2899 LPDWORD lpdwTagId,
2900 LPSTR lpDependencies,
2901 DWORD dwDependSize,
2902 LPSTR lpServiceStartName,
2903 LPBYTE lpPassword,
2904 DWORD dwPwSize,
2905 LPSTR lpDisplayName)
2906 {
2907 DWORD dwError = ERROR_SUCCESS;
2908 PSERVICE_HANDLE hSvc;
2909 PSERVICE lpService = NULL;
2910 HKEY hServiceKey = NULL;
2911 LPWSTR lpDisplayNameW = NULL;
2912 // LPWSTR lpBinaryPathNameW = NULL;
2913 LPWSTR lpLoadOrderGroupW = NULL;
2914 LPWSTR lpDependenciesW = NULL;
2915 // LPWSTR lpPasswordW = NULL;
2916
2917 DPRINT("RChangeServiceConfigA() called\n");
2918 DPRINT("dwServiceType = %lu\n", dwServiceType);
2919 DPRINT("dwStartType = %lu\n", dwStartType);
2920 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2921 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2922 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2923 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2924
2925 if (ScmShutdown)
2926 return ERROR_SHUTDOWN_IN_PROGRESS;
2927
2928 hSvc = (PSERVICE_HANDLE)hService;
2929 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2930 {
2931 DPRINT1("Invalid handle tag!\n");
2932 return ERROR_INVALID_HANDLE;
2933 }
2934
2935 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2936 SERVICE_CHANGE_CONFIG))
2937 {
2938 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2939 return ERROR_ACCESS_DENIED;
2940 }
2941
2942 lpService = hSvc->ServiceEntry;
2943 if (lpService == NULL)
2944 {
2945 DPRINT1("lpService == NULL!\n");
2946 return ERROR_INVALID_HANDLE;
2947 }
2948
2949 /* FIXME: Lock database exclusively */
2950
2951 if (lpService->bDeleted)
2952 {
2953 /* FIXME: Unlock database */
2954 DPRINT1("The service has already been marked for delete!\n");
2955 return ERROR_SERVICE_MARKED_FOR_DELETE;
2956 }
2957
2958 /* Open the service key */
2959 dwError = ScmOpenServiceKey(lpService->szServiceName,
2960 KEY_SET_VALUE,
2961 &hServiceKey);
2962 if (dwError != ERROR_SUCCESS)
2963 goto done;
2964
2965 /* Write service data to the registry */
2966
2967 if (lpDisplayName != NULL && *lpDisplayName != 0)
2968 {
2969 /* Set the display name */
2970 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2971 0,
2972 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
2973 if (lpDisplayNameW == NULL)
2974 {
2975 dwError = ERROR_NOT_ENOUGH_MEMORY;
2976 goto done;
2977 }
2978
2979 MultiByteToWideChar(CP_ACP,
2980 0,
2981 lpDisplayName,
2982 -1,
2983 lpDisplayNameW,
2984 wcslen(lpDisplayNameW) + 1);
2985
2986 RegSetValueExW(hServiceKey,
2987 L"DisplayName",
2988 0,
2989 REG_SZ,
2990 (LPBYTE)lpDisplayNameW,
2991 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2992
2993 /* Update lpService->lpDisplayName */
2994 if (lpService->lpDisplayName)
2995 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2996
2997 lpService->lpDisplayName = lpDisplayNameW;
2998 }
2999
3000 if (dwServiceType != SERVICE_NO_CHANGE)
3001 {
3002 /* Set the service type */
3003 dwError = RegSetValueExW(hServiceKey,
3004 L"Type",
3005 0,
3006 REG_DWORD,
3007 (LPBYTE)&dwServiceType,
3008 sizeof(DWORD));
3009 if (dwError != ERROR_SUCCESS)
3010 goto done;
3011
3012 lpService->Status.dwServiceType = dwServiceType;
3013 }
3014
3015 if (dwStartType != SERVICE_NO_CHANGE)
3016 {
3017 /* Set the start value */
3018 dwError = RegSetValueExW(hServiceKey,
3019 L"Start",
3020 0,
3021 REG_DWORD,
3022 (LPBYTE)&dwStartType,
3023 sizeof(DWORD));
3024 if (dwError != ERROR_SUCCESS)
3025 goto done;
3026
3027 lpService->dwStartType = dwStartType;
3028 }
3029
3030 if (dwErrorControl != SERVICE_NO_CHANGE)
3031 {
3032 /* Set the error control value */
3033 dwError = RegSetValueExW(hServiceKey,
3034 L"ErrorControl",
3035 0,
3036 REG_DWORD,
3037 (LPBYTE)&dwErrorControl,
3038 sizeof(DWORD));
3039 if (dwError != ERROR_SUCCESS)
3040 goto done;
3041
3042 lpService->dwErrorControl = dwErrorControl;
3043 }
3044
3045 #if 0
3046 /* FIXME: set the new ImagePath value */
3047
3048 /* Set the image path */
3049 if (dwServiceType & SERVICE_WIN32)
3050 {
3051 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3052 {
3053 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3054 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, wcslen(lpBinaryPathNameW)+1);
3055 dwError = RegSetValueExW(hServiceKey,
3056 L"ImagePath",
3057 0,
3058 REG_EXPAND_SZ,
3059 (LPBYTE)lpBinaryPathNameW,
3060 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3061 if (dwError != ERROR_SUCCESS)
3062 goto done;
3063 }
3064 }
3065 else if (dwServiceType & SERVICE_DRIVER)
3066 {
3067 if (lpImagePath != NULL && *lpImagePath != 0)
3068 {
3069 dwError = RegSetValueExW(hServiceKey,
3070 L"ImagePath",
3071 0,
3072 REG_EXPAND_SZ,
3073 (LPBYTE)lpImagePath,
3074 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3075 if (dwError != ERROR_SUCCESS)
3076 goto done;
3077 }
3078 }
3079 #endif
3080
3081 /* Set the group name */
3082 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3083 {
3084 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3085 0,
3086 (strlen(lpLoadOrderGroup)+1) * sizeof(WCHAR));
3087 if (lpLoadOrderGroupW == NULL)
3088 {
3089 dwError = ERROR_NOT_ENOUGH_MEMORY;
3090 goto done;
3091 }
3092
3093 MultiByteToWideChar(CP_ACP,
3094 0,
3095 lpLoadOrderGroup,
3096 -1,
3097 lpLoadOrderGroupW,
3098 wcslen(lpLoadOrderGroupW) + 1);
3099
3100 dwError = RegSetValueExW(hServiceKey,
3101 L"Group",
3102 0,
3103 REG_SZ,
3104 (LPBYTE)lpLoadOrderGroupW,
3105 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3106 if (dwError != ERROR_SUCCESS)
3107 goto done;
3108
3109 /* FIXME: Update lpService->lpServiceGroup */
3110
3111 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3112 }
3113
3114 if (lpdwTagId != NULL)
3115 {
3116 dwError = ScmAssignNewTag(lpService);
3117 if (dwError != ERROR_SUCCESS)
3118 goto done;
3119
3120 dwError = RegSetValueExW(hServiceKey,
3121 L"Tag",
3122 0,
3123 REG_DWORD,
3124 (LPBYTE)&lpService->dwTag,
3125 sizeof(DWORD));
3126 if (dwError != ERROR_SUCCESS)
3127 goto done;
3128
3129 *lpdwTagId = lpService->dwTag;
3130 }
3131
3132 /* Write dependencies */
3133 if (lpDependencies != NULL && *lpDependencies != 0)
3134 {
3135 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3136 0,
3137 (strlen(lpDependencies)+1) * sizeof(WCHAR));
3138 if (lpDependenciesW == NULL)
3139 {
3140 dwError = ERROR_NOT_ENOUGH_MEMORY;
3141 goto done;
3142 }
3143
3144 MultiByteToWideChar(CP_ACP,
3145 0,
3146 lpDependencies,
3147 dwDependSize,
3148 lpDependenciesW,
3149 wcslen(lpDependenciesW)+1);
3150
3151 dwError = ScmWriteDependencies(hServiceKey,
3152 (LPWSTR)lpDependenciesW,
3153 dwDependSize);
3154
3155 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3156 }
3157
3158 if (lpPassword != NULL)
3159 {
3160 /* FIXME: Write password */
3161 }
3162
3163 /* FIXME: Unlock database */
3164
3165 done:
3166 if (hServiceKey != NULL)
3167 RegCloseKey(hServiceKey);
3168
3169 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3170
3171 return dwError;
3172 }
3173
3174
3175 /* Function 24 */
3176 DWORD RCreateServiceA(
3177 handle_t BindingHandle,
3178 SC_RPC_HANDLE hSCManager,
3179 LPSTR lpServiceName,
3180 LPSTR lpDisplayName,
3181 DWORD dwDesiredAccess,
3182 DWORD dwServiceType,
3183 DWORD dwStartType,
3184 DWORD dwErrorControl,
3185 LPSTR lpBinaryPathName,
3186 LPSTR lpLoadOrderGroup,
3187 LPDWORD lpdwTagId,
3188 LPBYTE lpDependencies,
3189 DWORD dwDependSize,
3190 LPSTR lpServiceStartName,
3191 LPBYTE lpPassword,
3192 DWORD dwPwSize,
3193 LPSC_RPC_HANDLE lpServiceHandle)
3194 {
3195 UNIMPLEMENTED;
3196 return ERROR_CALL_NOT_IMPLEMENTED;
3197 }
3198
3199
3200 /* Function 25 */
3201 DWORD REnumDependentServicesA(
3202 handle_t BindingHandle,
3203 SC_RPC_HANDLE hService,
3204 DWORD dwServiceState,
3205 LPBYTE lpServices,
3206 DWORD cbBufSize,
3207 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3208 LPBOUNDED_DWORD_256K lpServicesReturned)
3209 {
3210 DWORD dwError = ERROR_SUCCESS;
3211 DWORD dwServicesReturned = 0;
3212 DWORD dwServiceCount;
3213 HKEY hServicesKey = NULL;
3214 LPSC_RPC_HANDLE hSCObject;
3215 PSERVICE_HANDLE hSvc;
3216 PSERVICE lpService = NULL;
3217 PSERVICE *lpServicesArray = NULL;
3218 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3219 LPSTR lpStr;
3220
3221 *pcbBytesNeeded = 0;
3222 *lpServicesReturned = 0;
3223
3224 DPRINT("REnumDependentServicesA() called\n");
3225
3226 hSCObject = &hService;
3227 hSvc = (PSERVICE_HANDLE) *hSCObject;
3228 lpService = hSvc->ServiceEntry;
3229
3230 /* Check access rights */
3231 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3232 SC_MANAGER_ENUMERATE_SERVICE))
3233 {
3234 DPRINT1("Insufficient access rights! 0x%lx\n",
3235 hSvc->Handle.DesiredAccess);
3236 return ERROR_ACCESS_DENIED;
3237 }
3238
3239 /* Open the Services Reg key */
3240 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3241 L"System\\CurrentControlSet\\Services",
3242 0,
3243 KEY_READ,
3244 &hServicesKey);
3245
3246 if (dwError != ERROR_SUCCESS) return dwError;
3247
3248 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3249 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3250 are the same for both. Verified in WINXP. */
3251
3252 /* First determine the bytes needed and get the number of dependent services*/
3253 dwError = Int_EnumDependentServicesW(hServicesKey,
3254 lpService,
3255 dwServiceState,
3256 NULL,
3257 pcbBytesNeeded,
3258 &dwServicesReturned);
3259 if (dwError != ERROR_SUCCESS)
3260 goto Done;
3261
3262 /* If buffer size is less than the bytes needed or pointer is null*/
3263 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3264