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