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