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