d9dcfa3a50fa4c0734bfbc43a2f0e4ddcdf641f9
[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
1286 dwError = ScmSetServiceGroup(lpService,
1287 lpLoadOrderGroup);
1288 if (dwError != ERROR_SUCCESS)
1289 goto done;
1290 }
1291
1292 if (lpdwTagId != NULL)
1293 {
1294 dwError = ScmAssignNewTag(lpService);
1295 if (dwError != ERROR_SUCCESS)
1296 goto done;
1297
1298 dwError = RegSetValueExW(hServiceKey,
1299 L"Tag",
1300 0,
1301 REG_DWORD,
1302 (LPBYTE)&lpService->dwTag,
1303 sizeof(DWORD));
1304 if (dwError != ERROR_SUCCESS)
1305 goto done;
1306
1307 *lpdwTagId = lpService->dwTag;
1308 }
1309
1310 /* Write dependencies */
1311 if (lpDependencies != NULL && *lpDependencies != 0)
1312 {
1313 dwError = ScmWriteDependencies(hServiceKey,
1314 (LPWSTR)lpDependencies,
1315 dwDependSize);
1316 if (dwError != ERROR_SUCCESS)
1317 goto done;
1318 }
1319
1320 if (lpPassword != NULL)
1321 {
1322 /* FIXME: Write password */
1323 }
1324
1325 /* FIXME: Unlock database */
1326
1327 done:
1328 if (hServiceKey != NULL)
1329 RegCloseKey(hServiceKey);
1330
1331 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1332
1333 return dwError;
1334 }
1335
1336
1337 /* Create a path suitable for the bootloader out of the full path */
1338 DWORD
1339 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1340 {
1341 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1342 WCHAR Dest;
1343 WCHAR *Expanded;
1344 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1345 OBJECT_ATTRIBUTES ObjectAttributes;
1346 NTSTATUS Status;
1347 HANDLE SymbolicLinkHandle;
1348
1349 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1350
1351 ServiceNameLen = wcslen(CanonName);
1352
1353 /* First check, if it's already good */
1354 if (ServiceNameLen > 12 &&
1355 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1356 {
1357 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1358 if (*RelativeName == NULL)
1359 {
1360 DPRINT1("Error allocating memory for boot driver name!\n");
1361 return ERROR_NOT_ENOUGH_MEMORY;
1362 }
1363
1364 /* Copy it */
1365 wcscpy(*RelativeName, CanonName);
1366
1367 DPRINT1("Bootdriver name %S\n", *RelativeName);
1368 return ERROR_SUCCESS;
1369 }
1370
1371 /* If it has %SystemRoot% prefix, substitute it to \System*/
1372 if (ServiceNameLen > 13 &&
1373 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1374 {
1375 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1376 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1377
1378 if (*RelativeName == NULL)
1379 {
1380 DPRINT1("Error allocating memory for boot driver name!\n");
1381 return ERROR_NOT_ENOUGH_MEMORY;
1382 }
1383
1384 /* Copy it */
1385 wcscpy(*RelativeName, L"\\SystemRoot\\");
1386 wcscat(*RelativeName, CanonName + 13);
1387
1388 DPRINT1("Bootdriver name %S\n", *RelativeName);
1389 return ERROR_SUCCESS;
1390 }
1391
1392 /* Get buffer size needed for expanding env strings */
1393 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1394
1395 if (BufferSize <= 1)
1396 {
1397 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1398 return ERROR_INVALID_ENVIRONMENT;
1399 }
1400
1401 /* Allocate memory, since the size is known now */
1402 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1403 if (!Expanded)
1404 {
1405 DPRINT1("Error allocating memory for boot driver name!\n");
1406 return ERROR_NOT_ENOUGH_MEMORY;
1407 }
1408
1409 /* Expand it */
1410 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1411 BufferSize)
1412 {
1413 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1414 LocalFree(Expanded);
1415 return ERROR_NOT_ENOUGH_MEMORY;
1416 }
1417
1418 /* Convert to NY-style path */
1419 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1420 {
1421 DPRINT1("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1422 return ERROR_INVALID_ENVIRONMENT;
1423 }
1424
1425 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1426
1427 /* No need to keep the dos-path anymore */
1428 LocalFree(Expanded);
1429
1430 /* Copy it to the allocated place */
1431 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1432 if (!Expanded)
1433 {
1434 DPRINT1("Error allocating memory for boot driver name!\n");
1435 return ERROR_NOT_ENOUGH_MEMORY;
1436 }
1437
1438 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1439 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1440 Expanded[ExpandedLen] = 0;
1441
1442 if (ServiceNameLen > ExpandedLen &&
1443 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
1444 {
1445 /* Only \SystemRoot\ is missing */
1446 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1447 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1448 if (*RelativeName == NULL)
1449 {
1450 DPRINT1("Error allocating memory for boot driver name!\n");
1451 LocalFree(Expanded);
1452 return ERROR_NOT_ENOUGH_MEMORY;
1453 }
1454
1455 wcscpy(*RelativeName, L"\\SystemRoot\\");
1456 wcscat(*RelativeName, CanonName + ExpandedLen);
1457
1458 RtlFreeUnicodeString(&NtPathName);
1459 return ERROR_SUCCESS;
1460 }
1461
1462 /* The most complex case starts here */
1463 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1464 InitializeObjectAttributes(&ObjectAttributes,
1465 &SystemRoot,
1466 OBJ_CASE_INSENSITIVE,
1467 NULL,
1468 NULL);
1469
1470 /* Open this symlink */
1471 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1472
1473 if (NT_SUCCESS(Status))
1474 {
1475 LinkTarget.Length = 0;
1476 LinkTarget.MaximumLength = 0;
1477
1478 DPRINT("Opened symbolic link object\n");
1479
1480 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1481 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1482 {
1483 /* Check if required buffer size is sane */
1484 if (BufferSize > 0xFFFD)
1485 {
1486 DPRINT1("Too large buffer required\n");
1487 *RelativeName = 0;
1488
1489 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1490 LocalFree(Expanded);
1491 return ERROR_NOT_ENOUGH_MEMORY;
1492 }
1493
1494 /* Alloc the string */
1495 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1496 if (!LinkTarget.Buffer)
1497 {
1498 DPRINT1("Unable to alloc buffer\n");
1499 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1500 LocalFree(Expanded);
1501 return ERROR_NOT_ENOUGH_MEMORY;
1502 }
1503
1504 /* Do a real query now */
1505 LinkTarget.Length = BufferSize;
1506 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1507
1508 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1509 if (NT_SUCCESS(Status))
1510 {
1511 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1512
1513 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1514 if ((ServiceNameLen > ExpandedLen) &&
1515 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1516 {
1517 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1518 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1519
1520 if (*RelativeName == NULL)
1521 {
1522 DPRINT1("Unable to alloc buffer\n");
1523 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1524 LocalFree(Expanded);
1525 RtlFreeUnicodeString(&NtPathName);
1526 return ERROR_NOT_ENOUGH_MEMORY;
1527 }
1528
1529 /* Copy it over, substituting the first part
1530 with SystemRoot */
1531 wcscpy(*RelativeName, L"\\SystemRoot\\");
1532 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1533
1534 /* Cleanup */
1535 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1536 LocalFree(Expanded);
1537 RtlFreeUnicodeString(&NtPathName);
1538
1539 /* Return success */
1540 return ERROR_SUCCESS;
1541 }
1542 else
1543 {
1544 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1545 LocalFree(Expanded);
1546 RtlFreeUnicodeString(&NtPathName);
1547 return ERROR_INVALID_PARAMETER;
1548 }
1549 }
1550 else
1551 {
1552 DPRINT1("Error, Status = %08X\n", Status);
1553 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1554 LocalFree(Expanded);
1555 RtlFreeUnicodeString(&NtPathName);
1556 return ERROR_INVALID_PARAMETER;
1557 }
1558 }
1559 else
1560 {
1561 DPRINT1("Error, Status = %08X\n", Status);
1562 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1563 LocalFree(Expanded);
1564 RtlFreeUnicodeString(&NtPathName);
1565 return ERROR_INVALID_PARAMETER;
1566 }
1567 }
1568 else
1569 {
1570 DPRINT1("Error, Status = %08X\n", Status);
1571 LocalFree(Expanded);
1572 return ERROR_INVALID_PARAMETER;
1573 }
1574
1575 /* Failure */
1576 *RelativeName = NULL;
1577 return ERROR_INVALID_PARAMETER;
1578 }
1579
1580 DWORD
1581 ScmCanonDriverImagePath(DWORD dwStartType,
1582 const wchar_t *lpServiceName,
1583 wchar_t **lpCanonName)
1584 {
1585 DWORD ServiceNameLen, Result;
1586 UNICODE_STRING NtServiceName;
1587 WCHAR *RelativeName;
1588 const WCHAR *SourceName = lpServiceName;
1589
1590 /* Calculate the length of the service's name */
1591 ServiceNameLen = wcslen(lpServiceName);
1592
1593 /* 12 is wcslen(L"\\SystemRoot\\") */
1594 if (ServiceNameLen > 12 &&
1595 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1596 {
1597 /* SystemRoot prefix is already included */
1598
1599 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1600
1601 if (*lpCanonName == NULL)
1602 {
1603 DPRINT1("Error allocating memory for canonized service name!\n");
1604 return ERROR_NOT_ENOUGH_MEMORY;
1605 }
1606
1607 /* If it's a boot-time driver, it must be systemroot relative */
1608 if (dwStartType == SERVICE_BOOT_START)
1609 SourceName += 12;
1610
1611 /* Copy it */
1612 wcscpy(*lpCanonName, SourceName);
1613
1614 DPRINT("Canonicalized name %S\n", *lpCanonName);
1615 return NO_ERROR;
1616 }
1617
1618 /* Check if it has %SystemRoot% (len=13) */
1619 if (ServiceNameLen > 13 &&
1620 !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1621 {
1622 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1623 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1624
1625 if (*lpCanonName == NULL)
1626 {
1627 DPRINT1("Error allocating memory for canonized service name!\n");
1628 return ERROR_NOT_ENOUGH_MEMORY;
1629 }
1630
1631 /* If it's a boot-time driver, it must be systemroot relative */
1632 if (dwStartType == SERVICE_BOOT_START)
1633 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1634
1635 wcscat(*lpCanonName, lpServiceName + 13);
1636
1637 DPRINT("Canonicalized name %S\n", *lpCanonName);
1638 return NO_ERROR;
1639 }
1640
1641 /* Check if it's a relative path name */
1642 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1643 {
1644 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1645
1646 if (*lpCanonName == NULL)
1647 {
1648 DPRINT1("Error allocating memory for canonized service name!\n");
1649 return ERROR_NOT_ENOUGH_MEMORY;
1650 }
1651
1652 /* Just copy it over without changing */
1653 wcscpy(*lpCanonName, lpServiceName);
1654
1655 return NO_ERROR;
1656 }
1657
1658 /* It seems to be a DOS path, convert it */
1659 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1660 {
1661 DPRINT1("RtlDosPathNameToNtPathName_U() failed!\n");
1662 return ERROR_INVALID_PARAMETER;
1663 }
1664
1665 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1666
1667 if (*lpCanonName == NULL)
1668 {
1669 DPRINT1("Error allocating memory for canonized service name!\n");
1670 RtlFreeUnicodeString(&NtServiceName);
1671 return ERROR_NOT_ENOUGH_MEMORY;
1672 }
1673
1674 /* Copy the string */
1675 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1676
1677 /* The unicode string is not needed anymore */
1678 RtlFreeUnicodeString(&NtServiceName);
1679
1680 if (dwStartType != SERVICE_BOOT_START)
1681 {
1682 DPRINT("Canonicalized name %S\n", *lpCanonName);
1683 return NO_ERROR;
1684 }
1685
1686 /* The service is boot-started, so must be relative */
1687 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1688 if (Result)
1689 {
1690 /* There is a problem, free name and return */
1691 LocalFree(*lpCanonName);
1692 DPRINT1("Error converting named!\n");
1693 return Result;
1694 }
1695
1696 ASSERT(RelativeName);
1697
1698 /* Copy that string */
1699 wcscpy(*lpCanonName, RelativeName + 12);
1700
1701 /* Free the allocated buffer */
1702 LocalFree(RelativeName);
1703
1704 DPRINT("Canonicalized name %S\n", *lpCanonName);
1705
1706 /* Success */
1707 return NO_ERROR;
1708 }
1709
1710
1711 /* Function 12 */
1712 DWORD RCreateServiceW(
1713 SC_RPC_HANDLE hSCManager,
1714 LPCWSTR lpServiceName,
1715 LPCWSTR lpDisplayName,
1716 DWORD dwDesiredAccess,
1717 DWORD dwServiceType,
1718 DWORD dwStartType,
1719 DWORD dwErrorControl,
1720 LPCWSTR lpBinaryPathName,
1721 LPCWSTR lpLoadOrderGroup,
1722 LPDWORD lpdwTagId,
1723 LPBYTE lpDependencies,
1724 DWORD dwDependSize,
1725 LPCWSTR lpServiceStartName,
1726 LPBYTE lpPassword,
1727 DWORD dwPwSize,
1728 LPSC_RPC_HANDLE lpServiceHandle)
1729 {
1730 PMANAGER_HANDLE hManager;
1731 DWORD dwError = ERROR_SUCCESS;
1732 PSERVICE lpService = NULL;
1733 SC_HANDLE hServiceHandle = NULL;
1734 LPWSTR lpImagePath = NULL;
1735 HKEY hServiceKey = NULL;
1736 LPWSTR lpObjectName;
1737
1738 DPRINT("RCreateServiceW() called\n");
1739 DPRINT("lpServiceName = %S\n", lpServiceName);
1740 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1741 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1742 DPRINT("dwServiceType = %lu\n", dwServiceType);
1743 DPRINT("dwStartType = %lu\n", dwStartType);
1744 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1745 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1746 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1747
1748 if (ScmShutdown)
1749 return ERROR_SHUTDOWN_IN_PROGRESS;
1750
1751 hManager = (PMANAGER_HANDLE)hSCManager;
1752 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1753 {
1754 DPRINT1("Invalid manager handle!\n");
1755 return ERROR_INVALID_HANDLE;
1756 }
1757
1758 /* Check access rights */
1759 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1760 SC_MANAGER_CREATE_SERVICE))
1761 {
1762 DPRINT1("Insufficient access rights! 0x%lx\n",
1763 hManager->Handle.DesiredAccess);
1764 return ERROR_ACCESS_DENIED;
1765 }
1766
1767 if (wcslen(lpServiceName) == 0)
1768 {
1769 return ERROR_INVALID_NAME;
1770 }
1771
1772 if (wcslen(lpBinaryPathName) == 0)
1773 {
1774 return ERROR_INVALID_PARAMETER;
1775 }
1776
1777 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1778 (lpServiceStartName))
1779 {
1780 return ERROR_INVALID_PARAMETER;
1781 }
1782
1783 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
1784 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1785 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
1786 {
1787 return ERROR_INVALID_PARAMETER;
1788 }
1789
1790 if (dwStartType > SERVICE_DISABLED)
1791 {
1792 return ERROR_INVALID_PARAMETER;
1793 }
1794
1795 lpService = ScmGetServiceEntryByName(lpServiceName);
1796 if (lpService)
1797 {
1798 /* check if it is marked for deletion */
1799 if (lpService->bDeleted)
1800 return ERROR_SERVICE_MARKED_FOR_DELETE;
1801 /* Return Error exist */
1802 return ERROR_SERVICE_EXISTS;
1803 }
1804
1805 if (lpDisplayName != NULL &&
1806 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
1807 return ERROR_DUPLICATE_SERVICE_NAME;
1808
1809 if (dwServiceType & SERVICE_DRIVER)
1810 {
1811 dwError = ScmCanonDriverImagePath(dwStartType,
1812 lpBinaryPathName,
1813 &lpImagePath);
1814 if (dwError != ERROR_SUCCESS)
1815 goto done;
1816 }
1817 else
1818 {
1819 if (dwStartType == SERVICE_BOOT_START ||
1820 dwStartType == SERVICE_SYSTEM_START)
1821 {
1822 return ERROR_INVALID_PARAMETER;
1823 }
1824 }
1825
1826 /* Allocate a new service entry */
1827 dwError = ScmCreateNewServiceRecord(lpServiceName,
1828 &lpService);
1829 if (dwError != ERROR_SUCCESS)
1830 goto done;
1831
1832 /* Fill the new service entry */
1833 lpService->Status.dwServiceType = dwServiceType;
1834 lpService->dwStartType = dwStartType;
1835 lpService->dwErrorControl = dwErrorControl;
1836
1837 /* Fill the display name */
1838 if (lpDisplayName != NULL &&
1839 *lpDisplayName != 0 &&
1840 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1841 {
1842 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1843 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1844 if (lpService->lpDisplayName == NULL)
1845 {
1846 dwError = ERROR_NOT_ENOUGH_MEMORY;
1847 goto done;
1848 }
1849 wcscpy(lpService->lpDisplayName, lpDisplayName);
1850 }
1851
1852 /* Assign the service to a group */
1853 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1854 {
1855 dwError = ScmSetServiceGroup(lpService,
1856 lpLoadOrderGroup);
1857 if (dwError != ERROR_SUCCESS)
1858 goto done;
1859 }
1860
1861 /* Assign a new tag */
1862 if (lpdwTagId != NULL)
1863 {
1864 dwError = ScmAssignNewTag(lpService);
1865 if (dwError != ERROR_SUCCESS)
1866 goto done;
1867 }
1868
1869 /* Write service data to the registry */
1870 /* Create the service key */
1871 dwError = ScmCreateServiceKey(lpServiceName,
1872 KEY_WRITE,
1873 &hServiceKey);
1874 if (dwError != ERROR_SUCCESS)
1875 goto done;
1876
1877 /* Set the display name */
1878 if (lpDisplayName != NULL && *lpDisplayName != 0)
1879 {
1880 RegSetValueExW(hServiceKey,
1881 L"DisplayName",
1882 0,
1883 REG_SZ,
1884 (LPBYTE)lpDisplayName,
1885 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1886 }
1887
1888 /* Set the service type */
1889 dwError = RegSetValueExW(hServiceKey,
1890 L"Type",
1891 0,
1892 REG_DWORD,
1893 (LPBYTE)&dwServiceType,
1894 sizeof(DWORD));
1895 if (dwError != ERROR_SUCCESS)
1896 goto done;
1897
1898 /* Set the start value */
1899 dwError = RegSetValueExW(hServiceKey,
1900 L"Start",
1901 0,
1902 REG_DWORD,
1903 (LPBYTE)&dwStartType,
1904 sizeof(DWORD));
1905 if (dwError != ERROR_SUCCESS)
1906 goto done;
1907
1908 /* Set the error control value */
1909 dwError = RegSetValueExW(hServiceKey,
1910 L"ErrorControl",
1911 0,
1912 REG_DWORD,
1913 (LPBYTE)&dwErrorControl,
1914 sizeof(DWORD));
1915 if (dwError != ERROR_SUCCESS)
1916 goto done;
1917
1918 /* Set the image path */
1919 if (dwServiceType & SERVICE_WIN32)
1920 {
1921 dwError = RegSetValueExW(hServiceKey,
1922 L"ImagePath",
1923 0,
1924 REG_EXPAND_SZ,
1925 (LPBYTE)lpBinaryPathName,
1926 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1927 if (dwError != ERROR_SUCCESS)
1928 goto done;
1929 }
1930 else if (dwServiceType & SERVICE_DRIVER)
1931 {
1932 dwError = RegSetValueExW(hServiceKey,
1933 L"ImagePath",
1934 0,
1935 REG_EXPAND_SZ,
1936 (LPBYTE)lpImagePath,
1937 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
1938 if (dwError != ERROR_SUCCESS)
1939 goto done;
1940 }
1941
1942 /* Set the group name */
1943 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1944 {
1945 dwError = RegSetValueExW(hServiceKey,
1946 L"Group",
1947 0,
1948 REG_SZ,
1949 (LPBYTE)lpLoadOrderGroup,
1950 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1951 if (dwError != ERROR_SUCCESS)
1952 goto done;
1953 }
1954
1955 if (lpdwTagId != NULL)
1956 {
1957 dwError = RegSetValueExW(hServiceKey,
1958 L"Tag",
1959 0,
1960 REG_DWORD,
1961 (LPBYTE)&lpService->dwTag,
1962 sizeof(DWORD));
1963 if (dwError != ERROR_SUCCESS)
1964 goto done;
1965 }
1966
1967 /* Write dependencies */
1968 if (lpDependencies != NULL && *lpDependencies != 0)
1969 {
1970 dwError = ScmWriteDependencies(hServiceKey,
1971 (LPWSTR)lpDependencies,
1972 dwDependSize);
1973 if (dwError != ERROR_SUCCESS)
1974 goto done;
1975 }
1976
1977 /* Write service start name */
1978 if (dwServiceType & SERVICE_WIN32)
1979 {
1980 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
1981 dwError = RegSetValueExW(hServiceKey,
1982 L"ObjectName",
1983 0,
1984 REG_SZ,
1985 (LPBYTE)lpObjectName,
1986 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
1987 if (dwError != ERROR_SUCCESS)
1988 goto done;
1989 }
1990
1991 if (lpPassword != NULL)
1992 {
1993 /* FIXME: Write password */
1994 }
1995
1996 dwError = ScmCreateServiceHandle(lpService,
1997 &hServiceHandle);
1998 if (dwError != ERROR_SUCCESS)
1999 goto done;
2000
2001 dwError = ScmCheckAccess(hServiceHandle,
2002 dwDesiredAccess);
2003 if (dwError != ERROR_SUCCESS)
2004 goto done;
2005
2006 lpService->dwRefCount = 1;
2007 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2008
2009 done:;
2010 if (hServiceKey != NULL)
2011 RegCloseKey(hServiceKey);
2012
2013 if (dwError == ERROR_SUCCESS)
2014 {
2015 DPRINT("hService %p\n", hServiceHandle);
2016 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2017
2018 if (lpdwTagId != NULL)
2019 *lpdwTagId = lpService->dwTag;
2020 }
2021 else
2022 {
2023 /* Release the display name buffer */
2024 if (lpService->lpServiceName != NULL)
2025 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2026
2027 if (hServiceHandle)
2028 {
2029 /* Remove the service handle */
2030 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2031 }
2032
2033 if (lpService != NULL)
2034 {
2035 /* FIXME: remove the service entry */
2036 }
2037 }
2038
2039 if (lpImagePath != NULL)
2040 HeapFree(GetProcessHeap(), 0, lpImagePath);
2041
2042 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2043
2044 return dwError;
2045 }
2046
2047
2048 /* Function 13 */
2049 DWORD REnumDependentServicesW(
2050 SC_RPC_HANDLE hService,
2051 DWORD dwServiceState,
2052 LPBYTE lpServices,
2053 DWORD cbBufSize,
2054 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2055 LPBOUNDED_DWORD_256K lpServicesReturned)
2056 {
2057 DWORD dwError = ERROR_SUCCESS;
2058 DWORD dwServicesReturned = 0;
2059 DWORD dwServiceCount;
2060 HKEY hServicesKey = NULL;
2061 LPSC_RPC_HANDLE hSCObject;
2062 PSERVICE_HANDLE hSvc;
2063 PSERVICE lpService = NULL;
2064 PSERVICE *lpServicesArray = NULL;
2065 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2066 LPWSTR lpStr;
2067
2068 *pcbBytesNeeded = 0;
2069 *lpServicesReturned = 0;
2070
2071 DPRINT("REnumDependentServicesW() called\n");
2072
2073 hSCObject = &hService;
2074 hSvc = (PSERVICE_HANDLE) *hSCObject;
2075 lpService = hSvc->ServiceEntry;
2076
2077 /* Check access rights */
2078 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2079 SC_MANAGER_ENUMERATE_SERVICE))
2080 {
2081 DPRINT1("Insufficient access rights! 0x%lx\n",
2082 hSvc->Handle.DesiredAccess);
2083 return ERROR_ACCESS_DENIED;
2084 }
2085
2086 /* Open the Services Reg key */
2087 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2088 L"System\\CurrentControlSet\\Services",
2089 0,
2090 KEY_READ,
2091 &hServicesKey);
2092 if (dwError != ERROR_SUCCESS)
2093 return dwError;
2094
2095 /* First determine the bytes needed and get the number of dependent services */
2096 dwError = Int_EnumDependentServicesW(hServicesKey,
2097 lpService,
2098 dwServiceState,
2099 NULL,
2100 pcbBytesNeeded,
2101 &dwServicesReturned);
2102 if (dwError != ERROR_SUCCESS)
2103 goto Done;
2104
2105 /* If buffer size is less than the bytes needed or pointer is null */
2106 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2107 {
2108 dwError = ERROR_MORE_DATA;
2109 goto Done;
2110 }
2111
2112 /* Allocate memory for array of service pointers */
2113 lpServicesArray = HeapAlloc(GetProcessHeap(),
2114 0,
2115 (dwServicesReturned + 1) * sizeof(PSERVICE));
2116 if (!lpServicesArray)
2117 {
2118 DPRINT1("Could not allocate a buffer!!\n");
2119 dwError = ERROR_NOT_ENOUGH_MEMORY;
2120 goto Done;
2121 }
2122
2123 dwServicesReturned = 0;
2124 *pcbBytesNeeded = 0;
2125
2126 dwError = Int_EnumDependentServicesW(hServicesKey,
2127 lpService,
2128 dwServiceState,
2129 lpServicesArray,
2130 pcbBytesNeeded,
2131 &dwServicesReturned);
2132 if (dwError != ERROR_SUCCESS)
2133 {
2134 goto Done;
2135 }
2136
2137 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2138 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2139
2140 /* Copy EnumDepenedentService to Buffer */
2141 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2142 {
2143 lpService = lpServicesArray[dwServiceCount];
2144
2145 /* Copy status info */
2146 memcpy(&lpServicesPtr->ServiceStatus,
2147 &lpService->Status,
2148 sizeof(SERVICE_STATUS));
2149
2150 /* Copy display name */
2151 wcscpy(lpStr, lpService->lpDisplayName);
2152 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2153 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2154
2155 /* Copy service name */
2156 wcscpy(lpStr, lpService->lpServiceName);
2157 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2158 lpStr += (wcslen(lpService->lpServiceName) + 1);
2159
2160 lpServicesPtr ++;
2161 }
2162
2163 *lpServicesReturned = dwServicesReturned;
2164
2165 Done:
2166 if (lpServicesArray != NULL)
2167 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2168
2169 RegCloseKey(hServicesKey);
2170
2171 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2172
2173 return dwError;
2174 }
2175
2176
2177 /* Function 14 */
2178 DWORD REnumServicesStatusW(
2179 SC_RPC_HANDLE hSCManager,
2180 DWORD dwServiceType,
2181 DWORD dwServiceState,
2182 LPBYTE lpBuffer,
2183 DWORD dwBufSize,
2184 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2185 LPBOUNDED_DWORD_256K lpServicesReturned,
2186 LPBOUNDED_DWORD_256K lpResumeHandle)
2187 {
2188 PMANAGER_HANDLE hManager;
2189 PSERVICE lpService;
2190 DWORD dwError = ERROR_SUCCESS;
2191 PLIST_ENTRY ServiceEntry;
2192 PSERVICE CurrentService;
2193 DWORD dwState;
2194 DWORD dwRequiredSize;
2195 DWORD dwServiceCount;
2196 DWORD dwSize;
2197 DWORD dwLastResumeCount = 0;
2198 LPENUM_SERVICE_STATUSW lpStatusPtr;
2199 LPWSTR lpStringPtr;
2200
2201 DPRINT("REnumServicesStatusW() called\n");
2202
2203 if (ScmShutdown)
2204 return ERROR_SHUTDOWN_IN_PROGRESS;
2205
2206 hManager = (PMANAGER_HANDLE)hSCManager;
2207 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2208 {
2209 DPRINT1("Invalid manager handle!\n");
2210 return ERROR_INVALID_HANDLE;
2211 }
2212
2213 *pcbBytesNeeded = 0;
2214 *lpServicesReturned = 0;
2215
2216 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2217 {
2218 DPRINT("Not a valid Service Type!\n");
2219 return ERROR_INVALID_PARAMETER;
2220 }
2221
2222 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2223 {
2224 DPRINT("Not a valid Service State!\n");
2225 return ERROR_INVALID_PARAMETER;
2226 }
2227
2228 /* Check access rights */
2229 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2230 SC_MANAGER_ENUMERATE_SERVICE))
2231 {
2232 DPRINT1("Insufficient access rights! 0x%lx\n",
2233 hManager->Handle.DesiredAccess);
2234 return ERROR_ACCESS_DENIED;
2235 }
2236
2237 if (lpResumeHandle)
2238 dwLastResumeCount = *lpResumeHandle;
2239
2240 /* FIXME: Lock the service list shared */
2241
2242 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2243 if (lpService == NULL)
2244 {
2245 dwError = ERROR_SUCCESS;
2246 goto Done;
2247 }
2248
2249 dwRequiredSize = 0;
2250 dwServiceCount = 0;
2251
2252 for (ServiceEntry = &lpService->ServiceListEntry;
2253 ServiceEntry != &ServiceListHead;
2254 ServiceEntry = ServiceEntry->Flink)
2255 {
2256 CurrentService = CONTAINING_RECORD(ServiceEntry,
2257 SERVICE,
2258 ServiceListEntry);
2259
2260 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2261 continue;
2262
2263 dwState = SERVICE_ACTIVE;
2264 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2265 dwState = SERVICE_INACTIVE;
2266
2267 if ((dwState & dwServiceState) == 0)
2268 continue;
2269
2270 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2271 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2272 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2273
2274 if (dwRequiredSize + dwSize > dwBufSize)
2275 {
2276 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2277 break;
2278 }
2279
2280 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2281 dwRequiredSize += dwSize;
2282 dwServiceCount++;
2283 dwLastResumeCount = CurrentService->dwResumeCount;
2284 }
2285
2286 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2287 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2288
2289 for (;
2290 ServiceEntry != &ServiceListHead;
2291 ServiceEntry = ServiceEntry->Flink)
2292 {
2293 CurrentService = CONTAINING_RECORD(ServiceEntry,
2294 SERVICE,
2295 ServiceListEntry);
2296
2297 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2298 continue;
2299
2300 dwState = SERVICE_ACTIVE;
2301 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2302 dwState = SERVICE_INACTIVE;
2303
2304 if ((dwState & dwServiceState) == 0)
2305 continue;
2306
2307 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2308 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2309 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2310
2311 dwError = ERROR_MORE_DATA;
2312 }
2313
2314 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2315
2316 if (lpResumeHandle)
2317 *lpResumeHandle = dwLastResumeCount;
2318
2319 *lpServicesReturned = dwServiceCount;
2320 *pcbBytesNeeded = dwRequiredSize;
2321
2322 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2323 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2324 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2325
2326 dwRequiredSize = 0;
2327 for (ServiceEntry = &lpService->ServiceListEntry;
2328 ServiceEntry != &ServiceListHead;
2329 ServiceEntry = ServiceEntry->Flink)
2330 {
2331 CurrentService = CONTAINING_RECORD(ServiceEntry,
2332 SERVICE,
2333 ServiceListEntry);
2334
2335 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2336 continue;
2337
2338 dwState = SERVICE_ACTIVE;
2339 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2340 dwState = SERVICE_INACTIVE;
2341
2342 if ((dwState & dwServiceState) == 0)
2343 continue;
2344
2345 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2346 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2347 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2348
2349 if (dwRequiredSize + dwSize > dwBufSize)
2350 break;
2351
2352 /* Copy the service name */
2353 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2354 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2355 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2356
2357 /* Copy the display name */
2358 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2359 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2360 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2361
2362 /* Copy the status information */
2363 memcpy(&lpStatusPtr->ServiceStatus,
2364 &CurrentService->Status,
2365 sizeof(SERVICE_STATUS));
2366
2367 lpStatusPtr++;
2368 dwRequiredSize += dwSize;
2369 }
2370
2371 if (dwError == 0)
2372 {
2373 *pcbBytesNeeded = 0;
2374 if (lpResumeHandle) *lpResumeHandle = 0;
2375 }
2376
2377 Done:;
2378 /* FIXME: Unlock the service list */
2379
2380 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2381
2382 return dwError;
2383 }
2384
2385
2386 /* Function 15 */
2387 DWORD ROpenSCManagerW(
2388 LPWSTR lpMachineName,
2389 LPWSTR lpDatabaseName,
2390 DWORD dwDesiredAccess,
2391 LPSC_RPC_HANDLE lpScHandle)
2392 {
2393 DWORD dwError;
2394 SC_HANDLE hHandle;
2395
2396 DPRINT("ROpenSCManagerW() called\n");
2397 DPRINT("lpMachineName = %p\n", lpMachineName);
2398 DPRINT("lpMachineName: %S\n", lpMachineName);
2399 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2400 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2401 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2402
2403 if (ScmShutdown)
2404 return ERROR_SHUTDOWN_IN_PROGRESS;
2405
2406 if (!lpScHandle)
2407 return ERROR_INVALID_PARAMETER;
2408
2409 dwError = ScmCreateManagerHandle(lpDatabaseName,
2410 &hHandle);
2411 if (dwError != ERROR_SUCCESS)
2412 {
2413 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2414 return dwError;
2415 }
2416
2417 /* Check the desired access */
2418 dwError = ScmCheckAccess(hHandle,
2419 dwDesiredAccess | SC_MANAGER_CONNECT);
2420 if (dwError != ERROR_SUCCESS)
2421 {
2422 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2423 HeapFree(GetProcessHeap(), 0, hHandle);
2424 return dwError;
2425 }
2426
2427 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2428 DPRINT("*hScm = %p\n", *lpScHandle);
2429
2430 DPRINT("ROpenSCManagerW() done\n");
2431
2432 return ERROR_SUCCESS;
2433 }
2434
2435
2436 /* Function 16 */
2437 DWORD ROpenServiceW(
2438 SC_RPC_HANDLE hSCManager,
2439 LPWSTR lpServiceName,
2440 DWORD dwDesiredAccess,
2441 LPSC_RPC_HANDLE lpServiceHandle)
2442 {
2443 PSERVICE lpService;
2444 PMANAGER_HANDLE hManager;
2445 SC_HANDLE hHandle;
2446 DWORD dwError;
2447
2448 DPRINT("ROpenServiceW() called\n");
2449 DPRINT("hSCManager = %p\n", hSCManager);
2450 DPRINT("lpServiceName = %p\n", lpServiceName);
2451 DPRINT("lpServiceName: %S\n", lpServiceName);
2452 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2453
2454 if (ScmShutdown)
2455 return ERROR_SHUTDOWN_IN_PROGRESS;
2456
2457 hManager = (PMANAGER_HANDLE)hSCManager;
2458 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2459 {
2460 DPRINT1("Invalid manager handle!\n");
2461 return ERROR_INVALID_HANDLE;
2462 }
2463
2464 if (!lpServiceHandle)
2465 return ERROR_INVALID_PARAMETER;
2466
2467 if (!lpServiceName)
2468 return ERROR_INVALID_ADDRESS;
2469
2470 /* FIXME: Lock the service list */
2471
2472 /* Get service database entry */
2473 lpService = ScmGetServiceEntryByName(lpServiceName);
2474 if (lpService == NULL)
2475 {
2476 DPRINT("Could not find a service!\n");
2477 return ERROR_SERVICE_DOES_NOT_EXIST;
2478 }
2479
2480 /* Create a service handle */
2481 dwError = ScmCreateServiceHandle(lpService,
2482 &hHandle);
2483 if (dwError != ERROR_SUCCESS)
2484 {
2485 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2486 return dwError;
2487 }
2488
2489 /* Check the desired access */
2490 dwError = ScmCheckAccess(hHandle,
2491 dwDesiredAccess);
2492 if (dwError != ERROR_SUCCESS)
2493 {
2494 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2495 HeapFree(GetProcessHeap(), 0, hHandle);
2496 return dwError;
2497 }
2498
2499 lpService->dwRefCount++;
2500 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2501
2502 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2503 DPRINT("*hService = %p\n", *lpServiceHandle);
2504
2505 DPRINT("ROpenServiceW() done\n");
2506
2507 return ERROR_SUCCESS;
2508 }
2509
2510
2511 /* Function 17 */
2512 DWORD RQueryServiceConfigW(
2513 SC_RPC_HANDLE hService,
2514 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2515 DWORD cbBufSize,
2516 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2517 {
2518 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2519 DWORD dwError = ERROR_SUCCESS;
2520 PSERVICE_HANDLE hSvc;
2521 PSERVICE lpService = NULL;
2522 HKEY hServiceKey = NULL;
2523 LPWSTR lpImagePath = NULL;
2524 LPWSTR lpServiceStartName = NULL;
2525 LPWSTR lpDependencies = NULL;
2526 DWORD dwDependenciesLength = 0;
2527 DWORD dwRequiredSize;
2528 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2529 WCHAR lpEmptyString[] = {0,0};
2530 LPWSTR lpStr;
2531
2532 DPRINT("RQueryServiceConfigW() called\n");
2533
2534 if (ScmShutdown)
2535 return ERROR_SHUTDOWN_IN_PROGRESS;
2536
2537 hSvc = (PSERVICE_HANDLE)hService;
2538 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2539 {
2540 DPRINT1("Invalid handle tag!\n");
2541 return ERROR_INVALID_HANDLE;
2542 }
2543
2544 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2545 SERVICE_QUERY_CONFIG))
2546 {
2547 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2548 return ERROR_ACCESS_DENIED;
2549 }
2550
2551 lpService = hSvc->ServiceEntry;
2552 if (lpService == NULL)
2553 {
2554 DPRINT1("lpService == NULL!\n");
2555 return ERROR_INVALID_HANDLE;
2556 }
2557
2558 /* FIXME: Lock the service database shared */
2559
2560 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2561 KEY_READ,
2562 &hServiceKey);
2563 if (dwError != ERROR_SUCCESS)
2564 goto Done;
2565
2566 /* Read the image path */
2567 dwError = ScmReadString(hServiceKey,
2568 L"ImagePath",
2569 &lpImagePath);
2570 if (dwError != ERROR_SUCCESS)
2571 goto Done;
2572
2573 /* Read the service start name */
2574 ScmReadString(hServiceKey,
2575 L"ObjectName",
2576 &lpServiceStartName);
2577
2578 /* Read the dependencies */
2579 ScmReadDependencies(hServiceKey,
2580 &lpDependencies,
2581 &dwDependenciesLength);
2582
2583 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2584
2585 if (lpImagePath != NULL)
2586 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2587 else
2588 dwRequiredSize += 2 * sizeof(WCHAR);
2589
2590 if (lpService->lpGroup != NULL)
2591 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2592 else
2593 dwRequiredSize += 2 * sizeof(WCHAR);
2594
2595 if (lpDependencies != NULL)
2596 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2597 else
2598 dwRequiredSize += 2 * sizeof(WCHAR);
2599
2600 if (lpServiceStartName != NULL)
2601 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2602 else
2603 dwRequiredSize += 2 * sizeof(WCHAR);
2604
2605 if (lpService->lpDisplayName != NULL)
2606 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2607 else
2608 dwRequiredSize += 2 * sizeof(WCHAR);
2609
2610 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2611 {
2612 dwError = ERROR_INSUFFICIENT_BUFFER;
2613 }
2614 else
2615 {
2616 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2617 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2618 lpConfig->dwStartType = lpService->dwStartType;
2619 lpConfig->dwErrorControl = lpService->dwErrorControl;
2620 lpConfig->dwTagId = lpService->dwTag;
2621
2622 lpStr = (LPWSTR)(lpConfig + 1);
2623
2624 /* Append the image path */
2625 if (lpImagePath != NULL)
2626 {
2627 wcscpy(lpStr, lpImagePath);
2628 }
2629 else
2630 {
2631 wcscpy(lpStr, lpEmptyString);
2632 }
2633
2634 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2635 lpStr += (wcslen(lpStr) + 1);
2636
2637 /* Append the group name */
2638 if (lpService->lpGroup != NULL)
2639 {
2640 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2641 }
2642 else
2643 {
2644 wcscpy(lpStr, lpEmptyString);
2645 }
2646
2647 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2648 lpStr += (wcslen(lpStr) + 1);
2649
2650 /* Append Dependencies */
2651 if (lpDependencies != NULL)
2652 {
2653 memcpy(lpStr,
2654 lpDependencies,
2655 dwDependenciesLength * sizeof(WCHAR));
2656 }
2657 else
2658 {
2659 wcscpy(lpStr, lpEmptyString);
2660 }
2661
2662 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2663 if (lpDependencies != NULL)
2664 lpStr += dwDependenciesLength * sizeof(WCHAR);
2665 else
2666 lpStr += (wcslen(lpStr) + 1);
2667
2668 /* Append the service start name */
2669 if (lpServiceStartName != NULL)
2670 {
2671 wcscpy(lpStr, lpServiceStartName);
2672 }
2673 else
2674 {
2675 wcscpy(lpStr, lpEmptyString);
2676 }
2677
2678 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2679 lpStr += (wcslen(lpStr) + 1);
2680
2681 /* Append the display name */
2682 if (lpService->lpDisplayName != NULL)
2683 {
2684 wcscpy(lpStr, lpService->lpDisplayName);
2685 }
2686 else
2687 {
2688 wcscpy(lpStr, lpEmptyString);
2689 }
2690
2691 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2692 }
2693
2694 if (pcbBytesNeeded != NULL)
2695 *pcbBytesNeeded = dwRequiredSize;
2696
2697 Done:;
2698 if (lpImagePath != NULL)
2699 HeapFree(GetProcessHeap(), 0, lpImagePath);
2700
2701 if (lpServiceStartName != NULL)
2702 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2703
2704 if (lpDependencies != NULL)
2705 HeapFree(GetProcessHeap(), 0, lpDependencies);
2706
2707 if (hServiceKey != NULL)
2708 RegCloseKey(hServiceKey);
2709
2710 /* FIXME: Unlock the service database */
2711
2712 DPRINT("RQueryServiceConfigW() done\n");
2713
2714 return dwError;
2715 }
2716
2717
2718 /* Function 18 */
2719 DWORD RQueryServiceLockStatusW(
2720 SC_RPC_HANDLE hSCManager,
2721 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2722 DWORD cbBufSize,
2723 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2724 {
2725 UNIMPLEMENTED;
2726 return ERROR_CALL_NOT_IMPLEMENTED;
2727 }
2728
2729
2730 /* Function 19 */
2731 DWORD RStartServiceW(
2732 SC_RPC_HANDLE hService,
2733 DWORD argc,
2734 LPSTRING_PTRSW argv)
2735 {
2736 DWORD dwError = ERROR_SUCCESS;
2737 PSERVICE_HANDLE hSvc;
2738 PSERVICE lpService = NULL;
2739
2740 DPRINT("RStartServiceW() called\n");
2741
2742 if (ScmShutdown)
2743 return ERROR_SHUTDOWN_IN_PROGRESS;
2744
2745 hSvc = (PSERVICE_HANDLE)hService;
2746 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2747 {
2748 DPRINT1("Invalid handle tag!\n");
2749 return ERROR_INVALID_HANDLE;
2750 }
2751
2752 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2753 SERVICE_START))
2754 {
2755 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2756 return ERROR_ACCESS_DENIED;
2757 }
2758
2759 lpService = hSvc->ServiceEntry;
2760 if (lpService == NULL)
2761 {
2762 DPRINT1("lpService == NULL!\n");
2763 return ERROR_INVALID_HANDLE;
2764 }
2765
2766 if (lpService->dwStartType == SERVICE_DISABLED)
2767 return ERROR_SERVICE_DISABLED;
2768
2769 if (lpService->bDeleted)
2770 return ERROR_SERVICE_MARKED_FOR_DELETE;
2771
2772 if (argv) {
2773 UNIMPLEMENTED;
2774 argv = NULL;
2775 }
2776
2777 /* Start the service */
2778 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2779
2780 return dwError;
2781 }
2782
2783
2784 /* Function 20 */
2785 DWORD RGetServiceDisplayNameW(
2786 SC_RPC_HANDLE hSCManager,
2787 LPCWSTR lpServiceName,
2788 LPWSTR lpDisplayName,
2789 DWORD *lpcchBuffer)
2790 {
2791 // PMANAGER_HANDLE hManager;
2792 PSERVICE lpService;
2793 DWORD dwLength;
2794 DWORD dwError;
2795
2796 DPRINT("RGetServiceDisplayNameW() called\n");
2797 DPRINT("hSCManager = %p\n", hSCManager);
2798 DPRINT("lpServiceName: %S\n", lpServiceName);
2799 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2800 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2801
2802 // hManager = (PMANAGER_HANDLE)hSCManager;
2803 // if (hManager->Handle.Tag != MANAGER_TAG)
2804 // {
2805 // DPRINT1("Invalid manager handle!\n");
2806 // return ERROR_INVALID_HANDLE;
2807 // }
2808
2809 /* Get service database entry */
2810 lpService = ScmGetServiceEntryByName(lpServiceName);
2811 if (lpService == NULL)
2812 {
2813 DPRINT1("Could not find a service!\n");
2814
2815 /* If the service could not be found and lpcchBuffer is less than 2, windows
2816 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2817 if (*lpcchBuffer < 2)
2818 {
2819 *lpcchBuffer = 2;
2820 if (lpDisplayName != NULL)
2821 {
2822 *lpDisplayName = '\0';
2823 }
2824 }
2825
2826 return ERROR_SERVICE_DOES_NOT_EXIST;
2827 }
2828
2829 if (!lpService->lpDisplayName)
2830 {
2831 dwLength = wcslen(lpService->lpServiceName);
2832
2833 if (lpDisplayName != NULL &&
2834 *lpcchBuffer > dwLength)
2835 {
2836 wcscpy(lpDisplayName, lpService->lpServiceName);
2837 }
2838 }
2839 else
2840 {
2841 dwLength = wcslen(lpService->lpDisplayName);
2842
2843 if (lpDisplayName != NULL &&
2844 *lpcchBuffer > dwLength)
2845 {
2846 wcscpy(lpDisplayName, lpService->lpDisplayName);
2847 }
2848 }
2849
2850 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2851
2852 *lpcchBuffer = dwLength;
2853
2854 return dwError;
2855 }
2856
2857
2858 /* Function 21 */
2859 DWORD RGetServiceKeyNameW(
2860 SC_RPC_HANDLE hSCManager,
2861 LPCWSTR lpDisplayName,
2862 LPWSTR lpServiceName,
2863 DWORD *lpcchBuffer)
2864 {
2865 // PMANAGER_HANDLE hManager;
2866 PSERVICE lpService;
2867 DWORD dwLength;
2868 DWORD dwError;
2869
2870 DPRINT("RGetServiceKeyNameW() called\n");
2871 DPRINT("hSCManager = %p\n", hSCManager);
2872 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2873 DPRINT("lpServiceName: %p\n", lpServiceName);
2874 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2875
2876 // hManager = (PMANAGER_HANDLE)hSCManager;
2877 // if (hManager->Handle.Tag != MANAGER_TAG)
2878 // {
2879 // DPRINT1("Invalid manager handle!\n");
2880 // return ERROR_INVALID_HANDLE;
2881 // }
2882
2883 /* Get service database entry */
2884 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2885 if (lpService == NULL)
2886 {
2887 DPRINT1("Could not find a service!\n");
2888
2889 /* If the service could not be found and lpcchBuffer is less than 2, windows
2890 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2891 if (*lpcchBuffer < 2)
2892 {
2893 *lpcchBuffer = 2;
2894 if (lpServiceName != NULL)
2895 {
2896 *lpServiceName = '\0';
2897 }
2898 }
2899
2900 return ERROR_SERVICE_DOES_NOT_EXIST;
2901 }
2902
2903 dwLength = wcslen(lpService->lpServiceName);
2904
2905 if (lpServiceName != NULL &&
2906 *lpcchBuffer > dwLength)
2907 {
2908 wcscpy(lpServiceName, lpService->lpServiceName);
2909 *lpcchBuffer = dwLength;
2910 return ERROR_SUCCESS;
2911 }
2912
2913 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2914
2915 *lpcchBuffer = dwLength;
2916
2917 return dwError;
2918 }
2919
2920
2921 /* Function 22 */
2922 DWORD RI_ScSetServiceBitsA(
2923 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
2924 DWORD dwServiceBits,
2925 int bSetBitsOn,
2926 int bUpdateImmediately,
2927 char *lpString)
2928 {
2929 UNIMPLEMENTED;
2930 return ERROR_CALL_NOT_IMPLEMENTED;
2931 }
2932
2933
2934 /* Function 23 */
2935 DWORD RChangeServiceConfigA(
2936 SC_RPC_HANDLE hService,
2937 DWORD dwServiceType,
2938 DWORD dwStartType,
2939 DWORD dwErrorControl,
2940 LPSTR lpBinaryPathName,
2941 LPSTR lpLoadOrderGroup,
2942 LPDWORD lpdwTagId,
2943 LPSTR lpDependencies,
2944 DWORD dwDependSize,
2945 LPSTR lpServiceStartName,
2946 LPBYTE lpPassword,
2947 DWORD dwPwSize,
2948 LPSTR lpDisplayName)
2949 {
2950 DWORD dwError = ERROR_SUCCESS;
2951 PSERVICE_HANDLE hSvc;
2952 PSERVICE lpService = NULL;
2953 HKEY hServiceKey = NULL;
2954 LPWSTR lpDisplayNameW = NULL;
2955 // LPWSTR lpBinaryPathNameW = NULL;
2956 LPWSTR lpLoadOrderGroupW = NULL;
2957 LPWSTR lpDependenciesW = NULL;
2958 // LPWSTR lpPasswordW = NULL;
2959
2960 DPRINT("RChangeServiceConfigA() called\n");
2961 DPRINT("dwServiceType = %lu\n", dwServiceType);
2962 DPRINT("dwStartType = %lu\n", dwStartType);
2963 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2964 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2965 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2966 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2967
2968 if (ScmShutdown)
2969 return ERROR_SHUTDOWN_IN_PROGRESS;
2970
2971 hSvc = (PSERVICE_HANDLE)hService;
2972 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2973 {
2974 DPRINT1("Invalid handle tag!\n");
2975 return ERROR_INVALID_HANDLE;
2976 }
2977
2978 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2979 SERVICE_CHANGE_CONFIG))
2980 {
2981 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2982 return ERROR_ACCESS_DENIED;
2983 }
2984
2985 lpService = hSvc->ServiceEntry;
2986 if (lpService == NULL)
2987 {
2988 DPRINT1("lpService == NULL!\n");
2989 return ERROR_INVALID_HANDLE;
2990 }
2991
2992 /* FIXME: Lock database exclusively */
2993
2994 if (lpService->bDeleted)
2995 {
2996 /* FIXME: Unlock database */
2997 DPRINT1("The service has already been marked for delete!\n");
2998 return ERROR_SERVICE_MARKED_FOR_DELETE;
2999 }
3000
3001 /* Open the service key */
3002 dwError = ScmOpenServiceKey(lpService->szServiceName,
3003 KEY_SET_VALUE,
3004 &hServiceKey);
3005 if (dwError != ERROR_SUCCESS)
3006 goto done;
3007
3008 /* Write service data to the registry */
3009
3010 if (lpDisplayName != NULL && *lpDisplayName != 0)
3011 {
3012 /* Set the display name */
3013 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3014 0,
3015 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3016 if (lpDisplayNameW == NULL)
3017 {
3018 dwError = ERROR_NOT_ENOUGH_MEMORY;
3019 goto done;
3020 }
3021
3022 MultiByteToWideChar(CP_ACP,
3023 0,
3024 lpDisplayName,
3025 -1,
3026 lpDisplayNameW,
3027 strlen(lpDisplayName) + 1);
3028
3029 RegSetValueExW(hServiceKey,
3030 L"DisplayName",
3031 0,
3032 REG_SZ,
3033 (LPBYTE)lpDisplayNameW,
3034 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3035
3036 /* Update lpService->lpDisplayName */
3037 if (lpService->lpDisplayName)
3038 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3039
3040 lpService->lpDisplayName = lpDisplayNameW;
3041 }
3042
3043 if (dwServiceType != SERVICE_NO_CHANGE)
3044 {
3045 /* Set the service type */
3046 dwError = RegSetValueExW(hServiceKey,
3047 L"Type",
3048 0,
3049 REG_DWORD,
3050 (LPBYTE)&dwServiceType,
3051 sizeof(DWORD));
3052 if (dwError != ERROR_SUCCESS)
3053 goto done;
3054
3055 lpService->Status.dwServiceType = dwServiceType;
3056 }
3057
3058 if (dwStartType != SERVICE_NO_CHANGE)
3059 {
3060 /* Set the start value */
3061 dwError = RegSetValueExW(hServiceKey,
3062 L"Start",
3063 0,
3064 REG_DWORD,
3065 (LPBYTE)&dwStartType,
3066 sizeof(DWORD));
3067 if (dwError != ERROR_SUCCESS)
3068 goto done;
3069
3070 lpService->dwStartType = dwStartType;
3071 }
3072
3073 if (dwErrorControl != SERVICE_NO_CHANGE)
3074 {
3075 /* Set the error control value */
3076 dwError = RegSetValueExW(hServiceKey,
3077 L"ErrorControl",
3078 0,
3079 REG_DWORD,
3080 (LPBYTE)&dwErrorControl,
3081 sizeof(DWORD));
3082 if (dwError != ERROR_SUCCESS)
3083 goto done;
3084
3085 lpService->dwErrorControl = dwErrorControl;
3086 }
3087
3088 #if 0
3089 /* FIXME: set the new ImagePath value */
3090
3091 /* Set the image path */
3092 if (dwServiceType & SERVICE_WIN32)
3093 {
3094 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3095 {
3096 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3097 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
3098 dwError = RegSetValueExW(hServiceKey,
3099 L"ImagePath",
3100 0,
3101 REG_EXPAND_SZ,
3102 (LPBYTE)lpBinaryPathNameW,
3103 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3104 if (dwError != ERROR_SUCCESS)
3105 goto done;
3106 }
3107 }
3108 else if (dwServiceType & SERVICE_DRIVER)
3109 {
3110 if (lpImagePath != NULL && *lpImagePath != 0)
3111 {
3112 dwError = RegSetValueExW(hServiceKey,
3113 L"ImagePath",
3114 0,
3115 REG_EXPAND_SZ,
3116 (LPBYTE)lpImagePath,
3117 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3118 if (dwError != ERROR_SUCCESS)
3119 goto done;
3120 }
3121 }
3122 #endif
3123
3124 /* Set the group name */
3125 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3126 {
3127 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3128 0,
3129 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3130 if (lpLoadOrderGroupW == NULL)
3131 {
3132 dwError = ERROR_NOT_ENOUGH_MEMORY;
3133 goto done;
3134 }
3135
3136 MultiByteToWideChar(CP_ACP,
3137 0,
3138 lpLoadOrderGroup,
3139 -1,
3140 lpLoadOrderGroupW,
3141 strlen(lpLoadOrderGroup) + 1);
3142
3143 dwError = RegSetValueExW(hServiceKey,
3144 L"Group",
3145 0,
3146 REG_SZ,
3147 (LPBYTE)lpLoadOrderGroupW,
3148 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3149 if (dwError != ERROR_SUCCESS)
3150 {
3151 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3152 goto done;
3153 }
3154
3155 dwError = ScmSetServiceGroup(lpService,
3156 lpLoadOrderGroupW);
3157
3158 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3159
3160 if (dwError != ERROR_SUCCESS)
3161 goto done;
3162 }
3163
3164 if (lpdwTagId != NULL)
3165 {
3166 dwError = ScmAssignNewTag(lpService);
3167 if (dwError != ERROR_SUCCESS)
3168 goto done;
3169
3170 dwError = RegSetValueExW(hServiceKey,
3171 L"Tag",
3172 0,
3173 REG_DWORD,
3174 (LPBYTE)&lpService->dwTag,
3175 sizeof(DWORD));
3176 if (dwError != ERROR_SUCCESS)
3177 goto done;
3178
3179 *lpdwTagId = lpService->dwTag;
3180 }
3181
3182 /* Write dependencies */
3183 if (lpDependencies != NULL && *lpDependencies != 0)
3184 {
3185 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3186 0,
3187 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3188 if (lpDependenciesW == NULL)
3189 {
3190 dwError = ERROR_NOT_ENOUGH_MEMORY;
3191 goto done;
3192 }
3193
3194 MultiByteToWideChar(CP_ACP,
3195 0,
3196 lpDependencies,
3197 dwDependSize,
3198 lpDependenciesW,
3199 strlen(lpDependencies) + 1);
3200
3201 dwError = ScmWriteDependencies(hServiceKey,
3202 (LPWSTR)lpDependenciesW,
3203 dwDependSize);
3204
3205 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3206 }
3207
3208 if (lpPassword != NULL)
3209 {
3210 /* FIXME: Write password */
3211 }
3212
3213 /* FIXME: Unlock database */
3214
3215 done:
3216 if (hServiceKey != NULL)
3217 RegCloseKey(hServiceKey);
3218
3219 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3220
3221 return dwError;
3222 }
3223
3224
3225 /* Function 24 */
3226 DWORD RCreateServiceA(
3227 SC_RPC_HANDLE hSCManager,
3228 LPSTR lpServiceName,
3229 LPSTR lpDisplayName,
3230 DWORD dwDesiredAccess,
3231 DWORD dwServiceType,
3232 DWORD dwStartType,
3233 DWORD dwErrorControl,
3234 LPSTR lpBinaryPathName,
3235 LPSTR lpLoadOrderGroup,
3236 LPDWORD lpdwTagId,
3237 LPBYTE lpDependencies,
3238 DWORD dwDependSize,
3239 LPSTR lpServiceStartName,
3240 LPBYTE lpPassword,
3241 DWORD dwPwSize,
3242 LPSC_RPC_HANDLE lpServiceHandle)
3243 {
3244 UNIMPLEMENTED;
3245 return ERROR_CALL_NOT_IMPLEMENTED;
3246 }
3247
3248
3249 /* Function 25 */
3250 DWORD REnumDependentServicesA(
3251 SC_RPC_HANDLE hService,
3252 DWORD dwServiceState,
3253 LPBYTE lpServices,
3254 DWORD cbBufSize,
3255 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3256 LPBOUNDED_DWORD_256K lpServicesReturned)
3257 {
3258 DWORD dwError = ERROR_SUCCESS;
3259 DWORD dwServicesReturned = 0;
3260 DWORD dwServiceCount;
3261 HKEY hServicesKey = NULL;
3262 LPSC_RPC_HANDLE hSCObject;
3263 PSERVICE_HANDLE hSvc;
3264 PSERVICE lpService = NULL;
3265 PSERVICE *lpServicesArray = NULL;
3266 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3267 LPSTR lpStr;
3268
3269 *pcbBytesNeeded = 0;
3270 *lpServicesReturned = 0;
3271
3272 DPRINT("REnumDependentServicesA() called\n");
3273
3274 hSCObject = &hService;
3275 hSvc = (PSERVICE_HANDLE) *hSCObject;
3276 lpService = hSvc->ServiceEntry;
3277
3278 /* Check access rights */
3279 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3280 SC_MANAGER_ENUMERATE_SERVICE))
3281 {
3282 DPRINT1("Insufficient access rights! 0x%lx\n",
3283 hSvc->Handle.DesiredAccess);
3284 return ERROR_ACCESS_DENIED;
3285 }
3286
3287 /* Open the Services Reg key */
3288 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3289 L"System\\CurrentControlSet\\Services",
3290 0,
3291 KEY_READ,
3292 &hServicesKey);
3293
3294 if (dwError != ERROR_SUCCESS)
3295 return dwError;
3296
3297 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3298 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3299 are the same for both. Verified in WINXP. */
3300
3301 /* First determine the bytes needed and get the number of dependent services*/
3302 dwError = Int_EnumDependentServicesW(hServicesKey,
3303 lpService,
3304 dwServiceState,
3305 NULL,
3306 pcbBytesNeeded,
3307 &dwServicesReturned);
3308 if (dwError != ERROR_SUCCESS)
3309 goto Done;
3310
3311 /* If buffer size is less than the bytes needed or pointer is null*/
3312 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3313 {
3314 dwError = ERROR_MORE_DATA;
3315 goto Done;
3316 }
3317
3318 /* Allocate memory for array of service pointers */
3319 lpServicesArray = HeapAlloc(GetProcessHeap(),
3320 0,
3321 (dwServicesReturned + 1) * sizeof(PSERVICE));
3322 if (!lpServicesArray)
3323 {
3324 DPRINT1("Could not allocate a buffer!!\n");
3325 dwError = ERROR_NOT_ENOUGH_MEMORY;
3326 goto Done;
3327 }
3328
3329 dwServicesReturned = 0;
3330 *pcbBytesNeeded = 0;
3331
3332 dwError = Int_EnumDependentServicesW(hServicesKey,
3333 lpService,
3334 dwServiceState,
3335 lpServicesArray,
3336 pcbBytesNeeded,
3337 &dwServicesReturned);
3338 if (dwError != ERROR_SUCCESS)
3339 {
3340 goto Done;
3341 }
3342
3343 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3344 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3345
3346 /* Copy EnumDepenedentService to Buffer */
3347 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3348 {
3349 lpService = lpServicesArray[dwServiceCount];
3350
3351 /* Copy the status info */
3352 memcpy(&lpServicesPtr->ServiceStatus,
3353 &lpService->Status,
3354 sizeof(SERVICE_STATUS));
3355
3356 /* Copy display name */
3357 WideCharToMultiByte(CP_ACP,
3358 0,
3359 lpService->lpDisplayName,
3360 -1,
3361 lpStr,
3362 wcslen(lpService->lpDisplayName),
3363 0,
3364 0);
3365 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3366 lpStr += strlen(lpStr) + 1;
3367
3368 /* Copy service name */
3369 WideCharToMultiByte(CP_ACP,
3370 0,
3371 lpService->lpServiceName,
3372 -1,
3373 lpStr,
3374 wcslen(lpService->lpServiceName),
3375 0,
3376 0);
3377 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3378 lpStr += strlen(lpStr) + 1;
3379
3380 lpServicesPtr ++;
3381 }
3382
3383 *lpServicesReturned = dwServicesReturned;
3384
3385 Done:
3386 if (lpServicesArray)
3387 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3388
3389 RegCloseKey(hServicesKey);
3390
3391 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3392
3393 return dwError;
3394 }
3395
3396
3397 /* Function 26 */
3398 DWORD REnumServicesStatusA(
3399 SC_RPC_HANDLE hSCManager,
3400 DWORD dwServiceType,
3401 DWORD dwServiceState,
3402 LPBYTE lpBuffer,
3403 DWORD dwBufSize,
3404 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3405 LPBOUNDED_DWORD_256K lpServicesReturned,
3406 LPBOUNDED_DWORD_256K lpResumeHandle)
3407 {
3408 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3409 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3410 LPWSTR lpStringPtrW;
3411 LPSTR lpStringPtrA;
3412 DWORD dwError;
3413 DWORD dwServiceCount;
3414
3415 DPRINT("REnumServicesStatusA() called\n");
3416
3417 if ((dwBufSize > 0) && (lpBuffer))
3418 {
3419 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3420 if (!lpStatusPtrW)
3421 {
3422 DPRINT1("Failed to allocate buffer!\n");
3423 return ERROR_NOT_ENOUGH_MEMORY;
3424 }
3425 }
3426
3427 dwError = REnumServicesStatusW(hSCManager,
3428 dwServiceType,
3429 dwServiceState,
3430 (LPBYTE)lpStatusPtrW,
3431 dwBufSize,
3432 pcbBytesNeeded,
3433 lpServicesReturned,
3434 lpResumeHandle);
3435
3436 /* if no services were returned then we are Done */
3437 if (*lpServicesReturned == 0)
3438 goto Done;
3439
3440 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3441 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3442 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3443 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3444 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3445
3446 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3447 {
3448 /* Copy the service name */
3449 WideCharToMultiByte(CP_ACP,
3450 0,
3451 lpStringPtrW,
3452 -1,
3453 lpStringPtrA,
3454 wcslen(lpStringPtrW),
3455 0,
3456 0);
3457
3458 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3459 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3460 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3461
3462 /* Copy the display name */
3463 WideCharToMultiByte(CP_ACP,
3464 0,
3465 lpStringPtrW,
3466 -1,
3467 lpStringPtrA,
3468 wcslen(lpStringPtrW),
3469 0,
3470 0);
3471
3472 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3473 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3474 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3475
3476 /* Copy the status information */
3477 memcpy(&lpStatusPtrA->ServiceStatus,
3478 &lpStatusPtrW->ServiceStatus,
3479 sizeof(SERVICE_STATUS));
3480
3481 lpStatusPtrA++;
3482 }
3483
3484 Done:;
3485 if (lpStatusPtrW)
3486 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3487
3488 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3489
3490 return dwError;
3491 }
3492
3493
3494 /* Function 27 */
3495 DWORD ROpenSCManagerA(
3496 LPSTR lpMachineName,
3497 LPSTR lpDatabaseName,
3498 DWORD dwDesiredAccess,
3499 LPSC_RPC_HANDLE lpScHandle)
3500 {
3501 UNICODE_STRING MachineName;
3502 UNICODE_STRING DatabaseName;
3503 DWORD dwError;
3504
3505 DPRINT("ROpenSCManagerA() called\n");
3506
3507 if (lpMachineName)
3508 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3509 lpMachineName);
3510
3511 if (lpDatabaseName)
3512 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3513 lpDatabaseName);
3514
3515 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3516 lpDatabaseName ? DatabaseName.Buffer : NULL,
3517 dwDesiredAccess,
3518 lpScHandle);
3519
3520 if (lpMachineName)
3521 RtlFreeUnicodeString(&MachineName);
3522
3523 if (lpDatabaseName)
3524 RtlFreeUnicodeString(&DatabaseName);
3525
3526 return dwError;
3527 }
3528
3529
3530 /* Function 28 */
3531 DWORD ROpenServiceA(
3532 SC_RPC_HANDLE hSCManager,
3533 LPSTR lpServiceName,
3534 DWORD dwDesiredAccess,
3535 LPSC_RPC_HANDLE lpServiceHandle)
3536 {
3537 UNICODE_STRING ServiceName;
3538 DWORD dwError;
3539
3540 DPRINT("ROpenServiceA() called\n");
3541
3542 if (lpServiceName)
3543 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3544 lpServiceName);
3545
3546 dwError = ROpenServiceW(hSCManager,
3547 lpServiceName ? ServiceName.Buffer : NULL,
3548 dwDesiredAccess,
3549 lpServiceHandle);
3550
3551 if (lpServiceName)
3552 RtlFreeUnicodeString(&ServiceName);
3553
3554 return dwError;
3555 }
3556
3557
3558 /* Function 29 */
3559 DWORD RQueryServiceConfigA(
3560 SC_RPC_HANDLE hService,
3561 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3562 DWORD cbBufSize,
3563 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3564 {
3565 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3566 DWORD dwError = ERROR_SUCCESS;
3567 PSERVICE_HANDLE hSvc;
3568 PSERVICE lpService = NULL;
3569 HKEY hServiceKey = NULL;
3570 LPWSTR lpImagePath = NULL;
3571 LPWSTR lpServiceStartName = NULL;
3572 LPWSTR lpDependencies = NULL;
3573 DWORD dwDependenciesLength = 0;
3574 DWORD dwRequiredSize;
3575 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3576 CHAR lpEmptyString[]={0,0};
3577 LPSTR lpStr;
3578
3579 DPRINT("RQueryServiceConfigA() called\n");
3580
3581 if (ScmShutdown)
3582 return ERROR_SHUTDOWN_IN_PROGRESS;
3583
3584 hSvc = (PSERVICE_HANDLE)hService;
3585 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3586 {
3587 DPRINT1("Invalid handle tag!\n");
3588 return ERROR_INVALID_HANDLE;
3589 }
3590
3591 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3592 SERVICE_QUERY_CONFIG))
3593 {
3594 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3595 return ERROR_ACCESS_DENIED;
3596 }
3597
3598 lpService = hSvc->ServiceEntry;
3599 if (lpService == NULL)
3600 {
3601 DPRINT1("lpService == NULL!\n");
3602 return ERROR_INVALID_HANDLE;
3603 }
3604
3605 /* FIXME: Lock the service database shared */
3606
3607 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3608 KEY_READ,
3609 &hServiceKey);
3610 if (dwError != ERROR_SUCCESS)
3611 goto Done;
3612
3613 /* Read the image path */
3614 dwError = ScmReadString(hServiceKey,
3615 L"ImagePath",
3616 &lpImagePath);
3617 if (dwError != ERROR_SUCCESS)
3618 goto Done;
3619
3620 /* Read the service start name */
3621 ScmReadString(hServiceKey,
3622 L"ObjectName",
3623 &lpServiceStartName);
3624
3625 /* Read the dependencies */
3626 ScmReadDependencies(hServiceKey,
3627 &lpDependencies,
3628 &dwDependenciesLength);
3629
3630 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3631
3632 if (lpImagePath != NULL)
3633 dwRequiredSize += wcslen(lpImagePath) + 1;
3634 else
3635 dwRequiredSize += 2;
3636
3637 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3638 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
3639 else
3640 dwRequiredSize += 2;
3641
3642 /* Add Dependencies length */
3643 if (lpDependencies != NULL)
3644 dwRequiredSize += dwDependenciesLength;
3645 else
3646 dwRequiredSize += 2;
3647
3648 if (lpServiceStartName != NULL)
3649 dwRequiredSize += wcslen(lpServiceStartName) + 1;
3650 else
3651 dwRequiredSize += 2;
3652
3653 if (lpService->lpDisplayName != NULL)
3654 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
3655 else
3656 dwRequiredSize += 2;
3657
3658 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3659 {
3660 dwError = ERROR_INSUFFICIENT_BUFFER;
3661 }
3662 else
3663 {
3664 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
3665 lpConfig->dwServiceType = lpService->Status.dwServiceType;
3666 lpConfig->dwStartType = lpService->dwStartType;
3667 lpConfig->dwErrorControl = lpService->dwErrorControl;
3668 lpConfig->dwTagId = lpService->dwTag;
3669
3670 lpStr = (LPSTR)(lpServiceConfig + 1);
3671
3672 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3673 Verified in WINXP*/
3674
3675 if (lpImagePath)
3676 {
3677 WideCharToMultiByte(CP_ACP,
3678 0,
3679 lpImagePath,
3680 -1,
3681 lpStr,
3682 wcslen(lpImagePath) + 1,
3683 0,
3684 0);
3685 }
3686 else
3687 {
3688 strcpy(lpStr, lpEmptyString);
3689 }
3690
3691 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3692 lpStr += (strlen((LPSTR)lpStr) + 1);
3693
3694 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
3695 {
3696 WideCharToMultiByte(CP_ACP,
3697 0,
3698 lpService->lpGroup->lpGroupName,
3699 -1,
3700 lpStr,
3701 wcslen(lpService->lpGroup->lpGroupName) + 1,
3702 0,
3703 0);
3704 }
3705 else
3706 {
3707 strcpy(lpStr, lpEmptyString);
3708 }
3709
3710 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3711 lpStr += (strlen(lpStr) + 1);
3712
3713 /* Append Dependencies */
3714 if (lpDependencies)
3715 {
3716 WideCharToMultiByte(CP_ACP,
3717 0,
3718 lpDependencies,
3719 dwDependenciesLength,
3720 lpStr,
3721 dwDependenciesLength,
3722 0,
3723 0);
3724 }
3725 else
3726 {
3727 strcpy(lpStr, lpEmptyString);
3728 }
3729
3730 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3731 if (lpDependencies)
3732 lpStr += dwDependenciesLength;
3733 else
3734 lpStr += (strlen(lpStr) + 1);
3735
3736 if (lpServiceStartName)
3737 {
3738 WideCharToMultiByte(CP_ACP,
3739 0,
3740 lpServiceStartName,
3741 -1,
3742 lpStr,
3743 wcslen(lpServiceStartName) + 1,
3744 0,
3745 0);
3746 }
3747 else
3748 {
3749 strcpy(lpStr, lpEmptyString);
3750 }
3751
3752 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3753 lpStr += (strlen(lpStr) + 1);
3754
3755 if (lpService->lpDisplayName)
3756 {
3757 WideCharToMultiByte(CP_ACP,
3758 0,
3759 lpService->lpDisplayName,
3760 -1,
3761 lpStr,
3762 wcslen(lpService->lpDisplayName) + 1,
3763 0,
3764 0);
3765 }
3766 else
3767 {
3768 strcpy(lpStr, lpEmptyString);
3769 }
3770
3771 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3772 }
3773
3774 if (pcbBytesNeeded != NULL)
3775 *pcbBytesNeeded = dwRequiredSize;
3776
3777 Done:;
3778 if (lpImagePath != NULL)
3779 HeapFree(GetProcessHeap(), 0, lpImagePath);
3780
3781 if (lpServiceStartName != NULL)
3782 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3783
3784 if (lpDependencies != NULL)