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