- RChangeServiceConfigA/W: Update the service group properly and fix the ANSI to...
[reactos.git] / reactos / base / system / services / rpcserver.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include "services.h"
14 #include "svcctl_s.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS *****************************************************************/
20
21 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
22 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
23
24 typedef struct _SCMGR_HANDLE
25 {
26 DWORD Tag;
27 DWORD RefCount;
28 DWORD DesiredAccess;
29 } SCMGR_HANDLE;
30
31
32 typedef struct _MANAGER_HANDLE
33 {
34 SCMGR_HANDLE Handle;
35
36 /* FIXME: Insert more data here */
37
38 WCHAR DatabaseName[1];
39 } MANAGER_HANDLE, *PMANAGER_HANDLE;
40
41
42 typedef struct _SERVICE_HANDLE
43 {
44 SCMGR_HANDLE Handle;
45
46 DWORD DesiredAccess;
47 PSERVICE ServiceEntry;
48
49 /* FIXME: Insert more data here */
50
51 } SERVICE_HANDLE, *PSERVICE_HANDLE;
52
53
54 #define SC_MANAGER_READ \
55 (STANDARD_RIGHTS_READ | \
56 SC_MANAGER_QUERY_LOCK_STATUS | \
57 SC_MANAGER_ENUMERATE_SERVICE)
58
59 #define SC_MANAGER_WRITE \
60 (STANDARD_RIGHTS_WRITE | \
61 SC_MANAGER_MODIFY_BOOT_CONFIG | \
62 SC_MANAGER_CREATE_SERVICE)
63
64 #define SC_MANAGER_EXECUTE \
65 (STANDARD_RIGHTS_EXECUTE | \
66 SC_MANAGER_LOCK | \
67 SC_MANAGER_ENUMERATE_SERVICE | \
68 SC_MANAGER_CONNECT | \
69 SC_MANAGER_CREATE_SERVICE)
70
71
72 #define SERVICE_READ \
73 (STANDARD_RIGHTS_READ | \
74 SERVICE_INTERROGATE | \
75 SERVICE_ENUMERATE_DEPENDENTS | \
76 SERVICE_QUERY_STATUS | \
77 SERVICE_QUERY_CONFIG)
78
79 #define SERVICE_WRITE \
80 (STANDARD_RIGHTS_WRITE | \
81 SERVICE_CHANGE_CONFIG)
82
83 #define SERVICE_EXECUTE \
84 (STANDARD_RIGHTS_EXECUTE | \
85 SERVICE_USER_DEFINED_CONTROL | \
86 SERVICE_PAUSE_CONTINUE | \
87 SERVICE_STOP | \
88 SERVICE_START)
89
90
91 /* VARIABLES ***************************************************************/
92
93 static GENERIC_MAPPING
94 ScmManagerMapping = {SC_MANAGER_READ,
95 SC_MANAGER_WRITE,
96 SC_MANAGER_EXECUTE,
97 SC_MANAGER_ALL_ACCESS};
98
99 static GENERIC_MAPPING
100 ScmServiceMapping = {SERVICE_READ,
101 SERVICE_WRITE,
102 SERVICE_EXECUTE,
103 SC_MANAGER_ALL_ACCESS};
104
105
106 /* FUNCTIONS ***************************************************************/
107
108 VOID
109 ScmStartRpcServer(VOID)
110 {
111 RPC_STATUS Status;
112
113 DPRINT("ScmStartRpcServer() called\n");
114
115 Status = RpcServerUseProtseqEpW(L"ncacn_np",
116 10,
117 L"\\pipe\\ntsvcs",
118 NULL);
119 if (Status != RPC_S_OK)
120 {
121 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
122 return;
123 }
124
125 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
126 NULL,
127 NULL);
128 if (Status != RPC_S_OK)
129 {
130 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
131 return;
132 }
133
134 Status = RpcServerListen(1, 20, TRUE);
135 if (Status != RPC_S_OK)
136 {
137 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
138 return;
139 }
140
141 DPRINT("ScmStartRpcServer() done\n");
142 }
143
144
145 static DWORD
146 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
147 SC_HANDLE *Handle)
148 {
149 PMANAGER_HANDLE Ptr;
150
151 if (lpDatabaseName == NULL)
152 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
153
154 if (_wcsicmp(lpDatabaseName,SERVICES_FAILED_DATABASEW)==0)
155 {
156 DPRINT1("Database %S, does not exist\n",lpDatabaseName);
157 return ERROR_DATABASE_DOES_NOT_EXIST;
158 }
159 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
160 {
161 DPRINT1("Invalid Database name %S.\n",lpDatabaseName);
162 return ERROR_INVALID_NAME;
163 }
164
165 Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
166 HEAP_ZERO_MEMORY,
167 sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
168 if (Ptr == NULL)
169 return ERROR_NOT_ENOUGH_MEMORY;
170
171 Ptr->Handle.Tag = MANAGER_TAG;
172 Ptr->Handle.RefCount = 1;
173
174 /* FIXME: initialize more data here */
175
176 wcscpy(Ptr->DatabaseName, lpDatabaseName);
177
178 *Handle = (SC_HANDLE)Ptr;
179
180 return ERROR_SUCCESS;
181 }
182
183
184 static DWORD
185 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
186 SC_HANDLE *Handle)
187 {
188 PSERVICE_HANDLE Ptr;
189
190 Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
191 HEAP_ZERO_MEMORY,
192 sizeof(SERVICE_HANDLE));
193 if (Ptr == NULL)
194 return ERROR_NOT_ENOUGH_MEMORY;
195
196 Ptr->Handle.Tag = SERVICE_TAG;
197 Ptr->Handle.RefCount = 1;
198
199 /* FIXME: initialize more data here */
200 Ptr->ServiceEntry = lpServiceEntry;
201
202 *Handle = (SC_HANDLE)Ptr;
203
204 return ERROR_SUCCESS;
205 }
206
207
208 static DWORD
209 ScmCheckAccess(SC_HANDLE Handle,
210 DWORD dwDesiredAccess)
211 {
212 PMANAGER_HANDLE hMgr;
213
214 hMgr = (PMANAGER_HANDLE)Handle;
215 if (hMgr->Handle.Tag == MANAGER_TAG)
216 {
217 RtlMapGenericMask(&dwDesiredAccess,
218 &ScmManagerMapping);
219
220 hMgr->Handle.DesiredAccess = dwDesiredAccess;
221
222 return ERROR_SUCCESS;
223 }
224 else if (hMgr->Handle.Tag == SERVICE_TAG)
225 {
226 RtlMapGenericMask(&dwDesiredAccess,
227 &ScmServiceMapping);
228
229 hMgr->Handle.DesiredAccess = dwDesiredAccess;
230
231 return ERROR_SUCCESS;
232 }
233
234 return ERROR_INVALID_HANDLE;
235 }
236
237
238 DWORD
239 ScmAssignNewTag(PSERVICE lpService)
240 {
241 /* FIXME */
242 DPRINT("Assigning new tag to service %S\n", lpService->lpServiceName);
243 lpService->dwTag = 0;
244 return ERROR_SUCCESS;
245 }
246
247
248 /* Internal recursive function */
249 /* Need to search for every dependency on every service */
250 static DWORD
251 Int_EnumDependentServicesW(HKEY hServicesKey,
252 PSERVICE lpService,
253 DWORD dwServiceState,
254 PSERVICE *lpServices,
255 LPDWORD pcbBytesNeeded,
256 LPDWORD lpServicesReturned)
257 {
258 DWORD dwError = ERROR_SUCCESS;
259 WCHAR szNameBuf[MAX_PATH];
260 WCHAR szValueBuf[MAX_PATH];
261 WCHAR *lpszNameBuf = szNameBuf;
262 WCHAR *lpszValueBuf = szValueBuf;
263 DWORD dwSize;
264 DWORD dwNumSubKeys;
265 DWORD dwIteration;
266 PSERVICE lpCurrentService;
267 HKEY hServiceEnumKey;
268 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
269 DWORD dwDependServiceStrPtr = 0;
270 DWORD dwRequiredSize = 0;
271
272 /* Get the number of service keys */
273 dwError = RegQueryInfoKeyW(hServicesKey,
274 NULL,
275 NULL,
276 NULL,
277 &dwNumSubKeys,
278 NULL,
279 NULL,
280 NULL,
281 NULL,
282 NULL,
283 NULL,
284 NULL);
285 if (dwError != ERROR_SUCCESS)
286 {
287 DPRINT1("ERROR! Unable to get number of services keys.\n");
288 return dwError;
289 }
290
291 /* Iterate the service keys to see if another service depends on the this service */
292 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
293 {
294 dwSize = MAX_PATH;
295 dwError = RegEnumKeyExW(hServicesKey,
296 dwIteration,
297 lpszNameBuf,
298 &dwSize,
299 NULL,
300 NULL,
301 NULL,
302 NULL);
303 if (dwError != ERROR_SUCCESS)
304 return dwError;
305
306 /* Open the Service key */
307 dwError = RegOpenKeyExW(hServicesKey,
308 lpszNameBuf,
309 0,
310 KEY_READ,
311 &hServiceEnumKey);
312 if (dwError != ERROR_SUCCESS)
313 return dwError;
314
315 dwSize = MAX_PATH;
316
317 /* Check for the DependOnService Value */
318 dwError = RegQueryValueExW(hServiceEnumKey,
319 L"DependOnService",
320 NULL,
321 NULL,
322 (LPBYTE)lpszValueBuf,
323 &dwSize);
324
325 /* FIXME: Handle load order. */
326
327 /* If the service found has a DependOnService value */
328 if (dwError == ERROR_SUCCESS)
329 {
330 dwDependServiceStrPtr = 0;
331
332 /* Can be more than one Dependencies in the DependOnService string */
333 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
334 {
335 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
336 {
337 /* Get the current enumed service pointer */
338 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
339
340 /* Check for valid Service */
341 if (!lpCurrentService)
342 {
343 /* This should never happen! */
344 DPRINT1("This should not happen at this point, report to Developer\n");
345 return ERROR_NOT_FOUND;
346 }
347
348 /* Determine state the service is in */
349 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
350 dwCurrentServiceState = SERVICE_INACTIVE;
351
352 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
353 if ((dwCurrentServiceState == dwServiceState) ||
354 (dwServiceState == SERVICE_STATE_ALL))
355 {
356 /* Calculate the required size */
357 dwRequiredSize += sizeof(SERVICE_STATUS);
358 dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
359 dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
360
361 /* Add the size for service name and display name pointers */
362 dwRequiredSize += (2 * sizeof(PVOID));
363
364 /* increase the BytesNeeded size */
365 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
366
367 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
368 comes first */
369
370 /* Recursive call to check for its dependencies */
371 Int_EnumDependentServicesW(hServicesKey,
372 lpCurrentService,
373 dwServiceState,
374 lpServices,
375 pcbBytesNeeded,
376 lpServicesReturned);
377
378 /* If the lpServices is valid set the service pointer */
379 if (lpServices)
380 lpServices[*lpServicesReturned] = lpCurrentService;
381
382 *lpServicesReturned = *lpServicesReturned + 1;
383 }
384 }
385
386 dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
387 }
388 }
389 else if (*pcbBytesNeeded)
390 {
391 dwError = ERROR_SUCCESS;
392 }
393
394 RegCloseKey(hServiceEnumKey);
395 }
396
397 return dwError;
398 }
399
400
401 /* Function 0 */
402 DWORD RCloseServiceHandle(
403 LPSC_RPC_HANDLE hSCObject)
404 {
405 PMANAGER_HANDLE hManager;
406 PSERVICE_HANDLE hService;
407 PSERVICE lpService;
408 HKEY hServicesKey;
409 DWORD dwError;
410 DWORD pcbBytesNeeded = 0;
411 DWORD dwServicesReturned = 0;
412
413 DPRINT("RCloseServiceHandle() called\n");
414
415 DPRINT("hSCObject = %p\n", *hSCObject);
416
417 if (*hSCObject == 0)
418 return ERROR_INVALID_HANDLE;
419
420 hManager = (PMANAGER_HANDLE)*hSCObject;
421 hService = (PSERVICE_HANDLE)*hSCObject;
422 if (hManager->Handle.Tag == MANAGER_TAG)
423 {
424 DPRINT("Found manager handle\n");
425
426 hManager->Handle.RefCount--;
427 if (hManager->Handle.RefCount == 0)
428 {
429 /* FIXME: add handle cleanup code */
430
431 HeapFree(GetProcessHeap(), 0, hManager);
432 hManager = NULL;
433 }
434
435 DPRINT("RCloseServiceHandle() done\n");
436 return ERROR_SUCCESS;
437 }
438 else if (hService->Handle.Tag == SERVICE_TAG)
439 {
440 DPRINT("Found service handle\n");
441
442 /* Get the pointer to the service record */
443 lpService = hService->ServiceEntry;
444
445 ASSERT(hService->Handle.RefCount > 0);
446
447 hService->Handle.RefCount--;
448 if (hService->Handle.RefCount == 0)
449 {
450 /* FIXME: add handle cleanup code */
451
452 /* Free the handle */
453 HeapFree(GetProcessHeap(), 0, hService);
454 hService = NULL;
455 }
456
457 ASSERT(lpService->dwRefCount > 0);
458
459 lpService->dwRefCount--;
460 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
461 lpService->dwRefCount);
462
463 if (lpService->dwRefCount == 0)
464 {
465 /* If this service has been marked for deletion */
466 if (lpService->bDeleted)
467 {
468 /* Open the Services Reg key */
469 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
470 L"System\\CurrentControlSet\\Services",
471 0,
472 KEY_SET_VALUE | KEY_READ,
473 &hServicesKey);
474 if (dwError != ERROR_SUCCESS)
475 {
476 DPRINT1("Failed to open services key\n");
477 return dwError;
478 }
479
480 /* Call the internal function with NULL, just to get bytes we need */
481 Int_EnumDependentServicesW(hServicesKey,
482 lpService,
483 SERVICE_ACTIVE,
484 NULL,
485 &pcbBytesNeeded,
486 &dwServicesReturned);
487
488 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
489 if (pcbBytesNeeded)
490 {
491 DPRINT1("Deletion failed due to running dependencies.\n");
492 RegCloseKey(hServicesKey);
493 return ERROR_SUCCESS;
494 }
495
496 /* There are no references and no runnning dependencies,
497 it is now safe to delete the service */
498
499 /* Delete the Service Key */
500 dwError = RegDeleteKeyW(hServicesKey,
501 lpService->lpServiceName);
502
503 RegCloseKey(hServicesKey);
504
505 if (dwError != ERROR_SUCCESS)
506 {
507 DPRINT1("Failed to Delete the Service Registry key\n");
508 return dwError;
509 }
510
511 /* Delete the Service */
512 ScmDeleteServiceRecord(lpService);
513 }
514 }
515
516 DPRINT("RCloseServiceHandle() done\n");
517 return ERROR_SUCCESS;
518 }
519
520 DPRINT1("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
521
522 return ERROR_INVALID_HANDLE;
523 }
524
525
526 /* Function 1 */
527 DWORD RControlService(
528 SC_RPC_HANDLE hService,
529 DWORD dwControl,
530 LPSERVICE_STATUS lpServiceStatus)
531 {
532 PSERVICE_HANDLE hSvc;
533 PSERVICE lpService;
534 ACCESS_MASK DesiredAccess;
535 DWORD dwError = ERROR_SUCCESS;
536 DWORD pcbBytesNeeded = 0;
537 DWORD dwServicesReturned = 0;
538 HKEY hServicesKey = NULL;
539
540 DPRINT("RControlService() called\n");
541
542 if (ScmShutdown)
543 return ERROR_SHUTDOWN_IN_PROGRESS;
544
545 /* Check the service handle */
546 hSvc = (PSERVICE_HANDLE)hService;
547 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
548 {
549 DPRINT1("Invalid handle tag!\n");
550 return ERROR_INVALID_HANDLE;
551 }
552
553 /* Check the service entry point */
554 lpService = hSvc->ServiceEntry;
555 if (lpService == NULL)
556 {
557 DPRINT1("lpService == NULL!\n");
558 return ERROR_INVALID_HANDLE;
559 }
560
561 /* Check access rights */
562 switch (dwControl)
563 {
564 case SERVICE_CONTROL_STOP:
565 DesiredAccess = SERVICE_STOP;
566 break;
567
568 case SERVICE_CONTROL_PAUSE:
569 case SERVICE_CONTROL_CONTINUE:
570 DesiredAccess = SERVICE_PAUSE_CONTINUE;
571 break;
572
573 case SERVICE_INTERROGATE:
574 DesiredAccess = SERVICE_INTERROGATE;
575 break;
576
577 default:
578 if (dwControl >= 128 && dwControl <= 255)
579 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
580 else
581 DesiredAccess = SERVICE_QUERY_CONFIG |
582 SERVICE_CHANGE_CONFIG |
583 SERVICE_QUERY_STATUS |
584 SERVICE_START |
585 SERVICE_PAUSE_CONTINUE;
586 break;
587 }
588
589 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
590 DesiredAccess))
591 return ERROR_ACCESS_DENIED;
592
593 if (dwControl == SERVICE_CONTROL_STOP)
594 {
595 /* Check if the service has dependencies running as windows
596 doesn't stop a service that does */
597
598 /* Open the Services Reg key */
599 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
600 L"System\\CurrentControlSet\\Services",
601 0,
602 KEY_READ,
603 &hServicesKey);
604 if (dwError != ERROR_SUCCESS)
605 {
606 DPRINT1("Failed to open services key\n");
607 return dwError;
608 }
609
610 /* Call the internal function with NULL, just to get bytes we need */
611 Int_EnumDependentServicesW(hServicesKey,
612 lpService,
613 SERVICE_ACTIVE,
614 NULL,
615 &pcbBytesNeeded,
616 &dwServicesReturned);
617
618 RegCloseKey(hServicesKey);
619
620 /* If pcbBytesNeeded is not zero then there are services running that
621 are dependent on this service */
622 if (pcbBytesNeeded != 0)
623 {
624 DPRINT("Service has running dependencies. Failed to stop service.\n");
625 return ERROR_DEPENDENT_SERVICES_RUNNING;
626 }
627 }
628
629 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
630 {
631 /* Send control code to the driver */
632 dwError = ScmControlDriver(lpService,
633 dwControl,
634 lpServiceStatus);
635 }
636 else
637 {
638 /* Send control code to the service */
639 dwError = ScmControlService(lpService,
640 dwControl,
641 lpServiceStatus);
642 }
643
644 if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
645 dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
646
647 /* Return service status information */
648 RtlCopyMemory(lpServiceStatus,
649 &lpService->Status,
650 sizeof(SERVICE_STATUS));
651
652 return dwError;
653 }
654
655
656 /* Function 2 */
657 DWORD RDeleteService(
658 SC_RPC_HANDLE hService)
659 {
660 PSERVICE_HANDLE hSvc;
661 PSERVICE lpService;
662 DWORD dwError;
663
664 DPRINT("RDeleteService() called\n");
665
666 if (ScmShutdown)
667 return ERROR_SHUTDOWN_IN_PROGRESS;
668
669 hSvc = (PSERVICE_HANDLE)hService;
670 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
671 return ERROR_INVALID_HANDLE;
672
673 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
674 DELETE))
675 return ERROR_ACCESS_DENIED;
676
677 lpService = hSvc->ServiceEntry;
678 if (lpService == NULL)
679 {
680 DPRINT1("lpService == NULL!\n");
681 return ERROR_INVALID_HANDLE;
682 }
683
684 /* FIXME: Acquire service database lock exclusively */
685
686 if (lpService->bDeleted)
687 {
688 DPRINT1("The service has already been marked for delete!\n");
689 return ERROR_SERVICE_MARKED_FOR_DELETE;
690 }
691
692 /* Mark service for delete */
693 lpService->bDeleted = TRUE;
694
695 dwError = ScmMarkServiceForDelete(lpService);
696
697 /* FIXME: Release service database lock */
698
699 DPRINT("RDeleteService() done\n");
700
701 return dwError;
702 }
703
704
705 /* Function 3 */
706 DWORD RLockServiceDatabase(
707 SC_RPC_HANDLE hSCManager,
708 LPSC_RPC_LOCK lpLock)
709 {
710 PMANAGER_HANDLE hMgr;
711
712 DPRINT("RLockServiceDatabase() called\n");
713
714 *lpLock = 0;
715
716 hMgr = (PMANAGER_HANDLE)hSCManager;
717 if (!hMgr || hMgr->Handle.Tag != MANAGER_TAG)
718 return ERROR_INVALID_HANDLE;
719
720 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
721 SC_MANAGER_LOCK))
722 return ERROR_ACCESS_DENIED;
723
724 // return ScmLockDatabase(0, hMgr->0xC, hLock);
725
726 /* FIXME: Lock the database */
727 *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
728
729 return ERROR_SUCCESS;
730 }
731
732
733 /* Function 4 */
734 DWORD RQueryServiceObjectSecurity(
735 SC_RPC_HANDLE hService,
736 SECURITY_INFORMATION dwSecurityInformation,
737 LPBYTE lpSecurityDescriptor,
738 DWORD cbBufSize,
739 LPBOUNDED_DWORD_256K pcbBytesNeeded)
740 {
741 PSERVICE_HANDLE hSvc;
742 PSERVICE lpService;
743 ULONG DesiredAccess = 0;
744 NTSTATUS Status;
745 DWORD dwBytesNeeded;
746 DWORD dwError;
747
748
749 SECURITY_DESCRIPTOR ObjectDescriptor;
750
751 DPRINT("RQueryServiceObjectSecurity() called\n");
752
753 hSvc = (PSERVICE_HANDLE)hService;
754 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
755 {
756 DPRINT1("Invalid handle tag!\n");
757 return ERROR_INVALID_HANDLE;
758 }
759
760 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION ||
761 GROUP_SECURITY_INFORMATION ||
762 OWNER_SECURITY_INFORMATION))
763 DesiredAccess |= READ_CONTROL;
764
765 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
766 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
767
768 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
769 DesiredAccess))
770 {
771 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
772 return ERROR_ACCESS_DENIED;
773 }
774
775 lpService = hSvc->ServiceEntry;
776 if (lpService == NULL)
777 {
778 DPRINT1("lpService == NULL!\n");
779 return ERROR_INVALID_HANDLE;
780 }
781
782 /* FIXME: Lock the service list */
783
784 /* hack */
785 Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
786
787 Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
788 dwSecurityInformation,
789 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
790 cbBufSize,
791 &dwBytesNeeded);
792
793 /* FIXME: Unlock the service list */
794
795 if (NT_SUCCESS(Status))
796 {
797 *pcbBytesNeeded = dwBytesNeeded;
798 dwError = STATUS_SUCCESS;
799 }
800 else if (Status == STATUS_BUFFER_TOO_SMALL)
801 {
802 *pcbBytesNeeded = dwBytesNeeded;
803 dwError = ERROR_INSUFFICIENT_BUFFER;
804 }
805 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
806 {
807 dwError = ERROR_GEN_FAILURE;
808 }
809 else
810 {
811 dwError = RtlNtStatusToDosError(Status);
812 }
813
814 return dwError;
815 }
816
817
818 /* Function 5 */
819 DWORD RSetServiceObjectSecurity(
820 SC_RPC_HANDLE hService,
821 DWORD dwSecurityInformation,
822 LPBYTE lpSecurityDescriptor,
823 DWORD dwSecuityDescriptorSize)
824 {
825 PSERVICE_HANDLE hSvc;
826 PSERVICE lpService;
827 ULONG DesiredAccess = 0;
828 /* HANDLE hToken = NULL; */
829 HKEY hServiceKey;
830 /* NTSTATUS Status; */
831 DWORD dwError;
832
833 DPRINT1("RSetServiceObjectSecurity() called\n");
834
835 hSvc = (PSERVICE_HANDLE)hService;
836 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
837 {
838 DPRINT1("Invalid handle tag!\n");
839 return ERROR_INVALID_HANDLE;
840 }
841
842 if (dwSecurityInformation == 0 ||
843 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
844 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
845 return ERROR_INVALID_PARAMETER;
846
847 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
848 return ERROR_INVALID_PARAMETER;
849
850 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
851 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
852
853 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
854 DesiredAccess |= WRITE_DAC;
855
856 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
857 DesiredAccess |= WRITE_OWNER;
858
859 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
860 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
861 return ERROR_INVALID_PARAMETER;
862
863 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
864 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
865 return ERROR_INVALID_PARAMETER;
866
867 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
868 DesiredAccess))
869 {
870 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
871 return ERROR_ACCESS_DENIED;
872 }
873
874 lpService = hSvc->ServiceEntry;
875 if (lpService == NULL)
876 {
877 DPRINT1("lpService == NULL!\n");
878 return ERROR_INVALID_HANDLE;
879 }
880
881 if (lpService->bDeleted)
882 return ERROR_SERVICE_MARKED_FOR_DELETE;
883
884 #if 0
885 RpcImpersonateClient(NULL);
886
887 Status = NtOpenThreadToken(NtCurrentThread(),
888 8,
889 TRUE,
890 &hToken);
891 if (!NT_SUCCESS(Status))
892 return RtlNtStatusToDosError(Status);
893
894 RpcRevertToSelf();
895
896 /* FIXME: Lock service database */
897
898 Status = RtlSetSecurityObject(dwSecurityInformation,
899 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
900 &lpService->lpSecurityDescriptor,
901 &ScmServiceMapping,
902 hToken);
903 if (!NT_SUCCESS(Status))
904 {
905 dwError = RtlNtStatusToDosError(Status);
906 goto Done;
907 }
908 #endif
909
910 dwError = ScmOpenServiceKey(lpService->lpServiceName,
911 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
912 &hServiceKey);
913 if (dwError != ERROR_SUCCESS)
914 goto Done;
915
916 UNIMPLEMENTED;
917 dwError = ERROR_SUCCESS;
918 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
919 // lpService->lpSecurityDescriptor);
920
921 RegFlushKey(hServiceKey);
922 RegCloseKey(hServiceKey);
923
924 Done:
925
926 #if 0
927 if (hToken != NULL)
928 NtClose(hToken);
929 #endif
930
931 /* FIXME: Unlock service database */
932
933 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
934
935 return dwError;
936 }
937
938
939 /* Function 6 */
940 DWORD RQueryServiceStatus(
941 SC_RPC_HANDLE hService,
942 LPSERVICE_STATUS lpServiceStatus)
943 {
944 PSERVICE_HANDLE hSvc;
945 PSERVICE lpService;
946
947 DPRINT("RQueryServiceStatus() called\n");
948
949 if (ScmShutdown)
950 return ERROR_SHUTDOWN_IN_PROGRESS;
951
952 hSvc = (PSERVICE_HANDLE)hService;
953 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
954 {
955 DPRINT1("Invalid handle tag!\n");
956 return ERROR_INVALID_HANDLE;
957 }
958
959 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
960 SERVICE_QUERY_STATUS))
961 {
962 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
963 return ERROR_ACCESS_DENIED;
964 }
965
966 lpService = hSvc->ServiceEntry;
967 if (lpService == NULL)
968 {
969 DPRINT1("lpService == NULL!\n");
970 return ERROR_INVALID_HANDLE;
971 }
972
973 /* Return service status information */
974 RtlCopyMemory(lpServiceStatus,
975 &lpService->Status,
976 sizeof(SERVICE_STATUS));
977
978 return ERROR_SUCCESS;
979 }
980
981
982 static BOOL
983 ScmIsValidServiceState(DWORD dwCurrentState)
984 {
985 switch (dwCurrentState)
986 {
987 case SERVICE_STOPPED:
988 case SERVICE_START_PENDING:
989 case SERVICE_STOP_PENDING:
990 case SERVICE_RUNNING:
991 case SERVICE_CONTINUE_PENDING:
992 case SERVICE_PAUSE_PENDING:
993 case SERVICE_PAUSED:
994 return TRUE;
995
996 default:
997 return FALSE;
998 }
999 }
1000
1001
1002 /* Function 7 */
1003 DWORD RSetServiceStatus(
1004 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1005 LPSERVICE_STATUS lpServiceStatus)
1006 {
1007 PSERVICE lpService;
1008
1009 DPRINT("RSetServiceStatus() called\n");
1010 DPRINT("hServiceStatus = %p\n", hServiceStatus);
1011 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1012 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1013 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1014 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1015 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1016 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1017 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1018
1019 if (hServiceStatus == 0)
1020 {
1021 DPRINT1("hServiceStatus == NULL!\n");
1022 return ERROR_INVALID_HANDLE;
1023 }
1024
1025 lpService = ScmGetServiceEntryByClientHandle((HANDLE)hServiceStatus);
1026 if (lpService == NULL)
1027 {
1028 DPRINT1("lpService == NULL!\n");
1029 return ERROR_INVALID_HANDLE;
1030 }
1031
1032 /* Check current state */
1033 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1034 {
1035 DPRINT1("Invalid service state!\n");
1036 return ERROR_INVALID_DATA;
1037 }
1038
1039 /* Check service type */
1040 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1041 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1042 {
1043 DPRINT1("Invalid service type!\n");
1044 return ERROR_INVALID_DATA;
1045 }
1046
1047 /* Check accepted controls */
1048 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1049 {
1050 DPRINT1("Invalid controls accepted!\n");
1051 return ERROR_INVALID_DATA;
1052 }
1053
1054
1055 RtlCopyMemory(&lpService->Status,
1056 lpServiceStatus,
1057 sizeof(SERVICE_STATUS));
1058
1059 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1060 DPRINT("RSetServiceStatus() done\n");
1061
1062 return ERROR_SUCCESS;
1063 }
1064
1065
1066 /* Function 8 */
1067 DWORD RUnlockServiceDatabase(
1068 LPSC_RPC_LOCK Lock)
1069 {
1070 UNIMPLEMENTED;
1071 return ERROR_SUCCESS;
1072 }
1073
1074
1075 /* Function 9 */
1076 DWORD RNotifyBootConfigStatus(
1077 SVCCTL_HANDLEW lpMachineName,
1078 DWORD BootAcceptable)
1079 {
1080 UNIMPLEMENTED;
1081 return ERROR_CALL_NOT_IMPLEMENTED;
1082 }
1083
1084
1085 /* Function 10 */
1086 DWORD RI_ScSetServiceBitsW(
1087 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1088 DWORD dwServiceBits,
1089 int bSetBitsOn,
1090 int bUpdateImmediately,
1091 wchar_t *lpString)
1092 {
1093 UNIMPLEMENTED;
1094 return ERROR_CALL_NOT_IMPLEMENTED;
1095 }
1096
1097
1098 /* Function 11 */
1099 DWORD RChangeServiceConfigW(
1100 SC_RPC_HANDLE hService,
1101 DWORD dwServiceType,
1102 DWORD dwStartType,
1103 DWORD dwErrorControl,
1104 LPWSTR lpBinaryPathName,
1105 LPWSTR lpLoadOrderGroup,
1106 LPDWORD lpdwTagId,
1107 LPBYTE lpDependencies,
1108 DWORD dwDependSize,
1109 LPWSTR lpServiceStartName,
1110 LPBYTE lpPassword,
1111 DWORD dwPwSize,
1112 LPWSTR lpDisplayName)
1113 {
1114 DWORD dwError = ERROR_SUCCESS;
1115 PSERVICE_HANDLE hSvc;
1116 PSERVICE lpService = NULL;
1117 HKEY hServiceKey = NULL;
1118 LPWSTR lpDisplayNameW = NULL;
1119
1120 DPRINT("RChangeServiceConfigW() called\n");
1121 DPRINT("dwServiceType = %lu\n", dwServiceType);
1122 DPRINT("dwStartType = %lu\n", dwStartType);
1123 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1124 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1125 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1126 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1127
1128 if (ScmShutdown)
1129 return ERROR_SHUTDOWN_IN_PROGRESS;
1130
1131 hSvc = (PSERVICE_HANDLE)hService;
1132 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
1133 {
1134 DPRINT1("Invalid handle tag!\n");
1135 return ERROR_INVALID_HANDLE;
1136 }
1137
1138 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1139 SERVICE_CHANGE_CONFIG))
1140 {
1141 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1142 return ERROR_ACCESS_DENIED;
1143 }
1144
1145 lpService = hSvc->ServiceEntry;
1146 if (lpService == NULL)
1147 {
1148 DPRINT1("lpService == NULL!\n");
1149 return ERROR_INVALID_HANDLE;
1150 }
1151
1152 /* FIXME: Lock database exclusively */
1153
1154 if (lpService->bDeleted)
1155 {
1156 /* FIXME: Unlock database */
1157 DPRINT1("The service has already been marked for delete!\n");
1158 return ERROR_SERVICE_MARKED_FOR_DELETE;
1159 }
1160
1161 /* Open the service key */
1162 dwError = ScmOpenServiceKey(lpService->szServiceName,
1163 KEY_SET_VALUE,
1164 &hServiceKey);
1165 if (dwError != ERROR_SUCCESS)
1166 goto done;
1167
1168 /* Write service data to the registry */
1169 /* Set the display name */
1170 if (lpDisplayName != NULL && *lpDisplayName != 0)
1171 {
1172 RegSetValueExW(hServiceKey,
1173 L"DisplayName",
1174 0,
1175 REG_SZ,
1176 (LPBYTE)lpDisplayName,
1177 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1178
1179 /* Update the display name */
1180 lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
1181 0,
1182 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1183 if (lpDisplayNameW == NULL)
1184 {
1185 dwError = ERROR_NOT_ENOUGH_MEMORY;
1186 goto done;
1187 }
1188
1189 if (lpService->lpDisplayName != lpService->lpServiceName)
1190 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1191
1192 lpService->lpDisplayName = lpDisplayNameW;
1193 }
1194
1195 if (dwServiceType != SERVICE_NO_CHANGE)
1196 {
1197 /* Set the service type */
1198 dwError = RegSetValueExW(hServiceKey,
1199 L"Type",
1200 0,
1201 REG_DWORD,
1202 (LPBYTE)&dwServiceType,
1203 sizeof(DWORD));
1204 if (dwError != ERROR_SUCCESS)
1205 goto done;
1206
1207 lpService->Status.dwServiceType = dwServiceType;
1208 }
1209
1210 if (dwStartType != SERVICE_NO_CHANGE)
1211 {
1212 /* Set the start value */
1213 dwError = RegSetValueExW(hServiceKey,
1214 L"Start",
1215 0,
1216 REG_DWORD,
1217 (LPBYTE)&dwStartType,
1218 sizeof(DWORD));
1219 if (dwError != ERROR_SUCCESS)
1220 goto done;
1221
1222 lpService->dwStartType = dwStartType;
1223 }
1224
1225 if (dwErrorControl != SERVICE_NO_CHANGE)
1226 {
1227 /* Set the error control value */
1228 dwError = RegSetValueExW(hServiceKey,
1229 L"ErrorControl",
1230 0,
1231 REG_DWORD,
1232 (LPBYTE)&dwErrorControl,
1233 sizeof(DWORD));
1234 if (dwError != ERROR_SUCCESS)
1235 goto done;
1236
1237 lpService->dwErrorControl = dwErrorControl;
1238 }
1239
1240 #if 0
1241 /* FIXME: set the new ImagePath value */
1242
1243 /* Set the image path */
1244 if (dwServiceType & SERVICE_WIN32)
1245 {
1246 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1247 {
1248 dwError = RegSetValueExW(hServiceKey,
1249 L"ImagePath",
1250 0,
1251 REG_EXPAND_SZ,
1252 (LPBYTE)lpBinaryPathName,
1253 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1254 if (dwError != ERROR_SUCCESS)
1255 goto done;
1256 }
1257 }
1258 else if (dwServiceType & SERVICE_DRIVER)
1259 {
1260 if (lpImagePath != NULL && *lpImagePath != 0)
1261 {
1262 dwError = RegSetValueExW(hServiceKey,
1263 L"ImagePath",
1264 0,
1265 REG_EXPAND_SZ,
1266 (LPBYTE)lpImagePath,
1267 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
1268 if (dwError != ERROR_SUCCESS)
1269 goto done;
1270 }
1271 }
1272 #endif
1273
1274 /* Set the group name */
1275 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1276 {
1277 dwError = RegSetValueExW(hServiceKey,
1278 L"Group",
1279 0,
1280 REG_SZ,
1281 (LPBYTE)lpLoadOrderGroup,
1282 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1283 if (dwError != ERROR_SUCCESS)
1284 goto done;
1285
1286 dwError = ScmSetServiceGroup(lpService,
1287 lpLoadOrderGroup);
1288 if (dwError != ERROR_SUCCESS)
1289 goto done;
1290 }
1291
1292 if (lpdwTagId != NULL)
1293 {
1294 dwError = ScmAssignNewTag(lpService);
1295 if (dwError != ERROR_SUCCESS)
1296 goto done;
1297
1298 dwError = RegSetValueExW(hServiceKey,
1299 L"Tag",
1300 0,
1301 REG_DWORD,
1302 (LPBYTE)&lpService->dwTag,
1303 sizeof(DWORD));
1304 if (dwError != ERROR_SUCCESS)
1305 goto done;
1306
1307 *lpdwTagId = lpService->dwTag;
1308 }
1309
1310 /* Write dependencies */
1311 if (lpDependencies != NULL && *lpDependencies != 0)
1312 {
1313 dwError = ScmWriteDependencies(hServiceKey,
1314 (LPWSTR)lpDependencies,
1315 dwDependSize);
1316 if (dwError != ERROR_SUCCESS)
1317 goto done;
1318 }
1319
1320 if (lpPassword != NULL)
1321 {
1322 /* FIXME: Write password */
1323 }
1324
1325 /* FIXME: Unlock database */
1326
1327 done:
1328 if (hServiceKey != NULL)
1329 RegCloseKey(hServiceKey);
1330
1331 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1332
1333 return dwError;
1334 }
1335
1336
1337 /* Create a path suitable for the bootloader out of the full path */
1338 DWORD
1339 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1340 {
1341 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1342 WCHAR Dest;
1343 WCHAR *Expanded;
1344 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1345 OBJECT_ATTRIBUTES ObjectAttributes;
1346 NTSTATUS Status;
1347 HANDLE SymbolicLinkHandle;
1348
1349 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1350
1351 ServiceNameLen = wcslen(CanonName);
1352
1353 /* First check, if it's already good */
1354 if (ServiceNameLen > 12 &&
1355 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1356 {
1357 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1358 if (*RelativeName == NULL)
1359 {
1360 DPRINT1("Error allocating memory for boot driver name!\n");
1361 return ERROR_NOT_ENOUGH_MEMORY;
1362 }
1363
1364 /* Copy it */
1365 wcscpy(*RelativeName, CanonName);
1366
1367 DPRINT1("Bootdriver name %S\n", *RelativeName);
1368 return ERROR_SUCCESS;
1369 }
1370
1371 /* If it has %SystemRoot% prefix, substitute it to \System*/
1372 if (ServiceNameLen > 13 &&
1373 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1374 {
1375 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1376 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1377
1378 if (*RelativeName == NULL)
1379 {
1380 DPRINT1("Error allocating memory for boot driver name!\n");
1381 return ERROR_NOT_ENOUGH_MEMORY;
1382 }
1383
1384 /* Copy it */
1385 wcscpy(*RelativeName, L"\\SystemRoot\\");
1386 wcscat(*RelativeName, CanonName + 13);
1387
1388 DPRINT1("Bootdriver name %S\n", *RelativeName);
1389 return ERROR_SUCCESS;
1390 }
1391
1392 /* Get buffer size needed for expanding env strings */
1393 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1394
1395 if (BufferSize <= 1)
1396 {
1397 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1398 return ERROR_INVALID_ENVIRONMENT;
1399 }
1400
1401 /* Allocate memory, since the size is known now */
1402 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1403 if (!Expanded)
1404 {
1405 DPRINT1("Error allocating memory for boot driver name!\n");
1406 return ERROR_NOT_ENOUGH_MEMORY;
1407 }
1408
1409 /* Expand it */
1410 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1411 BufferSize)
1412 {
1413 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1414 LocalFree(Expanded);
1415 return ERROR_NOT_ENOUGH_MEMORY;
1416 }
1417
1418 /* Convert to NY-style path */
1419 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1420 {
1421 DPRINT1("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1422 return ERROR_INVALID_ENVIRONMENT;
1423 }
1424
1425 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1426
1427 /* No need to keep the dos-path anymore */
1428 LocalFree(Expanded);
1429
1430 /* Copy it to the allocated place */
1431 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1432 if (!Expanded)
1433 {
1434 DPRINT1("Error allocating memory for boot driver name!\n");
1435 return ERROR_NOT_ENOUGH_MEMORY;
1436 }
1437
1438 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1439 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1440 Expanded[ExpandedLen] = 0;
1441
1442 if (ServiceNameLen > ExpandedLen &&
1443 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
1444 {
1445 /* Only \SystemRoot\ is missing */
1446 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1447 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1448 if (*RelativeName == NULL)
1449 {
1450 DPRINT1("Error allocating memory for boot driver name!\n");
1451 LocalFree(Expanded);
1452 return ERROR_NOT_ENOUGH_MEMORY;
1453 }
1454
1455 wcscpy(*RelativeName, L"\\SystemRoot\\");
1456 wcscat(*RelativeName, CanonName + ExpandedLen);
1457
1458 RtlFreeUnicodeString(&NtPathName);
1459 return ERROR_SUCCESS;
1460 }
1461
1462 /* The most complex case starts here */
1463 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1464 InitializeObjectAttributes(&ObjectAttributes,
1465 &SystemRoot,
1466 OBJ_CASE_INSENSITIVE,
1467 NULL,
1468 NULL);
1469
1470 /* Open this symlink */
1471 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1472
1473 if (NT_SUCCESS(Status))
1474 {
1475 LinkTarget.Length = 0;
1476 LinkTarget.MaximumLength = 0;
1477
1478 DPRINT("Opened symbolic link object\n");
1479
1480 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1481 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1482 {
1483 /* Check if required buffer size is sane */
1484 if (BufferSize > 0xFFFD)
1485 {
1486 DPRINT1("Too large buffer required\n");
1487 *RelativeName = 0;
1488
1489 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1490 LocalFree(Expanded);
1491 return ERROR_NOT_ENOUGH_MEMORY;
1492 }
1493
1494 /* Alloc the string */
1495 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1496 if (!LinkTarget.Buffer)
1497 {
1498 DPRINT1("Unable to alloc buffer\n");
1499 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1500 LocalFree(Expanded);
1501 return ERROR_NOT_ENOUGH_MEMORY;
1502 }
1503
1504 /* Do a real query now */
1505 LinkTarget.Length = BufferSize;
1506 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1507
1508 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1509 if (NT_SUCCESS(Status))
1510 {
1511 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1512
1513 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1514 if ((ServiceNameLen > ExpandedLen) &&
1515 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1516 {
1517 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1518 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1519
1520 if (*RelativeName == NULL)
1521 {
1522 DPRINT1("Unable to alloc buffer\n");
1523 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1524 LocalFree(Expanded);
1525 RtlFreeUnicodeString(&NtPathName);
1526 return ERROR_NOT_ENOUGH_MEMORY;
1527 }
1528
1529 /* Copy it over, substituting the first part
1530 with SystemRoot */
1531 wcscpy(*RelativeName, L"\\SystemRoot\\");
1532 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1533
1534 /* Cleanup */
1535 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1536 LocalFree(Expanded);
1537 RtlFreeUnicodeString(&NtPathName);
1538
1539 /* Return success */
1540 return ERROR_SUCCESS;
1541 }
1542 else
1543 {
1544 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1545 LocalFree(Expanded);
1546 RtlFreeUnicodeString(&NtPathName);
1547 return ERROR_INVALID_PARAMETER;
1548 }
1549 }
1550 else
1551 {
1552 DPRINT1("Error, Status = %08X\n", Status);
1553 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1554 LocalFree(Expanded);
1555 RtlFreeUnicodeString(&NtPathName);
1556 return ERROR_INVALID_PARAMETER;
1557 }
1558 }
1559 else
1560 {
1561 DPRINT1("Error, Status = %08X\n", Status);
1562 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1563 LocalFree(Expanded);
1564 RtlFreeUnicodeString(&NtPathName);
1565 return ERROR_INVALID_PARAMETER;
1566 }
1567 }
1568 else
1569 {
1570 DPRINT1("Error, Status = %08X\n", Status);
1571 LocalFree(Expanded);
1572 return ERROR_INVALID_PARAMETER;
1573 }
1574
1575 /* Failure */
1576 *RelativeName = NULL;
1577 return ERROR_INVALID_PARAMETER;
1578 }
1579
1580 DWORD
1581 ScmCanonDriverImagePath(DWORD dwStartType,
1582 const wchar_t *lpServiceName,
1583 wchar_t **lpCanonName)
1584 {
1585 DWORD ServiceNameLen, Result;
1586 UNICODE_STRING NtServiceName;
1587 WCHAR *RelativeName;
1588 const WCHAR *SourceName = lpServiceName;
1589
1590 /* Calculate the length of the service's name */
1591 ServiceNameLen = wcslen(lpServiceName);
1592
1593 /* 12 is wcslen(L"\\SystemRoot\\") */
1594 if (ServiceNameLen > 12 &&
1595 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1596 {
1597 /* SystemRoot prefix is already included */
1598
1599 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1600
1601 if (*lpCanonName == NULL)
1602 {
1603 DPRINT1("Error allocating memory for canonized service name!\n");
1604 return ERROR_NOT_ENOUGH_MEMORY;
1605 }
1606
1607 /* If it's a boot-time driver, it must be systemroot relative */
1608 if (dwStartType == SERVICE_BOOT_START)
1609 SourceName += 12;
1610
1611 /* Copy it */
1612 wcscpy(*lpCanonName, SourceName);
1613
1614 DPRINT("Canonicalized name %S\n", *lpCanonName);
1615 return NO_ERROR;
1616 }
1617
1618 /* Check if it has %SystemRoot% (len=13) */
1619 if (ServiceNameLen > 13 &&
1620 !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1621 {
1622 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1623 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1624
1625 if (*lpCanonName == NULL)
1626 {
1627 DPRINT1("Error allocating memory for canonized service name!\n");
1628 return ERROR_NOT_ENOUGH_MEMORY;
1629 }
1630
1631 /* If it's a boot-time driver, it must be systemroot relative */
1632 if (dwStartType == SERVICE_BOOT_START)
1633 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1634
1635 wcscat(*lpCanonName, lpServiceName + 13);
1636
1637 DPRINT("Canonicalized name %S\n", *lpCanonName);
1638 return NO_ERROR;
1639 }
1640
1641 /* Check if it's a relative path name */
1642 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1643 {
1644 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1645
1646 if (*lpCanonName == NULL)
1647 {
1648 DPRINT1("Error allocating memory for canonized service name!\n");
1649 return ERROR_NOT_ENOUGH_MEMORY;
1650 }
1651
1652 /* Just copy it over without changing */
1653 wcscpy(*lpCanonName, lpServiceName);
1654
1655 return NO_ERROR;
1656 }
1657
1658 /* It seems to be a DOS path, convert it */
1659 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1660 {
1661 DPRINT1("RtlDosPathNameToNtPathName_U() failed!\n");
1662 return ERROR_INVALID_PARAMETER;
1663 }
1664
1665 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1666
1667 if (*lpCanonName == NULL)
1668 {
1669 DPRINT1("Error allocating memory for canonized service name!\n");
1670 RtlFreeUnicodeString(&NtServiceName);
1671 return ERROR_NOT_ENOUGH_MEMORY;
1672 }
1673
1674 /* Copy the string */
1675 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1676
1677 /* The unicode string is not needed anymore */
1678 RtlFreeUnicodeString(&NtServiceName);
1679
1680 if (dwStartType != SERVICE_BOOT_START)
1681 {
1682 DPRINT("Canonicalized name %S\n", *lpCanonName);
1683 return NO_ERROR;
1684 }
1685
1686 /* The service is boot-started, so must be relative */
1687 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1688 if (Result)
1689 {
1690 /* There is a problem, free name and return */
1691 LocalFree(*lpCanonName);
1692 DPRINT1("Error converting named!\n");
1693 return Result;
1694 }
1695
1696 ASSERT(RelativeName);
1697
1698 /* Copy that string */
1699 wcscpy(*lpCanonName, RelativeName + 12);
1700
1701 /* Free the allocated buffer */
1702 LocalFree(RelativeName);
1703
1704 DPRINT("Canonicalized name %S\n", *lpCanonName);
1705
1706 /* Success */
1707 return NO_ERROR;
1708 }
1709
1710
1711 /* Function 12 */
1712 DWORD RCreateServiceW(
1713 SC_RPC_HANDLE hSCManager,
1714 LPCWSTR lpServiceName,
1715 LPCWSTR lpDisplayName,
1716 DWORD dwDesiredAccess,
1717 DWORD dwServiceType,
1718 DWORD dwStartType,
1719 DWORD dwErrorControl,
1720 LPCWSTR lpBinaryPathName,
1721 LPCWSTR lpLoadOrderGroup,
1722 LPDWORD lpdwTagId,
1723 LPBYTE lpDependencies,
1724 DWORD dwDependSize,
1725 LPCWSTR lpServiceStartName,
1726 LPBYTE lpPassword,
1727 DWORD dwPwSize,
1728 LPSC_RPC_HANDLE lpServiceHandle)
1729 {
1730 PMANAGER_HANDLE hManager;
1731 DWORD dwError = ERROR_SUCCESS;
1732 PSERVICE lpService = NULL;
1733 SC_HANDLE hServiceHandle = NULL;
1734 LPWSTR lpImagePath = NULL;
1735 HKEY hServiceKey = NULL;
1736
1737 DPRINT("RCreateServiceW() called\n");
1738 DPRINT("lpServiceName = %S\n", lpServiceName);
1739 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1740 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1741 DPRINT("dwServiceType = %lu\n", dwServiceType);
1742 DPRINT("dwStartType = %lu\n", dwStartType);
1743 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1744 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1745 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1746
1747 if (ScmShutdown)
1748 return ERROR_SHUTDOWN_IN_PROGRESS;
1749
1750 hManager = (PMANAGER_HANDLE)hSCManager;
1751 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1752 {
1753 DPRINT1("Invalid manager handle!\n");
1754 return ERROR_INVALID_HANDLE;
1755 }
1756
1757 /* Check access rights */
1758 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1759 SC_MANAGER_CREATE_SERVICE))
1760 {
1761 DPRINT1("Insufficient access rights! 0x%lx\n",
1762 hManager->Handle.DesiredAccess);
1763 return ERROR_ACCESS_DENIED;
1764 }
1765
1766 if (wcslen(lpServiceName) == 0)
1767 {
1768 return ERROR_INVALID_NAME;
1769 }
1770
1771 if (wcslen(lpBinaryPathName) == 0)
1772 {
1773 return ERROR_INVALID_PARAMETER;
1774 }
1775
1776 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1777 (lpServiceStartName))
1778 {
1779 return ERROR_INVALID_PARAMETER;
1780 }
1781
1782 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
1783 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1784 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
1785 {
1786 return ERROR_INVALID_PARAMETER;
1787 }
1788
1789 if (dwStartType > SERVICE_DISABLED)
1790 {
1791 return ERROR_INVALID_PARAMETER;
1792 }
1793
1794 lpService = ScmGetServiceEntryByName(lpServiceName);
1795 if (lpService)
1796 {
1797 /* check if it is marked for deletion */
1798 if (lpService->bDeleted)
1799 return ERROR_SERVICE_MARKED_FOR_DELETE;
1800 /* Return Error exist */
1801 return ERROR_SERVICE_EXISTS;
1802 }
1803
1804 if (lpDisplayName != NULL &&
1805 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
1806 return ERROR_DUPLICATE_SERVICE_NAME;
1807
1808 if (dwServiceType & SERVICE_DRIVER)
1809 {
1810 dwError = ScmCanonDriverImagePath(dwStartType,
1811 lpBinaryPathName,
1812 &lpImagePath);
1813 if (dwError != ERROR_SUCCESS)
1814 goto done;
1815 }
1816 else
1817 {
1818 if (dwStartType == SERVICE_BOOT_START ||
1819 dwStartType == SERVICE_SYSTEM_START)
1820 {
1821 return ERROR_INVALID_PARAMETER;
1822 }
1823 }
1824
1825 /* Allocate a new service entry */
1826 dwError = ScmCreateNewServiceRecord(lpServiceName,
1827 &lpService);
1828 if (dwError != ERROR_SUCCESS)
1829 goto done;
1830
1831 /* Fill the new service entry */
1832 lpService->Status.dwServiceType = dwServiceType;
1833 lpService->dwStartType = dwStartType;
1834 lpService->dwErrorControl = dwErrorControl;
1835
1836 /* Fill the display name */
1837 if (lpDisplayName != NULL &&
1838 *lpDisplayName != 0 &&
1839 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1840 {
1841 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1842 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1843 if (lpService->lpDisplayName == NULL)
1844 {
1845 dwError = ERROR_NOT_ENOUGH_MEMORY;
1846 goto done;
1847 }
1848 wcscpy(lpService->lpDisplayName, lpDisplayName);
1849 }
1850
1851 /* Assign the service to a group */
1852 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1853 {
1854 dwError = ScmSetServiceGroup(lpService,
1855 lpLoadOrderGroup);
1856 if (dwError != ERROR_SUCCESS)
1857 goto done;
1858 }
1859
1860 /* Assign a new tag */
1861 if (lpdwTagId != NULL)
1862 {
1863 dwError = ScmAssignNewTag(lpService);
1864 if (dwError != ERROR_SUCCESS)
1865 goto done;
1866 }
1867
1868 /* Write service data to the registry */
1869 /* Create the service key */
1870 dwError = ScmCreateServiceKey(lpServiceName,
1871 KEY_WRITE,
1872 &hServiceKey);
1873 if (dwError != ERROR_SUCCESS)
1874 goto done;
1875
1876 /* Set the display name */
1877 if (lpDisplayName != NULL && *lpDisplayName != 0)
1878 {
1879 RegSetValueExW(hServiceKey,
1880 L"DisplayName",
1881 0,
1882 REG_SZ,
1883 (LPBYTE)lpDisplayName,
1884 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1885 }
1886
1887 /* Set the service type */
1888 dwError = RegSetValueExW(hServiceKey,
1889 L"Type",
1890 0,
1891 REG_DWORD,
1892 (LPBYTE)&dwServiceType,
1893 sizeof(DWORD));
1894 if (dwError != ERROR_SUCCESS)
1895 goto done;
1896
1897 /* Set the start value */
1898 dwError = RegSetValueExW(hServiceKey,
1899 L"Start",
1900 0,
1901 REG_DWORD,
1902 (LPBYTE)&dwStartType,
1903 sizeof(DWORD));
1904 if (dwError != ERROR_SUCCESS)
1905 goto done;
1906
1907 /* Set the error control value */
1908 dwError = RegSetValueExW(hServiceKey,
1909 L"ErrorControl",
1910 0,
1911 REG_DWORD,
1912 (LPBYTE)&dwErrorControl,
1913 sizeof(DWORD));
1914 if (dwError != ERROR_SUCCESS)
1915 goto done;
1916
1917 /* Set the image path */
1918 if (dwServiceType & SERVICE_WIN32)
1919 {
1920 dwError = RegSetValueExW(hServiceKey,
1921 L"ImagePath",
1922 0,
1923 REG_EXPAND_SZ,
1924 (LPBYTE)lpBinaryPathName,
1925 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1926 if (dwError != ERROR_SUCCESS)
1927 goto done;
1928 }
1929 else if (dwServiceType & SERVICE_DRIVER)
1930 {
1931 dwError = RegSetValueExW(hServiceKey,
1932 L"ImagePath",
1933 0,
1934 REG_EXPAND_SZ,
1935 (LPBYTE)lpImagePath,
1936 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
1937 if (dwError != ERROR_SUCCESS)
1938 goto done;
1939 }
1940
1941 /* Set the group name */
1942 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1943 {
1944 dwError = RegSetValueExW(hServiceKey,
1945 L"Group",
1946 0,
1947 REG_SZ,
1948 (LPBYTE)lpLoadOrderGroup,
1949 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1950 if (dwError != ERROR_SUCCESS)
1951 goto done;
1952 }
1953
1954 if (lpdwTagId != NULL)
1955 {
1956 dwError = RegSetValueExW(hServiceKey,
1957 L"Tag",
1958 0,
1959 REG_DWORD,
1960 (LPBYTE)&lpService->dwTag,
1961 sizeof(DWORD));
1962 if (dwError != ERROR_SUCCESS)
1963 goto done;
1964 }
1965
1966 /* Write dependencies */
1967 if (lpDependencies != NULL && *lpDependencies != 0)
1968 {
1969 dwError = ScmWriteDependencies(hServiceKey,
1970 (LPWSTR)lpDependencies,
1971 dwDependSize);
1972 if (dwError != ERROR_SUCCESS)
1973 goto done;
1974 }
1975
1976 /* FIXME: Handle lpServiceStartName propertly! */
1977 /* If a non driver and NULL for lpServiceStartName, write ObjectName as LocalSystem */
1978 if ((dwServiceType & SERVICE_WIN32) && (!lpServiceStartName))
1979 {
1980 dwError = RegSetValueExW(hServiceKey,
1981 L"ObjectName",
1982 0,
1983 REG_SZ,
1984 (LPBYTE)L"LocalSystem",
1985 24);
1986 if (dwError != ERROR_SUCCESS)
1987 goto done;
1988 }
1989
1990 if (lpPassword != NULL)
1991 {
1992 /* FIXME: Write password */
1993 }
1994
1995 dwError = ScmCreateServiceHandle(lpService,
1996 &hServiceHandle);
1997 if (dwError != ERROR_SUCCESS)
1998 goto done;
1999
2000 dwError = ScmCheckAccess(hServiceHandle,
2001 dwDesiredAccess);
2002 if (dwError != ERROR_SUCCESS)
2003 goto done;
2004
2005 lpService->dwRefCount = 1;
2006 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2007
2008 done:;
2009 if (hServiceKey != NULL)
2010 RegCloseKey(hServiceKey);
2011
2012 if (dwError == ERROR_SUCCESS)
2013 {
2014 DPRINT("hService %p\n", hServiceHandle);
2015 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2016
2017 if (lpdwTagId != NULL)
2018 *lpdwTagId = lpService->dwTag;
2019 }
2020 else
2021 {
2022 /* Release the display name buffer */
2023 if (lpService->lpServiceName != NULL)
2024 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2025
2026 if (hServiceHandle)
2027 {
2028 /* Remove the service handle */
2029 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2030 }
2031
2032 if (lpService != NULL)
2033 {
2034 /* FIXME: remove the service entry */
2035 }
2036 }
2037
2038 if (lpImagePath != NULL)
2039 HeapFree(GetProcessHeap(), 0, lpImagePath);
2040
2041 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2042
2043 return dwError;
2044 }
2045
2046
2047 /* Function 13 */
2048 DWORD REnumDependentServicesW(
2049 SC_RPC_HANDLE hService,
2050 DWORD dwServiceState,
2051 LPBYTE lpServices,
2052 DWORD cbBufSize,
2053 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2054 LPBOUNDED_DWORD_256K lpServicesReturned)
2055 {
2056 DWORD dwError = ERROR_SUCCESS;
2057 DWORD dwServicesReturned = 0;
2058 DWORD dwServiceCount;
2059 HKEY hServicesKey = NULL;
2060 LPSC_RPC_HANDLE hSCObject;
2061 PSERVICE_HANDLE hSvc;
2062 PSERVICE lpService = NULL;
2063 PSERVICE *lpServicesArray = NULL;
2064 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2065 LPWSTR lpStr;
2066
2067 *pcbBytesNeeded = 0;
2068 *lpServicesReturned = 0;
2069
2070 DPRINT("REnumDependentServicesW() called\n");
2071
2072 hSCObject = &hService;
2073 hSvc = (PSERVICE_HANDLE) *hSCObject;
2074 lpService = hSvc->ServiceEntry;
2075
2076 /* Check access rights */
2077 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2078 SC_MANAGER_ENUMERATE_SERVICE))
2079 {
2080 DPRINT1("Insufficient access rights! 0x%lx\n",
2081 hSvc->Handle.DesiredAccess);
2082 return ERROR_ACCESS_DENIED;
2083 }
2084
2085 /* Open the Services Reg key */
2086 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2087 L"System\\CurrentControlSet\\Services",
2088 0,
2089 KEY_READ,
2090 &hServicesKey);
2091 if (dwError != ERROR_SUCCESS)
2092 return dwError;
2093
2094 /* First determine the bytes needed and get the number of dependent services */
2095 dwError = Int_EnumDependentServicesW(hServicesKey,
2096 lpService,
2097 dwServiceState,
2098 NULL,
2099 pcbBytesNeeded,
2100 &dwServicesReturned);
2101 if (dwError != ERROR_SUCCESS)
2102 goto Done;
2103
2104 /* If buffer size is less than the bytes needed or pointer is null */
2105 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2106 {
2107 dwError = ERROR_MORE_DATA;
2108 goto Done;
2109 }
2110
2111 /* Allocate memory for array of service pointers */
2112 lpServicesArray = HeapAlloc(GetProcessHeap(),
2113 0,
2114 (dwServicesReturned + 1) * sizeof(PSERVICE));
2115 if (!lpServicesArray)
2116 {
2117 DPRINT1("Could not allocate a buffer!!\n");
2118 dwError = ERROR_NOT_ENOUGH_MEMORY;
2119 goto Done;
2120 }
2121
2122 dwServicesReturned = 0;
2123 *pcbBytesNeeded = 0;
2124
2125 dwError = Int_EnumDependentServicesW(hServicesKey,
2126 lpService,
2127 dwServiceState,
2128 lpServicesArray,
2129 pcbBytesNeeded,
2130 &dwServicesReturned);
2131 if (dwError != ERROR_SUCCESS)
2132 {
2133 goto Done;
2134 }
2135
2136 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2137 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2138
2139 /* Copy EnumDepenedentService to Buffer */
2140 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2141 {
2142 lpService = lpServicesArray[dwServiceCount];
2143
2144 /* Copy status info */
2145 memcpy(&lpServicesPtr->ServiceStatus,
2146 &lpService->Status,
2147 sizeof(SERVICE_STATUS));
2148
2149 /* Copy display name */
2150 wcscpy(lpStr, lpService->lpDisplayName);
2151 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2152 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2153
2154 /* Copy service name */
2155 wcscpy(lpStr, lpService->lpServiceName);
2156 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2157 lpStr += (wcslen(lpService->lpServiceName) + 1);
2158
2159 lpServicesPtr ++;
2160 }
2161
2162 *lpServicesReturned = dwServicesReturned;
2163
2164 Done:
2165 if (lpServicesArray != NULL)
2166 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2167
2168 RegCloseKey(hServicesKey);
2169
2170 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2171
2172 return dwError;
2173 }
2174
2175
2176 /* Function 14 */
2177 DWORD REnumServicesStatusW(
2178 SC_RPC_HANDLE hSCManager,
2179 DWORD dwServiceType,
2180 DWORD dwServiceState,
2181 LPBYTE lpBuffer,
2182 DWORD dwBufSize,
2183 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2184 LPBOUNDED_DWORD_256K lpServicesReturned,
2185 LPBOUNDED_DWORD_256K lpResumeHandle)
2186 {
2187 PMANAGER_HANDLE hManager;
2188 PSERVICE lpService;
2189 DWORD dwError = ERROR_SUCCESS;
2190 PLIST_ENTRY ServiceEntry;
2191 PSERVICE CurrentService;
2192 DWORD dwState;
2193 DWORD dwRequiredSize;
2194 DWORD dwServiceCount;
2195 DWORD dwSize;
2196 DWORD dwLastResumeCount = 0;
2197 LPENUM_SERVICE_STATUSW lpStatusPtr;
2198 LPWSTR lpStringPtr;
2199
2200 DPRINT("REnumServicesStatusW() called\n");
2201
2202 if (ScmShutdown)
2203 return ERROR_SHUTDOWN_IN_PROGRESS;
2204
2205 hManager = (PMANAGER_HANDLE)hSCManager;
2206 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2207 {
2208 DPRINT1("Invalid manager handle!\n");
2209 return ERROR_INVALID_HANDLE;
2210 }
2211
2212 *pcbBytesNeeded = 0;
2213 *lpServicesReturned = 0;
2214
2215 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2216 {
2217 DPRINT("Not a valid Service Type!\n");
2218 return ERROR_INVALID_PARAMETER;
2219 }
2220
2221 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2222 {
2223 DPRINT("Not a valid Service State!\n");
2224 return ERROR_INVALID_PARAMETER;
2225 }
2226
2227 /* Check access rights */
2228 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2229 SC_MANAGER_ENUMERATE_SERVICE))
2230 {
2231 DPRINT1("Insufficient access rights! 0x%lx\n",
2232 hManager->Handle.DesiredAccess);
2233 return ERROR_ACCESS_DENIED;
2234 }
2235
2236 if (lpResumeHandle)
2237 dwLastResumeCount = *lpResumeHandle;
2238
2239 /* FIXME: Lock the service list shared */
2240
2241 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2242 if (lpService == NULL)
2243 {
2244 dwError = ERROR_SUCCESS;
2245 goto Done;
2246 }
2247
2248 dwRequiredSize = 0;
2249 dwServiceCount = 0;
2250
2251 for (ServiceEntry = &lpService->ServiceListEntry;
2252 ServiceEntry != &ServiceListHead;
2253 ServiceEntry = ServiceEntry->Flink)
2254 {
2255 CurrentService = CONTAINING_RECORD(ServiceEntry,
2256 SERVICE,
2257 ServiceListEntry);
2258
2259 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2260 continue;
2261
2262 dwState = SERVICE_ACTIVE;
2263 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2264 dwState = SERVICE_INACTIVE;
2265
2266 if ((dwState & dwServiceState) == 0)
2267 continue;
2268
2269 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2270 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2271 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2272
2273 if (dwRequiredSize + dwSize > dwBufSize)
2274 {
2275 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2276 break;
2277 }
2278
2279 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2280 dwRequiredSize += dwSize;
2281 dwServiceCount++;
2282 dwLastResumeCount = CurrentService->dwResumeCount;
2283 }
2284
2285 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2286 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2287
2288 for (;
2289 ServiceEntry != &ServiceListHead;
2290 ServiceEntry = ServiceEntry->Flink)
2291 {
2292 CurrentService = CONTAINING_RECORD(ServiceEntry,
2293 SERVICE,
2294 ServiceListEntry);
2295
2296 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2297 continue;
2298
2299 dwState = SERVICE_ACTIVE;
2300 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2301 dwState = SERVICE_INACTIVE;
2302
2303 if ((dwState & dwServiceState) == 0)
2304 continue;
2305
2306 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2307 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2308 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2309
2310 dwError = ERROR_MORE_DATA;
2311 }
2312
2313 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2314
2315 if (lpResumeHandle)
2316 *lpResumeHandle = dwLastResumeCount;
2317
2318 *lpServicesReturned = dwServiceCount;
2319 *pcbBytesNeeded = dwRequiredSize;
2320
2321 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2322 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2323 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2324
2325 dwRequiredSize = 0;
2326 for (ServiceEntry = &lpService->ServiceListEntry;
2327 ServiceEntry != &ServiceListHead;
2328 ServiceEntry = ServiceEntry->Flink)
2329 {
2330 CurrentService = CONTAINING_RECORD(ServiceEntry,
2331 SERVICE,
2332 ServiceListEntry);
2333
2334 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2335 continue;
2336
2337 dwState = SERVICE_ACTIVE;
2338 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2339 dwState = SERVICE_INACTIVE;
2340
2341 if ((dwState & dwServiceState) == 0)
2342 continue;
2343
2344 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2345 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2346 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2347
2348 if (dwRequiredSize + dwSize > dwBufSize)
2349 break;
2350
2351 /* Copy the service name */
2352 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2353 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2354 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2355
2356 /* Copy the display name */
2357 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2358 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2359 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2360
2361 /* Copy the status information */
2362 memcpy(&lpStatusPtr->ServiceStatus,
2363 &CurrentService->Status,
2364 sizeof(SERVICE_STATUS));
2365
2366 lpStatusPtr++;
2367 dwRequiredSize += dwSize;
2368 }
2369
2370 if (dwError == 0)
2371 {
2372 *pcbBytesNeeded = 0;
2373 if (lpResumeHandle) *lpResumeHandle = 0;
2374 }
2375
2376 Done:;
2377 /* FIXME: Unlock the service list */
2378
2379 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2380
2381 return dwError;
2382 }
2383
2384
2385 /* Function 15 */
2386 DWORD ROpenSCManagerW(
2387 LPWSTR lpMachineName,
2388 LPWSTR lpDatabaseName,
2389 DWORD dwDesiredAccess,
2390 LPSC_RPC_HANDLE lpScHandle)
2391 {
2392 DWORD dwError;
2393 SC_HANDLE hHandle;
2394
2395 DPRINT("ROpenSCManagerW() called\n");
2396 DPRINT("lpMachineName = %p\n", lpMachineName);
2397 DPRINT("lpMachineName: %S\n", lpMachineName);
2398 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2399 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2400 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2401
2402 if (ScmShutdown)
2403 return ERROR_SHUTDOWN_IN_PROGRESS;
2404
2405 if (!lpScHandle)
2406 return ERROR_INVALID_PARAMETER;
2407
2408 dwError = ScmCreateManagerHandle(lpDatabaseName,
2409 &hHandle);
2410 if (dwError != ERROR_SUCCESS)
2411 {
2412 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2413 return dwError;
2414 }
2415
2416 /* Check the desired access */
2417 dwError = ScmCheckAccess(hHandle,
2418 dwDesiredAccess | SC_MANAGER_CONNECT);
2419 if (dwError != ERROR_SUCCESS)
2420 {
2421 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2422 HeapFree(GetProcessHeap(), 0, hHandle);
2423 return dwError;
2424 }
2425
2426 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2427 DPRINT("*hScm = %p\n", *lpScHandle);
2428
2429 DPRINT("ROpenSCManagerW() done\n");
2430
2431 return ERROR_SUCCESS;
2432 }
2433
2434
2435 /* Function 16 */
2436 DWORD ROpenServiceW(
2437 SC_RPC_HANDLE hSCManager,
2438 LPWSTR lpServiceName,
2439 DWORD dwDesiredAccess,
2440 LPSC_RPC_HANDLE lpServiceHandle)
2441 {
2442 PSERVICE lpService;
2443 PMANAGER_HANDLE hManager;
2444 SC_HANDLE hHandle;
2445 DWORD dwError;
2446
2447 DPRINT("ROpenServiceW() called\n");
2448 DPRINT("hSCManager = %p\n", hSCManager);
2449 DPRINT("lpServiceName = %p\n", lpServiceName);
2450 DPRINT("lpServiceName: %S\n", lpServiceName);
2451 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2452
2453 if (ScmShutdown)
2454 return ERROR_SHUTDOWN_IN_PROGRESS;
2455
2456 hManager = (PMANAGER_HANDLE)hSCManager;
2457 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2458 {
2459 DPRINT1("Invalid manager handle!\n");
2460 return ERROR_INVALID_HANDLE;
2461 }
2462
2463 if (!lpServiceHandle)
2464 return ERROR_INVALID_PARAMETER;
2465
2466 if (!lpServiceName)
2467 return ERROR_INVALID_ADDRESS;
2468
2469 /* FIXME: Lock the service list */
2470
2471 /* Get service database entry */
2472 lpService = ScmGetServiceEntryByName(lpServiceName);
2473 if (lpService == NULL)
2474 {
2475 DPRINT("Could not find a service!\n");
2476 return ERROR_SERVICE_DOES_NOT_EXIST;
2477 }
2478
2479 /* Create a service handle */
2480 dwError = ScmCreateServiceHandle(lpService,
2481 &hHandle);
2482 if (dwError != ERROR_SUCCESS)
2483 {
2484 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2485 return dwError;
2486 }
2487
2488 /* Check the desired access */
2489 dwError = ScmCheckAccess(hHandle,
2490 dwDesiredAccess);
2491 if (dwError != ERROR_SUCCESS)
2492 {
2493 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2494 HeapFree(GetProcessHeap(), 0, hHandle);
2495 return dwError;
2496 }
2497
2498 lpService->dwRefCount++;
2499 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2500
2501 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2502 DPRINT("*hService = %p\n", *lpServiceHandle);
2503
2504 DPRINT("ROpenServiceW() done\n");
2505
2506 return ERROR_SUCCESS;
2507 }
2508
2509
2510 /* Function 17 */
2511 DWORD RQueryServiceConfigW(
2512 SC_RPC_HANDLE hService,
2513 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2514 DWORD cbBufSize,
2515 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2516 {
2517 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2518 DWORD dwError = ERROR_SUCCESS;
2519 PSERVICE_HANDLE hSvc;
2520 PSERVICE lpService = NULL;
2521 HKEY hServiceKey = NULL;
2522 LPWSTR lpImagePath = NULL;
2523 LPWSTR lpServiceStartName = NULL;
2524 DWORD dwRequiredSize;
2525 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2526 WCHAR lpEmptyString[] = {0,0};
2527 LPWSTR lpStr;
2528
2529 DPRINT("RQueryServiceConfigW() called\n");
2530
2531 if (ScmShutdown)
2532 return ERROR_SHUTDOWN_IN_PROGRESS;
2533
2534 hSvc = (PSERVICE_HANDLE)hService;
2535 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2536 {
2537 DPRINT1("Invalid handle tag!\n");
2538 return ERROR_INVALID_HANDLE;
2539 }
2540
2541 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2542 SERVICE_QUERY_CONFIG))
2543 {
2544 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2545 return ERROR_ACCESS_DENIED;
2546 }
2547
2548 lpService = hSvc->ServiceEntry;
2549 if (lpService == NULL)
2550 {
2551 DPRINT1("lpService == NULL!\n");
2552 return ERROR_INVALID_HANDLE;
2553 }
2554
2555 /* FIXME: Lock the service database shared */
2556
2557 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2558 KEY_READ,
2559 &hServiceKey);
2560 if (dwError != ERROR_SUCCESS)
2561 goto Done;
2562
2563 dwError = ScmReadString(hServiceKey,
2564 L"ImagePath",
2565 &lpImagePath);
2566 if (dwError != ERROR_SUCCESS)
2567 goto Done;
2568
2569 ScmReadString(hServiceKey,
2570 L"ObjectName",
2571 &lpServiceStartName);
2572
2573 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2574
2575 if (lpImagePath != NULL)
2576 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2577 else
2578 dwRequiredSize += 2 * sizeof(WCHAR);
2579
2580 if (lpService->lpGroup != NULL)
2581 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2582 else
2583 dwRequiredSize += 2 * sizeof(WCHAR);
2584
2585 /* FIXME: Add Dependencies length*/
2586
2587 if (lpServiceStartName != NULL)
2588 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2589 else
2590 dwRequiredSize += 2 * sizeof(WCHAR);
2591
2592 if (lpService->lpDisplayName != NULL)
2593 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2594 else
2595 dwRequiredSize += 2 * sizeof(WCHAR);
2596
2597 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2598 {
2599 dwError = ERROR_INSUFFICIENT_BUFFER;
2600 }
2601 else
2602 {
2603 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2604 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2605 lpConfig->dwStartType = lpService->dwStartType;
2606 lpConfig->dwErrorControl = lpService->dwErrorControl;
2607 lpConfig->dwTagId = lpService->dwTag;
2608
2609 lpStr = (LPWSTR)(lpConfig + 1);
2610
2611 if (lpImagePath != NULL)
2612 {
2613 wcscpy(lpStr, lpImagePath);
2614 }
2615 else
2616 {
2617 wcscpy(lpStr, lpEmptyString);
2618 }
2619
2620 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2621 lpStr += (wcslen(lpStr) + 1);
2622
2623 if (lpService->lpGroup != NULL)
2624 {
2625 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2626 }
2627 else
2628 {
2629 wcscpy(lpStr, lpEmptyString);
2630 }
2631
2632 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2633 lpStr += (wcslen(lpStr) + 1);
2634
2635 /* FIXME: Append Dependencies */
2636 wcscpy(lpStr, lpEmptyString);
2637
2638 lpStr += (wcslen(lpStr) + 1);
2639 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2640
2641 if (lpServiceStartName != NULL)
2642 {
2643 wcscpy(lpStr, lpServiceStartName);
2644 }
2645 else
2646 {
2647 wcscpy(lpStr, lpEmptyString);
2648 }
2649
2650 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2651 lpStr += (wcslen(lpStr) + 1);
2652
2653 if (lpService->lpDisplayName != NULL)
2654 {
2655 wcscpy(lpStr, lpService->lpDisplayName);
2656 }
2657 else
2658 {
2659 wcscpy(lpStr, lpEmptyString);
2660 }
2661
2662 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2663 }
2664
2665 if (pcbBytesNeeded != NULL)
2666 *pcbBytesNeeded = dwRequiredSize;
2667
2668 Done:;
2669 if (lpImagePath != NULL)
2670 HeapFree(GetProcessHeap(), 0, lpImagePath);
2671
2672 if (lpServiceStartName != NULL)
2673 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2674
2675 if (hServiceKey != NULL)
2676 RegCloseKey(hServiceKey);
2677
2678 /* FIXME: Unlock the service database */
2679
2680 DPRINT("RQueryServiceConfigW() done\n");
2681
2682 return dwError;
2683 }
2684
2685
2686 /* Function 18 */
2687 DWORD RQueryServiceLockStatusW(
2688 SC_RPC_HANDLE hSCManager,
2689 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2690 DWORD cbBufSize,
2691 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2692 {
2693 UNIMPLEMENTED;
2694 return ERROR_CALL_NOT_IMPLEMENTED;
2695 }
2696
2697
2698 /* Function 19 */
2699 DWORD RStartServiceW(
2700 SC_RPC_HANDLE hService,
2701 DWORD argc,
2702 LPSTRING_PTRSW argv)
2703 {
2704 DWORD dwError = ERROR_SUCCESS;
2705 PSERVICE_HANDLE hSvc;
2706 PSERVICE lpService = NULL;
2707
2708 DPRINT("RStartServiceW() called\n");
2709
2710 if (ScmShutdown)
2711 return ERROR_SHUTDOWN_IN_PROGRESS;
2712
2713 hSvc = (PSERVICE_HANDLE)hService;
2714 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2715 {
2716 DPRINT1("Invalid handle tag!\n");
2717 return ERROR_INVALID_HANDLE;
2718 }
2719
2720 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2721 SERVICE_START))
2722 {
2723 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2724 return ERROR_ACCESS_DENIED;
2725 }
2726
2727 lpService = hSvc->ServiceEntry;
2728 if (lpService == NULL)
2729 {
2730 DPRINT1("lpService == NULL!\n");
2731 return ERROR_INVALID_HANDLE;
2732 }
2733
2734 if (lpService->dwStartType == SERVICE_DISABLED)
2735 return ERROR_SERVICE_DISABLED;
2736
2737 if (lpService->bDeleted)
2738 return ERROR_SERVICE_MARKED_FOR_DELETE;
2739
2740 if (argv) {
2741 UNIMPLEMENTED;
2742 argv = NULL;
2743 }
2744
2745 /* Start the service */
2746 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2747
2748 return dwError;
2749 }
2750
2751
2752 /* Function 20 */
2753 DWORD RGetServiceDisplayNameW(
2754 SC_RPC_HANDLE hSCManager,
2755 LPCWSTR lpServiceName,
2756 LPWSTR lpDisplayName,
2757 DWORD *lpcchBuffer)
2758 {
2759 // PMANAGER_HANDLE hManager;
2760 PSERVICE lpService;
2761 DWORD dwLength;
2762 DWORD dwError;
2763
2764 DPRINT("RGetServiceDisplayNameW() called\n");
2765 DPRINT("hSCManager = %p\n", hSCManager);
2766 DPRINT("lpServiceName: %S\n", lpServiceName);
2767 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2768 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2769
2770 // hManager = (PMANAGER_HANDLE)hSCManager;
2771 // if (hManager->Handle.Tag != MANAGER_TAG)
2772 // {
2773 // DPRINT1("Invalid manager handle!\n");
2774 // return ERROR_INVALID_HANDLE;
2775 // }
2776
2777 /* Get service database entry */
2778 lpService = ScmGetServiceEntryByName(lpServiceName);
2779 if (lpService == NULL)
2780 {
2781 DPRINT1("Could not find a service!\n");
2782
2783 /* If the service could not be found and lpcchBuffer is less than 2, windows
2784 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2785 if (*lpcchBuffer < 2)
2786 {
2787 *lpcchBuffer = 2;
2788 if (lpDisplayName != NULL)
2789 {
2790 *lpDisplayName = '\0';
2791 }
2792 }
2793
2794 return ERROR_SERVICE_DOES_NOT_EXIST;
2795 }
2796
2797 if (!lpService->lpDisplayName)
2798 {
2799 dwLength = wcslen(lpService->lpServiceName);
2800
2801 if (lpDisplayName != NULL &&
2802 *lpcchBuffer > dwLength)
2803 {
2804 wcscpy(lpDisplayName, lpService->lpServiceName);
2805 }
2806 }
2807 else
2808 {
2809 dwLength = wcslen(lpService->lpDisplayName);
2810
2811 if (lpDisplayName != NULL &&
2812 *lpcchBuffer > dwLength)
2813 {
2814 wcscpy(lpDisplayName, lpService->lpDisplayName);
2815 }
2816 }
2817
2818 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2819
2820 *lpcchBuffer = dwLength;
2821
2822 return dwError;
2823 }
2824
2825
2826 /* Function 21 */
2827 DWORD RGetServiceKeyNameW(
2828 SC_RPC_HANDLE hSCManager,
2829 LPCWSTR lpDisplayName,
2830 LPWSTR lpServiceName,
2831 DWORD *lpcchBuffer)
2832 {
2833 // PMANAGER_HANDLE hManager;
2834 PSERVICE lpService;
2835 DWORD dwLength;
2836 DWORD dwError;
2837
2838 DPRINT("RGetServiceKeyNameW() called\n");
2839 DPRINT("hSCManager = %p\n", hSCManager);
2840 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2841 DPRINT("lpServiceName: %p\n", lpServiceName);
2842 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2843
2844 // hManager = (PMANAGER_HANDLE)hSCManager;
2845 // if (hManager->Handle.Tag != MANAGER_TAG)
2846 // {
2847 // DPRINT1("Invalid manager handle!\n");
2848 // return ERROR_INVALID_HANDLE;
2849 // }
2850
2851 /* Get service database entry */
2852 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2853 if (lpService == NULL)
2854 {
2855 DPRINT1("Could not find a service!\n");
2856
2857 /* If the service could not be found and lpcchBuffer is less than 2, windows
2858 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2859 if (*lpcchBuffer < 2)
2860 {
2861 *lpcchBuffer = 2;
2862 if (lpServiceName != NULL)
2863 {
2864 *lpServiceName = '\0';
2865 }
2866 }
2867
2868 return ERROR_SERVICE_DOES_NOT_EXIST;
2869 }
2870
2871 dwLength = wcslen(lpService->lpServiceName);
2872
2873 if (lpServiceName != NULL &&
2874 *lpcchBuffer > dwLength)
2875 {
2876 wcscpy(lpServiceName, lpService->lpServiceName);
2877 *lpcchBuffer = dwLength;
2878 return ERROR_SUCCESS;
2879 }
2880
2881 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2882
2883 *lpcchBuffer = dwLength;
2884
2885 return dwError;
2886 }
2887
2888
2889 /* Function 22 */
2890 DWORD RI_ScSetServiceBitsA(
2891 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
2892 DWORD dwServiceBits,
2893 int bSetBitsOn,
2894 int bUpdateImmediately,
2895 char *lpString)
2896 {
2897 UNIMPLEMENTED;
2898 return ERROR_CALL_NOT_IMPLEMENTED;
2899 }
2900
2901
2902 /* Function 23 */
2903 DWORD RChangeServiceConfigA(
2904 SC_RPC_HANDLE hService,
2905 DWORD dwServiceType,
2906 DWORD dwStartType,
2907 DWORD dwErrorControl,
2908 LPSTR lpBinaryPathName,
2909 LPSTR lpLoadOrderGroup,
2910 LPDWORD lpdwTagId,
2911 LPSTR lpDependencies,
2912 DWORD dwDependSize,
2913 LPSTR lpServiceStartName,
2914 LPBYTE lpPassword,
2915 DWORD dwPwSize,
2916 LPSTR lpDisplayName)
2917 {
2918 DWORD dwError = ERROR_SUCCESS;
2919 PSERVICE_HANDLE hSvc;
2920 PSERVICE lpService = NULL;
2921 HKEY hServiceKey = NULL;
2922 LPWSTR lpDisplayNameW = NULL;
2923 // LPWSTR lpBinaryPathNameW = NULL;
2924 LPWSTR lpLoadOrderGroupW = NULL;
2925 LPWSTR lpDependenciesW = NULL;
2926 // LPWSTR lpPasswordW = NULL;
2927
2928 DPRINT("RChangeServiceConfigA() called\n");
2929 DPRINT("dwServiceType = %lu\n", dwServiceType);
2930 DPRINT("dwStartType = %lu\n", dwStartType);
2931 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2932 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2933 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2934 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2935
2936 if (ScmShutdown)
2937 return ERROR_SHUTDOWN_IN_PROGRESS;
2938
2939 hSvc = (PSERVICE_HANDLE)hService;
2940 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2941 {
2942 DPRINT1("Invalid handle tag!\n");
2943 return ERROR_INVALID_HANDLE;
2944 }
2945
2946 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2947 SERVICE_CHANGE_CONFIG))
2948 {
2949 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2950 return ERROR_ACCESS_DENIED;
2951 }
2952
2953 lpService = hSvc->ServiceEntry;
2954 if (lpService == NULL)
2955 {
2956 DPRINT1("lpService == NULL!\n");
2957 return ERROR_INVALID_HANDLE;
2958 }
2959
2960 /* FIXME: Lock database exclusively */
2961
2962 if (lpService->bDeleted)
2963 {
2964 /* FIXME: Unlock database */
2965 DPRINT1("The service has already been marked for delete!\n");
2966 return ERROR_SERVICE_MARKED_FOR_DELETE;
2967 }
2968
2969 /* Open the service key */
2970 dwError = ScmOpenServiceKey(lpService->szServiceName,
2971 KEY_SET_VALUE,
2972 &hServiceKey);
2973 if (dwError != ERROR_SUCCESS)
2974 goto done;
2975
2976 /* Write service data to the registry */
2977
2978 if (lpDisplayName != NULL && *lpDisplayName != 0)
2979 {
2980 /* Set the display name */
2981 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2982 0,
2983 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
2984 if (lpDisplayNameW == NULL)
2985 {
2986 dwError = ERROR_NOT_ENOUGH_MEMORY;
2987 goto done;
2988 }
2989
2990 MultiByteToWideChar(CP_ACP,
2991 0,
2992 lpDisplayName,
2993 -1,
2994 lpDisplayNameW,
2995 strlen(lpDisplayName) + 1);
2996
2997 RegSetValueExW(hServiceKey,
2998 L"DisplayName",
2999 0,
3000 REG_SZ,
3001 (LPBYTE)lpDisplayNameW,
3002 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3003
3004 /* Update lpService->lpDisplayName */
3005 if (lpService->lpDisplayName)
3006 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3007
3008 lpService->lpDisplayName = lpDisplayNameW;
3009 }
3010
3011 if (dwServiceType != SERVICE_NO_CHANGE)
3012 {
3013 /* Set the service type */
3014 dwError = RegSetValueExW(hServiceKey,
3015 L"Type",
3016 0,
3017 REG_DWORD,
3018 (LPBYTE)&dwServiceType,
3019 sizeof(DWORD));
3020 if (dwError != ERROR_SUCCESS)
3021 goto done;
3022
3023 lpService->Status.dwServiceType = dwServiceType;
3024 }
3025
3026 if (dwStartType != SERVICE_NO_CHANGE)
3027 {
3028 /* Set the start value */
3029 dwError = RegSetValueExW(hServiceKey,
3030 L"Start",
3031 0,
3032 REG_DWORD,
3033 (LPBYTE)&dwStartType,
3034 sizeof(DWORD));
3035 if (dwError != ERROR_SUCCESS)
3036 goto done;
3037
3038 lpService->dwStartType = dwStartType;
3039 }
3040
3041 if (dwErrorControl != SERVICE_NO_CHANGE)
3042 {
3043 /* Set the error control value */
3044 dwError = RegSetValueExW(hServiceKey,
3045 L"ErrorControl",
3046 0,
3047 REG_DWORD,
3048 (LPBYTE)&dwErrorControl,
3049 sizeof(DWORD));
3050 if (dwError != ERROR_SUCCESS)
3051 goto done;
3052
3053 lpService->dwErrorControl = dwErrorControl;
3054 }
3055
3056 #if 0
3057 /* FIXME: set the new ImagePath value */
3058
3059 /* Set the image path */
3060 if (dwServiceType & SERVICE_WIN32)
3061 {
3062 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3063 {
3064 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3065 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
3066 dwError = RegSetValueExW(hServiceKey,
3067 L"ImagePath",
3068 0,
3069 REG_EXPAND_SZ,
3070 (LPBYTE)lpBinaryPathNameW,
3071 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3072 if (dwError != ERROR_SUCCESS)
3073 goto done;
3074 }
3075 }
3076 else if (dwServiceType & SERVICE_DRIVER)
3077 {
3078 if (lpImagePath != NULL && *lpImagePath != 0)
3079 {
3080 dwError = RegSetValueExW(hServiceKey,
3081 L"ImagePath",
3082 0,
3083 REG_EXPAND_SZ,
3084 (LPBYTE)lpImagePath,
3085 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3086 if (dwError != ERROR_SUCCESS)
3087 goto done;
3088 }
3089 }
3090 #endif
3091
3092 /* Set the group name */
3093 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3094 {
3095 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3096 0,
3097 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3098 if (lpLoadOrderGroupW == NULL)
3099 {
3100 dwError = ERROR_NOT_ENOUGH_MEMORY;
3101 goto done;
3102 }
3103
3104 MultiByteToWideChar(CP_ACP,
3105 0,
3106 lpLoadOrderGroup,
3107 -1,
3108 lpLoadOrderGroupW,
3109 strlen(lpLoadOrderGroup) + 1);
3110
3111 dwError = RegSetValueExW(hServiceKey,
3112 L"Group",
3113 0,
3114 REG_SZ,
3115 (LPBYTE)lpLoadOrderGroupW,
3116 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3117 if (dwError != ERROR_SUCCESS)
3118 {
3119 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3120 goto done;
3121 }
3122
3123 dwError = ScmSetServiceGroup(lpService,
3124 lpLoadOrderGroupW);
3125
3126 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3127
3128 if (dwError != ERROR_SUCCESS)
3129 goto done;
3130 }
3131
3132 if (lpdwTagId != NULL)
3133 {
3134 dwError = ScmAssignNewTag(lpService);
3135 if (dwError != ERROR_SUCCESS)
3136 goto done;
3137
3138 dwError = RegSetValueExW(hServiceKey,
3139 L"Tag",
3140 0,
3141 REG_DWORD,
3142 (LPBYTE)&lpService->dwTag,
3143 sizeof(DWORD));
3144 if (dwError != ERROR_SUCCESS)
3145 goto done;
3146
3147 *lpdwTagId = lpService->dwTag;
3148 }
3149
3150 /* Write dependencies */
3151 if (lpDependencies != NULL && *lpDependencies != 0)
3152 {
3153 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3154 0,
3155 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3156 if (lpDependenciesW == NULL)
3157 {
3158 dwError = ERROR_NOT_ENOUGH_MEMORY;
3159 goto done;
3160 }
3161
3162 MultiByteToWideChar(CP_ACP,
3163 0,
3164 lpDependencies,
3165 dwDependSize,
3166 lpDependenciesW,
3167 strlen(lpDependencies) + 1);
3168
3169 dwError = ScmWriteDependencies(hServiceKey,
3170 (LPWSTR)lpDependenciesW,
3171 dwDependSize);
3172
3173 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3174 }
3175
3176 if (lpPassword != NULL)
3177 {
3178 /* FIXME: Write password */
3179 }
3180
3181 /* FIXME: Unlock database */
3182
3183 done:
3184 if (hServiceKey != NULL)
3185 RegCloseKey(hServiceKey);
3186
3187 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3188
3189 return dwError;
3190 }
3191
3192
3193 /* Function 24 */
3194 DWORD RCreateServiceA(
3195 SC_RPC_HANDLE hSCManager,
3196 LPSTR lpServiceName,
3197 LPSTR lpDisplayName,
3198 DWORD dwDesiredAccess,
3199 DWORD dwServiceType,
3200 DWORD dwStartType,
3201 DWORD dwErrorControl,
3202 LPSTR lpBinaryPathName,
3203 LPSTR lpLoadOrderGroup,
3204 LPDWORD lpdwTagId,
3205 LPBYTE lpDependencies,
3206 DWORD dwDependSize,
3207 LPSTR lpServiceStartName,
3208 LPBYTE lpPassword,
3209 DWORD dwPwSize,
3210 LPSC_RPC_HANDLE lpServiceHandle)
3211 {
3212 UNIMPLEMENTED;
3213 return ERROR_CALL_NOT_IMPLEMENTED;
3214 }
3215
3216
3217 /* Function 25 */
3218 DWORD REnumDependentServicesA(
3219 SC_RPC_HANDLE hService,
3220 DWORD dwServiceState,
3221 LPBYTE lpServices,
3222 DWORD cbBufSize,
3223 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3224 LPBOUNDED_DWORD_256K lpServicesReturned)
3225 {
3226 DWORD dwError = ERROR_SUCCESS;
3227 DWORD dwServicesReturned = 0;
3228 DWORD dwServiceCount;
3229 HKEY hServicesKey = NULL;
3230 LPSC_RPC_HANDLE hSCObject;
3231 PSERVICE_HANDLE hSvc;
3232 PSERVICE lpService = NULL;
3233 PSERVICE *lpServicesArray = NULL;
3234 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3235 LPSTR lpStr;
3236
3237 *pcbBytesNeeded = 0;
3238 *lpServicesReturned = 0;
3239
3240 DPRINT("REnumDependentServicesA() called\n");
3241
3242 hSCObject = &hService;
3243 hSvc = (PSERVICE_HANDLE) *hSCObject;
3244 lpService = hSvc->ServiceEntry;
3245
3246 /* Check access rights */
3247 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3248 SC_MANAGER_ENUMERATE_SERVICE))
3249 {
3250 DPRINT1("Insufficient access rights! 0x%lx\n",
3251 hSvc->Handle.DesiredAccess);
3252 return ERROR_ACCESS_DENIED;
3253 }
3254
3255 /* Open the Services Reg key */
3256 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3257 L"System\\CurrentControlSet\\Services",
3258 0,
3259 KEY_READ,
3260 &hServicesKey);
3261
3262 if (dwError != ERROR_SUCCESS)
3263 return dwError;
3264
3265 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3266 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3267 are the same for both. Verified in WINXP. */
3268
3269 /* First determine the bytes needed and get the number of dependent services*/
3270 dwError = Int_EnumDependentServicesW(hServicesKey,
3271 lpService,
3272 dwServiceState,
3273 NULL,
3274 pcbBytesNeeded,
3275 &dwServicesReturned);
3276 if (dwError != ERROR_SUCCESS)
3277 goto Done;
3278
3279 /* If buffer size is less than the bytes needed or pointer is null*/
3280 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3281 {
3282 dwError = ERROR_MORE_DATA;
3283 goto Done;
3284 }
3285
3286 /* Allocate memory for array of service pointers */
3287 lpServicesArray = HeapAlloc(GetProcessHeap(),
3288 0,
3289 (dwServicesReturned + 1) * sizeof(PSERVICE));
3290 if (!lpServicesArray)
3291 {
3292 DPRINT1("Could not allocate a buffer!!\n");
3293 dwError = ERROR_NOT_ENOUGH_MEMORY;
3294 goto Done;
3295 }
3296
3297 dwServicesReturned = 0;
3298 *pcbBytesNeeded = 0;
3299
3300 dwError = Int_EnumDependentServicesW(hServicesKey,
3301 lpService,
3302 dwServiceState,
3303 lpServicesArray,
3304 pcbBytesNeeded,
3305 &dwServicesReturned);
3306 if (dwError != ERROR_SUCCESS)
3307 {
3308 goto Done;
3309 }
3310
3311 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3312 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3313
3314 /* Copy EnumDepenedentService to Buffer */
3315 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3316 {
3317 lpService = lpServicesArray[dwServiceCount];
3318
3319 /* Copy the status info */
3320 memcpy(&lpServicesPtr->ServiceStatus,
3321 &lpService->Status,
3322 sizeof(SERVICE_STATUS));
3323
3324 /* Copy display name */
3325 WideCharToMultiByte(CP_ACP,
3326 0,
3327 lpService->lpDisplayName,
3328 -1,
3329 lpStr,
3330 wcslen(lpService->lpDisplayName),
3331 0,
3332 0);
3333 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3334 lpStr += strlen(lpStr) + 1;
3335
3336 /* Copy service name */
3337 WideCharToMultiByte(CP_ACP,
3338 0,
3339 lpService->lpServiceName,
3340 -1,
3341 lpStr,
3342 wcslen(lpService->lpServiceName),
3343 0,
3344 0);
3345 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3346 lpStr += strlen(lpStr) + 1;
3347
3348 lpServicesPtr ++;
3349 }
3350
3351 *lpServicesReturned = dwServicesReturned;
3352
3353 Done:
3354 if (lpServicesArray)
3355 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3356
3357 RegCloseKey(hServicesKey);
3358
3359 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3360
3361 return dwError;
3362 }
3363
3364
3365 /* Function 26 */
3366 DWORD REnumServicesStatusA(
3367 SC_RPC_HANDLE hSCManager,
3368 DWORD dwServiceType,
3369 DWORD dwServiceState,
3370 LPBYTE lpBuffer,
3371 DWORD dwBufSize,
3372 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3373 LPBOUNDED_DWORD_256K lpServicesReturned,
3374 LPBOUNDED_DWORD_256K lpResumeHandle)
3375 {
3376 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3377 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3378 LPWSTR lpStringPtrW;
3379 LPSTR lpStringPtrA;
3380 DWORD dwError;
3381 DWORD dwServiceCount;
3382
3383 DPRINT("REnumServicesStatusA() called\n");
3384
3385 if ((dwBufSize > 0) && (lpBuffer))
3386 {
3387 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3388 if (!lpStatusPtrW)
3389 {
3390 DPRINT1("Failed to allocate buffer!\n");
3391 return ERROR_NOT_ENOUGH_MEMORY;
3392 }
3393 }
3394
3395 dwError = REnumServicesStatusW(hSCManager,
3396 dwServiceType,
3397 dwServiceState,
3398 (LPBYTE)lpStatusPtrW,
3399 dwBufSize,
3400 pcbBytesNeeded,
3401 lpServicesReturned,
3402 lpResumeHandle);
3403
3404 /* if no services were returned then we are Done */
3405 if (*lpServicesReturned == 0)
3406 goto Done;
3407
3408 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3409 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3410 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3411 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3412 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3413
3414 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3415 {
3416 /* Copy the service name */
3417 WideCharToMultiByte(CP_ACP,
3418 0,
3419 lpStringPtrW,
3420 -1,
3421 lpStringPtrA,
3422 wcslen(lpStringPtrW),
3423 0,
3424 0);
3425
3426 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3427 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3428 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3429
3430 /* Copy the display name */
3431 WideCharToMultiByte(CP_ACP,
3432 0,
3433 lpStringPtrW,
3434 -1,
3435 lpStringPtrA,
3436 wcslen(lpStringPtrW),
3437 0,
3438 0);
3439
3440 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3441 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3442 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3443
3444 /* Copy the status information */
3445 memcpy(&lpStatusPtrA->ServiceStatus,
3446 &lpStatusPtrW->ServiceStatus,
3447 sizeof(SERVICE_STATUS));
3448
3449 lpStatusPtrA++;
3450 }
3451
3452 Done:;
3453 if (lpStatusPtrW)
3454 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3455
3456 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3457
3458 return dwError;
3459 }
3460
3461
3462 /* Function 27 */
3463 DWORD ROpenSCManagerA(
3464 LPSTR lpMachineName,
3465 LPSTR lpDatabaseName,
3466 DWORD dwDesiredAccess,
3467 LPSC_RPC_HANDLE lpScHandle)
3468 {
3469 UNICODE_STRING MachineName;
3470 UNICODE_STRING DatabaseName;
3471 DWORD dwError;
3472
3473 DPRINT("ROpenSCManagerA() called\n");
3474
3475 if (lpMachineName)
3476 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3477 lpMachineName);
3478
3479 if (lpDatabaseName)
3480 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3481 lpDatabaseName);
3482
3483 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3484 lpDatabaseName ? DatabaseName.Buffer : NULL,
3485 dwDesiredAccess,
3486 lpScHandle);
3487
3488 if (lpMachineName)
3489 RtlFreeUnicodeString(&MachineName);
3490
3491 if (lpDatabaseName)
3492 RtlFreeUnicodeString(&DatabaseName);
3493
3494 return dwError;
3495 }
3496
3497
3498 /* Function 28 */
3499 DWORD ROpenServiceA(
3500 SC_RPC_HANDLE hSCManager,
3501 LPSTR lpServiceName,
3502 DWORD dwDesiredAccess,
3503 LPSC_RPC_HANDLE lpServiceHandle)
3504 {
3505 UNICODE_STRING ServiceName;
3506 DWORD dwError;
3507
3508 DPRINT("ROpenServiceA() called\n");
3509
3510 if (lpServiceName)
3511 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3512 lpServiceName);
3513
3514 dwError = ROpenServiceW(hSCManager,
3515 lpServiceName ? ServiceName.Buffer : NULL,
3516 dwDesiredAccess,
3517 lpServiceHandle);
3518
3519 if (lpServiceName)
3520 RtlFreeUnicodeString(&ServiceName);
3521
3522 return dwError;
3523 }
3524
3525
3526 /* Function 29 */
3527 DWORD RQueryServiceConfigA(
3528 SC_RPC_HANDLE hService,
3529 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3530 DWORD cbBufSize,
3531 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3532 {
3533 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3534 DWORD dwError = ERROR_SUCCESS;
3535 PSERVICE_HANDLE hSvc;
3536 PSERVICE lpService = NULL;
3537 HKEY hServiceKey = NULL;
3538 LPWSTR lpImagePath = NULL;
3539 LPWSTR lpServiceStartName = NULL;
3540 DWORD dwRequiredSize;
3541 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3542 CHAR lpEmptyString[]={0,0};
3543 LPSTR lpStr;
3544
3545 DPRINT("RQueryServiceConfigA() called\n");
3546
3547 if (ScmShutdown)
3548 return ERROR_SHUTDOWN_IN_PROGRESS;
3549
3550 hSvc = (PSERVICE_HANDLE)hService;
3551 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3552 {
3553 DPRINT1("Invalid handle tag!\n");
3554 return ERROR_INVALID_HANDLE;
3555 }
3556
3557 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3558 SERVICE_QUERY_CONFIG))
3559 {
3560 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3561 return ERROR_ACCESS_DENIED;
3562 }
3563
3564 lpService = hSvc->ServiceEntry;
3565 if (lpService == NULL)
3566 {
3567 DPRINT1("lpService == NULL!\n");
3568 return ERROR_INVALID_HANDLE;
3569 }
3570
3571 /* FIXME: Lock the service database shared */
3572
3573 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3574 KEY_READ,
3575 &hServiceKey);
3576 if (dwError != ERROR_SUCCESS)
3577 goto Done;
3578
3579 dwError = ScmReadString(hServiceKey,
3580 L"ImagePath",
3581 &lpImagePath);
3582 if (dwError != ERROR_SUCCESS)
3583 goto Done;
3584
3585 ScmReadString(hServiceKey,
3586 L"ObjectName",
3587 &lpServiceStartName);
3588
3589 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3590
3591 if (lpImagePath != NULL)
3592 dwRequiredSize += wcslen(lpImagePath) + 1;
3593 else
3594 dwRequiredSize += 2;
3595
3596 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3597 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
3598 else
3599 dwRequiredSize += 2;
3600
3601 /* FIXME: Add Dependencies length*/
3602 dwRequiredSize += 2;
3603
3604 if (lpServiceStartName != NULL)
3605 dwRequiredSize += wcslen(lpServiceStartName) + 1;
3606 else
3607 dwRequiredSize += 2;
3608
3609 if (lpService->lpDisplayName != NULL)
3610 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
3611 else
3612 dwRequiredSize += 2;
3613
3614 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3615 {
3616 dwError = ERROR_INSUFFICIENT_BUFFER;
3617 }
3618 else
3619 {
3620 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
3621 lpConfig->dwServiceType = lpService->Status.dwServiceType;
3622 lpConfig->dwStartType = lpService->dwStartType;
3623 lpConfig->dwErrorControl = lpService->dwErrorControl;
3624 lpConfig->dwTagId = lpService->dwTag;
3625
3626 lpStr = (LPSTR)(lpServiceConfig + 1);
3627
3628 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3629 Verified in WINXP*/
3630
3631 if (lpImagePath)
3632 {
3633 WideCharToMultiByte(CP_ACP,
3634 0,
3635 lpImagePath,
3636 -1,
3637 lpStr,
3638 wcslen(lpImagePath)+1,
3639 0,
3640 0);
3641 }
3642 else
3643 {
3644 strcpy(lpStr, lpEmptyString);
3645 }
3646
3647 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3648 lpStr += (strlen((LPSTR)lpStr) + 1);
3649
3650 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
3651 {
3652 WideCharToMultiByte(CP_ACP,
3653 0,
3654 lpService->lpGroup->lpGroupName,
3655 -1,
3656 lpStr,
3657 wcslen(lpService->lpGroup->lpGroupName)+1,
3658 0,
3659 0);
3660 }
3661 else
3662 {
3663 strcpy(lpStr, lpEmptyString);
3664 }
3665
3666 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3667 lpStr += (strlen(lpStr) + 1);
3668
3669 /* FIXME: Append Dependencies */
3670 strcpy(lpStr, lpEmptyString);
3671
3672 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3673 lpStr += (strlen(lpStr) + 1);
3674
3675 if (lpServiceStartName)
3676 {
3677 WideCharToMultiByte(CP_ACP,
3678 0,
3679 lpServiceStartName,
3680 -1,
3681 lpStr,
3682 wcslen(lpServiceStartName)+1,
3683 0,
3684 0);
3685 }
3686 else
3687 {
3688 strcpy(lpStr, lpEmptyString);
3689 }
3690
3691 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3692 lpStr += (strlen(lpStr) + 1);
3693
3694 if (lpService->lpDisplayName)
3695 {
3696 WideCharToMultiByte(CP_ACP,
3697 0,
3698 lpService->lpDisplayName,
3699 -1,
3700 lpStr,
3701 wcslen(lpService->lpDisplayName)+1,
3702 0,
3703 0);
3704 }
3705 else
3706 {
3707 strcpy(lpStr, lpEmptyString);
3708 }
3709
3710 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3711 }
3712
3713 if (pcbBytesNeeded != NULL)
3714 *pcbBytesNeeded = dwRequiredSize;
3715
3716 Done:;
3717 if (lpImagePath != NULL)
3718 HeapFree(GetProcessHeap(), 0, lpImagePath);
3719
3720 if (lpServiceStartName != NULL)
3721 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3722
3723 if (hServiceKey != NULL)
3724 RegCloseKey(hServiceKey);
3725
3726 /* FIXME: Unlock the service database */
3727
3728 DPRINT("RQueryServiceConfigA() done\n");
3729
3730 return dwError;
3731 }
3732
3733
3734 /* Function 30 */
3735 DWORD RQueryServiceLockStatusA(
3736 SC_RPC_HANDLE hSCManager,
3737 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
3738 DWORD cbBufSize,
3739 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3740 {
3741 UNIMPLEMENTED;
3742 return ERROR_CALL_NOT_IMPLEMENTED;
3743 }
3744
3745
3746 /* Function 31 */
3747 DWORD RStartServiceA(
3748 SC_RPC_HANDLE hService,
3749 DWORD argc,
3750 LPSTRING_PTRSA argv)
3751 {
3752 DWORD dwError = ERROR_SUCCESS;
3753 PSERVICE_HANDLE hSvc;
3754 PSERVICE lpService = NULL;
3755
3756 DPRINT1("RStartServiceA() called\n");
3757
3758 if (ScmShutdown)
3759 return ERROR_SHUTDOWN_IN_PROGRESS;
3760
3761 hSvc = (PSERVICE_HANDLE)hService;
3762 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3763 {
3764 DPRINT1("Invalid handle tag!\n");
3765 return ERROR_INVALID_HANDLE;
3766 }
3767
3768 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3769 SERVICE_START))
3770 {
3771 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3772 return ERROR_ACCESS_DENIED;
3773 }
3774
3775 lpService = hSvc->ServiceEntry;
3776 if (lpService == NULL)
3777 {
3778 DPRINT1("lpService == NULL!\n");
3779 return ERROR_INVALID_HANDLE;
3780 }
3781
3782 if (lpService->dwStartType == SERVICE_DISABLED)
3783 return ERROR_SERVICE_DISABLED;
3784
3785 if (lpService->bDeleted)
3786 return ERROR_SERVICE_MARKED_FOR_DELETE;
3787
3788 /* FIXME: Convert argument vector to Unicode */
3789
3790 /* Start the service */
3791 dwError = ScmStartService(lpService, 0, NULL);
3792
3793 /* FIXME: Free argument vector */
3794
3795 return dwError;
3796 }
3797
3798
3799 /* Function 32 */
3800 DWORD RGetServiceDisplayNameA(
3801 SC_RPC_HANDLE hSCManager,
3802 LPCSTR lpServiceName,
3803 LPSTR lpDisplayName,
3804 LPBOUNDED_DWORD_4K lpcchBuffer)
3805 {
3806 // PMANAGER_HANDLE hManager;
3807 PSERVICE lpService = NULL;
3808 DWORD dwLength;
3809 DWORD dwError;
3810 LPWSTR lpServiceNameW;
3811
3812 DPRINT("RGetServiceDisplayNameA() called\n");
3813 DPRINT("hSCManager = %p\n", hSCManager);
3814 DPRINT("lpServiceName: %s\n", lpServiceName);
3815 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3816 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3817
3818 // hManager = (PMANAGER_HANDLE)hSCManager;
3819 // if (hManager->Handle.Tag != MANAGER_TAG)
3820 // {
3821 // DPRINT1("Invalid manager handle!\n");
3822 // return ERROR_INVALID_HANDLE;
3823 // }
3824
3825 if (lpServiceName != NULL)
3826 {
3827 dwLength = strlen(lpServiceName) + 1;
3828 lpServiceNameW = HeapAlloc(GetProcessHeap(),
3829 HEAP_ZERO_MEMORY,
3830 dwLength * sizeof(WCHAR));
3831 if (!lpServiceNameW)
3832 return ERROR_NOT_ENOUGH_MEMORY;
3833
3834 MultiByteToWideChar(CP_ACP,
3835 0,
3836 lpServiceName,
3837 -1,
3838 lpServiceNameW,
3839 dwLength);
3840
3841 lpService = ScmGetServiceEntryByName(lpServiceNameW);
3842
3843 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3844 }
3845
3846 if (lpService == NULL)
3847 {
3848 DPRINT1("Could not find a service!\n");
3849
3850 /* If the service could not be found and lpcchBuffer is 0, windows
3851 puts null in lpDisplayName and puts 1 in lpcchBuffer */
3852 if (*lpcchBuffer == 0)
3853 {
3854 *lpcchBuffer = 1;
3855 if (lpDisplayName != NULL)
3856 {
3857 *lpDisplayName = '\0';
3858 }
3859 }
3860 return ERROR_SERVICE_DOES_NOT_EXIST;
3861 }
3862
3863 if (!lpService->lpDisplayName)
3864 {
3865 dwLength = wcslen(lpService->lpServiceName);
3866 if (lpDisplayName != NULL &&
3867 *lpcchBuffer > dwLength)
3868 {
3869 WideCharToMultiByte(CP_ACP,
3870 0,
3871 lpService->lpServiceName,
3872 wcslen(lpService->lpServiceName),
3873 lpDisplayName,
3874 dwLength + 1,
3875 NULL,
3876 NULL);
3877 return ERROR_SUCCESS;
3878 }
3879 }
3880 else
3881 {
3882 dwLength = wcslen(lpService->lpDisplayName);
3883 if (lpDisplayName != NULL &&
3884 *lpcchBuffer > dwLength)
3885 {
3886 WideCharToMultiByte(CP_ACP,
3887 0,
3888 lpService->lpDisplayName,
3889 wcslen(lpService->lpDisplayName),
3890 lpDisplayName,
3891 dwLength + 1,
3892 NULL,
3893 NULL);
3894 return ERROR_SUCCESS;
3895 }
3896 }
3897
3898 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3899
3900 *lpcchBuffer = dwLength * 2;
3901
3902 return dwError;
3903 }
3904
3905
3906 /* Function 33 */
3907 DWORD RGetServiceKeyNameA(
3908 SC_RPC_HANDLE hSCManager,
3909 LPCSTR lpDisplayName,
3910 LPSTR lpServiceName,
3911 LPBOUNDED_DWORD_4K lpcchBuffer)
3912 {
3913 PSERVICE lpService;
3914 DWORD dwLength;
3915 DWORD dwError;
3916 LPWSTR lpDisplayNameW;
3917
3918 DPRINT("RGetServiceKeyNameA() called\n");
3919 DPRINT("hSCManager = %p\n", hSCManager);
3920 DPRINT("lpDisplayName: %s\n", lpDisplayName);
3921 DPRINT("lpServiceName: %p\n", lpServiceName);
3922 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3923
3924 dwLength = strlen(lpDisplayName) + 1;
3925 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3926 HEAP_ZERO_MEMORY,
3927 dwLength * sizeof(WCHAR));
3928 if (!lpDisplayNameW)
3929 return ERROR_NOT_ENOUGH_MEMORY;
3930
3931 MultiByteToWideChar(CP_ACP,
3932 0,
3933 lpDisplayName,
3934 -1,
3935 lpDisplayNameW,
3936 dwLength);
3937
3938 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
3939
3940 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3941
3942 if (lpService == NULL)
3943 {
3944 DPRINT1("Could not find the service!\n");
3945
3946 /* If the service could not be found and lpcchBuffer is 0,
3947 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
3948 if (*lpcchBuffer == 0)
3949 {
3950 *lpcchBuffer = 1;
3951 if (lpServiceName != NULL)
3952 {
3953 *lpServiceName = '\0';
3954 }
3955 }
3956
3957 return ERROR_SERVICE_DOES_NOT_EXIST;
3958 }
3959
3960 dwLength = wcslen(lpService->lpServiceName);
3961 if (lpServiceName != NULL &&
3962 *lpcchBuffer > dwLength)
3963 {
3964 WideCharToMultiByte(CP_ACP,
3965 0,
3966 lpService->lpServiceName,
3967 wcslen(lpService->lpServiceName),
3968 lpServiceName,
3969 dwLength + 1,
3970 NULL,
3971 NULL);
3972 return ERROR_SUCCESS;
3973 }
3974
3975 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3976
3977 *lpcchBuffer = dwLength * 2;
3978
3979 return dwError;
3980 }
3981
3982
3983 /* Function 34 */
3984 DWORD RI_ScGetCurrentGroupStateW(
3985 SC_RPC_HANDLE hSCManager,
3986 LPWSTR lpLoadOrderGroup,
3987 LPDWORD lpState)
3988 {
3989 UNIMPLEMENTED;
3990 return ERROR_CALL_NOT_IMPLEMENTED;
3991 }
3992
3993
3994 /* Function 35 */
3995 DWORD REnumServiceGroupW(
3996 SC_RPC_HANDLE hSCManager,
3997 DWORD dwServiceType,
3998 DWORD dwServiceState,
3999 LPBYTE lpBuffer,
4000 DWORD cbBufSize,
4001 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4002 LPBOUNDED_DWORD_256K lpServicesReturned,
4003 LPBOUNDED_DWORD_256K lpResumeIndex,
4004 LPCWSTR pszGroupName)
4005 {
4006 UNIMPLEMENTED;
4007 return ERROR_CALL_NOT_IMPLEMENTED;
4008 }
4009
4010
4011 //
4012 // WARNING: This function is untested
4013 //
4014 /* Function 36 */
4015 DWORD RChangeServiceConfig2A(
4016 SC_RPC_HANDLE hService,
4017 SC_RPC_CONFIG_INFOA Info)
4018 {
4019 SC_RPC_CONFIG_INFOW InfoW;
4020 DWORD dwRet, dwLength;
4021 PVOID ptr = NULL;
4022
4023 DPRINT("RChangeServiceConfig2A() called\n");
4024 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4025
4026 InfoW.dwInfoLevel = Info.dwInfoLevel;
4027
4028 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4029 {
4030 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4031 LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4032
4033 lpServiceDescriptonA = Info.psd;
4034
4035 ///if (lpServiceDescriptonA &&
4036 ///lpServiceDescriptonA->lpDescription)
4037 ///{
4038 dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
4039
4040 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4041 0,
4042 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4043 if (!lpServiceDescriptonW)
4044 {
4045 return ERROR_NOT_ENOUGH_MEMORY;
4046 }
4047
4048 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4049
4050 MultiByteToWideChar(CP_ACP,
4051 0,
4052 Info.lpDescription,
4053 -1,
4054 lpServiceDescriptonW->lpDescription,
4055 dwLength);
4056
4057 ptr = lpServiceDescriptonW;
4058 InfoW.psd = lpServiceDescriptonW;
4059 ///}
4060 }
4061 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4062 {
4063 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4064 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4065 DWORD dwRebootLen = 0;
4066 DWORD dwCommandLen = 0;
4067
4068 lpServiceFailureActionsA = Info.psfa;
4069
4070 if (lpServiceFailureActionsA)
4071 {
4072 if (lpServiceFailureActionsA->lpRebootMsg)
4073 {
4074 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4075 }
4076 if (lpServiceFailureActionsA->lpCommand)
4077 {
4078 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4079 }
4080 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4081
4082 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4083 0,
4084 dwLength);
4085 if (!lpServiceFailureActionsW)
4086 {
4087 return ERROR_NOT_ENOUGH_MEMORY;
4088 }
4089
4090 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4091 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4092 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4093
4094 if (lpServiceFailureActionsA->lpRebootMsg)
4095 {
4096 MultiByteToWideChar(CP_ACP,
4097 0,
4098 lpServiceFailureActionsA->lpRebootMsg,
4099 -1,
4100 lpServiceFailureActionsW->lpRebootMsg,
4101 dwRebootLen);
4102 }
4103
4104 if (lpServiceFailureActionsA->lpCommand)
4105 {
4106 MultiByteToWideChar(CP_ACP,
4107 0,
4108 lpServiceFailureActionsA->lpCommand,
4109 -1,
4110 lpServiceFailureActionsW->lpCommand,
4111 dwCommandLen);
4112 }
4113
4114 ptr = lpServiceFailureActionsW;
4115 }
4116 }
4117
4118 dwRet = RChangeServiceConfig2W(hService, InfoW);
4119
4120 HeapFree(GetProcessHeap(), 0, ptr);
4121
4122 return dwRet;
4123 }
4124
4125
4126 /* Function 37 */
4127 DWORD RChangeServiceConfig2W(
4128 SC_RPC_HANDLE hService,
4129 SC_RPC_CONFIG_INFOW Info)
4130 {
4131 DWORD dwError = ERROR_SUCCESS;
4132 PSERVICE_HANDLE hSvc;
4133 PSERVICE lpService = NULL;
4134 HKEY hServiceKey = NULL;
4135
4136 DPRINT("RChangeServiceConfig2W() called\n");
4137 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4138
4139 if (ScmShutdown)
4140 return ERROR_SHUTDOWN_IN_PROGRESS;
4141
4142 hSvc = (PSERVICE_HANDLE)hService;
4143 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4144 {
4145 DPRINT1("Invalid handle tag!\n");
4146 return ERROR_INVALID_HANDLE;
4147 }
4148
4149 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4150 SERVICE_CHANGE_CONFIG))
4151 {
4152 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4153 return ERROR_ACCESS_DENIED;
4154 }
4155
4156 lpService = hSvc->ServiceEntry;
4157 if (lpService == NULL)
4158 {
4159 DPRINT1("lpService == NULL!\n");
4160 return ERROR_INVALID_HANDLE;
4161 }
4162
4163 /* FIXME: Lock database exclusively */
4164
4165 if (lpService->bDeleted)
4166 {
4167 /* FIXME: Unlock database */
4168 DPRINT1("The service has already been marked for delete!\n");
4169 return ERROR_SERVICE_MARKED_FOR_DELETE;
4170 }
4171
4172 /* Open the service key */
4173 dwError = ScmOpenServiceKey(lpService->szServiceName,
4174 KEY_SET_VALUE,
4175 &hServiceKey);
4176 if (dwError != ERROR_SUCCESS)
4177 goto done;
4178
4179 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4180 {
4181 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4182
4183 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
4184 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
4185
4186 if (lpServiceDescription != NULL &&
4187 lpServiceDescription->lpDescription != NULL)
4188 {
4189 DPRINT1("Setting value %S\n", lpServiceDescription->lpDescription);
4190 RegSetValueExW(hServiceKey,
4191 L"Description",
4192 0,
4193 REG_SZ,
4194 (LPBYTE)lpServiceDescription->lpDescription,
4195 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4196
4197 if (dwError != ERROR_SUCCESS)
4198 goto done;
4199 }
4200 }
4201 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4202 {
4203 UNIMPLEMENTED;
4204 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4205 goto done;
4206 }
4207
4208 done:
4209 /* FIXME: Unlock database */
4210 if (hServiceKey != NULL)
4211 RegCloseKey(hServiceKey);
4212
4213 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4214
4215 return dwError;
4216 }
4217
4218
4219 /* Function 38 */
4220 DWORD RQueryServiceConfig2A(
4221 SC_RPC_HANDLE hService,
4222 DWORD dwInfoLevel,
4223 LPBYTE lpBuffer,
4224 DWORD cbBufSize,
4225 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4226 {
4227 DWORD dwError = ERROR_SUCCESS;
4228 PSERVICE_HANDLE hSvc;
4229 PSERVICE lpService = NULL;
4230 HKEY hServiceKey = NULL;
4231 LPWSTR lpDescriptionW = NULL;
4232 LPSTR lpDescription = NULL;
4233
4234 DPRINT1("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
4235
4236 if (!lpBuffer)
4237 return ERROR_INVALID_ADDRESS;
4238
4239 if (ScmShutdown)
4240 return ERROR_SHUTDOWN_IN_PROGRESS;
4241
4242 hSvc = (PSERVICE_HANDLE)hService;
4243 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4244 {
4245 DPRINT1("Invalid handle tag!\n");
4246 return ERROR_INVALID_HANDLE;
4247 }
4248
4249 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4250 SERVICE_QUERY_CONFIG))
4251 {
4252 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4253 return ERROR_ACCESS_DENIED;
4254 }
4255
4256 lpService = hSvc->ServiceEntry;
4257 if (lpService == NULL)
4258 {
4259 DPRINT1("lpService == NULL!\n");
4260 return ERROR_INVALID_HANDLE;
4261 }
4262
4263 /* FIXME: Lock the service database shared */
4264
4265 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4266 KEY_READ,
4267 &hServiceKey);
4268 if (dwError != ERROR_SUCCESS)
4269 goto done;
4270
4271 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4272 {
4273 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4274 LPSTR lpStr;
4275
4276 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4277
4278 dwError = ScmReadString(hServiceKey,
4279 L"Description",
4280 &lpDescriptionW);
4281 if (dwError == ERROR_SUCCESS)
4282 {
4283 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
4284 }
4285
4286 if (cbBufSize >= *pcbBytesNeeded)
4287 {
4288
4289 if (dwError == ERROR_SUCCESS)
4290 {
4291 lpStr = (LPSTR)(lpServiceDescription + 1);
4292
4293 WideCharToMultiByte(CP_ACP,
4294 0,
4295 lpDescriptionW,
4296 -1,
4297 lpStr,
4298 wcslen(lpDescriptionW),
4299 NULL,
4300 NULL);
4301 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4302 }
4303 else
4304 {
4305 lpServiceDescription->lpDescription = NULL;
4306 goto done;
4307 }
4308 }
4309 else
4310 {
4311 dwError = ERROR_INSUFFICIENT_BUFFER;
4312 goto done;
4313 }
4314 }
4315 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4316 {
4317 UNIMPLEMENTED;
4318 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4319 goto done;
4320 }
4321
4322 done:
4323 if (lpDescription != NULL)
4324 HeapFree(GetProcessHeap(), 0, lpDescription);
4325
4326 if (hServiceKey != NULL)
4327 RegCloseKey(hServiceKey);
4328
4329 /* FIXME: Unlock database */
4330
4331 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4332
4333 return dwError;
4334 }
4335
4336
4337 /* Function 39 */
4338 DWORD RQueryServiceConfig2W(
4339 SC_RPC_HANDLE hService,
4340 DWORD dwInfoLevel,
4341 LPBYTE lpBuffer,
4342 DWORD cbBufSize,
4343 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4344 {
4345 DWORD dwError = ERROR_SUCCESS;
4346 PSERVICE_HANDLE hSvc;
4347 PSERVICE lpService = NULL;
4348 HKEY hServiceKey = NULL;
4349 DWORD dwRequiredSize;
4350 LPWSTR lpDescription = NULL;
4351 LPWSTR lpFailureCommand = NULL;
4352 LPWSTR lpRebootMessage = NULL;
4353
4354 DPRINT("RQueryServiceConfig2W() called\n");
4355
4356 if (!lpBuffer)
4357 return ERROR_INVALID_ADDRESS;
4358
4359 if (ScmShutdown)
4360 return ERROR_SHUTDOWN_IN_PROGRESS;
4361
4362 hSvc = (PSERVICE_HANDLE)hService;
4363 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4364 {
4365 DPRINT1("Invalid handle tag!\n");
4366 return ERROR_INVALID_HANDLE;
4367 }
4368
4369 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4370 SERVICE_QUERY_CONFIG))
4371 {
4372 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4373 return ERROR_ACCESS_DENIED;
4374 }
4375
4376 lpService = hSvc->ServiceEntry;
4377 if (lpService == NULL)
4378 {
4379 DPRINT1("lpService == NULL!\n");
4380 return ERROR_INVALID_HANDLE;
4381 }
4382
4383 /* FIXME: Lock the service database shared */
4384
4385 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4386 KEY_READ,
4387 &hServiceKey);
4388 if (dwError != ERROR_SUCCESS)
4389 goto done;
4390
4391 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4392 {
4393 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4394 LPWSTR lpStr;
4395
4396 dwError = ScmReadString(hServiceKey,
4397 L"Description",
4398 &lpDescription);
4399 if (dwError != ERROR_SUCCESS)
4400 goto done;
4401
4402 dwRequiredSize = sizeof(SERVICE_DESCRIPTIONW) + ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4403
4404 if (cbBufSize < dwRequiredSize)
4405 {
4406 *pcbBytesNeeded = dwRequiredSize;
4407 dwError = ERROR_INSUFFICIENT_BUFFER;
4408 goto done;
4409 }
4410
4411 lpStr = (LPWSTR)(lpServiceDescription + 1);
4412 wcscpy(lpStr, lpDescription);
4413 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4414 }
4415 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4416 {
4417 LPWSTR lpStr;
4418 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
4419
4420 UNIMPLEMENTED;
4421
4422 dwError = ScmReadString(hServiceKey,
4423 L"FailureCommand",
4424 &lpFailureCommand);
4425
4426 dwError = ScmReadString(hServiceKey,
4427 L"RebootMessage",
4428 &lpRebootMessage);
4429
4430 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
4431
4432 if (lpFailureCommand)
4433 dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
4434
4435 if (lpRebootMessage)
4436 dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
4437
4438 if (cbBufSize < dwRequiredSize)
4439 {
4440 *pcbBytesNeeded = dwRequiredSize;
4441 dwError = ERROR_INSUFFICIENT_BUFFER;
4442 goto done;
4443 }
4444
4445 lpFailureActions->cActions = 0;
4446 lpFailureActions->dwResetPeriod = 0;
4447 lpFailureActions->lpCommand = NULL;
4448 lpFailureActions->lpRebootMsg = NULL;
4449 lpFailureActions->lpsaActions = NULL;
4450
4451 lpStr = (LPWSTR)(lpFailureActions + 1);
4452 if (lpRebootMessage)
4453 {
4454 wcscpy(lpStr, lpRebootMessage);
4455 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
4456 lpStr += wcslen(lpRebootMessage) + 1;
4457 }
4458
4459 if (lpFailureCommand)
4460 {
4461 wcscpy(lpStr, lpFailureCommand);
4462 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
4463 lpStr += wcslen(lpRebootMessage) + 1;
4464 }
4465 dwError = STATUS_SUCCESS;
4466 goto done;
4467 }
4468
4469 done:
4470 if (lpDescription != NULL)
4471 HeapFree(GetProcessHeap(), 0, lpDescription);
4472
4473 if (lpRebootMessage != NULL)
4474 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
4475
4476 if (lpFailureCommand != NULL)
4477 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
4478
4479 if (hServiceKey != NULL)
4480 RegCloseKey(hServiceKey);
4481
4482 /* FIXME: Unlock database */
4483
4484 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4485
4486 return dwError;
4487 }
4488
4489
4490 /* Function 40 */
4491 DWORD RQueryServiceStatusEx(
4492 SC_RPC_HANDLE hService,
4493 SC_STATUS_TYPE InfoLevel,
4494 LPBYTE lpBuffer,
4495 DWORD cbBufSize,
4496 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4497 {
4498 LPSERVICE_STATUS_PROCESS lpStatus;
4499 PSERVICE_HANDLE hSvc;
4500 PSERVICE lpService;
4501
4502 DPRINT("RQueryServiceStatusEx() called\n");
4503
4504 if (ScmShutdown)
4505 return ERROR_SHUTDOWN_IN_PROGRESS;
4506
4507 if (InfoLevel != SC_STATUS_PROCESS_INFO)
4508 return ERROR_INVALID_LEVEL;
4509
4510 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
4511
4512 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
4513 return ERROR_INSUFFICIENT_BUFFER;
4514
4515 hSvc = (PSERVICE_HANDLE)hService;
4516 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4517 {
4518 DPRINT1("Invalid handle tag!\n");
4519 return ERROR_INVALID_HANDLE;
4520 }
4521
4522 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4523 SERVICE_QUERY_STATUS))
4524 {
4525 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4526 return ERROR_ACCESS_DENIED;
4527 }
4528
4529 lpService = hSvc->ServiceEntry;
4530 if (lpService == NULL)
4531 {
4532 DPRINT1("lpService == NULL!\n");
4533 return ERROR_INVALID_HANDLE;
4534 }
4535
4536 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
4537
4538 /* Return service status information */
4539 RtlCopyMemory(lpStatus,
4540 &lpService->Status,
4541 sizeof(SERVICE_STATUS));
4542
4543 lpStatus->dwProcessId = lpService->ProcessId; /* FIXME */
4544 lpStatus->dwServiceFlags = 0; /* FIXME */
4545
4546 return ERROR_SUCCESS;
4547 }
4548
4549
4550 /* Function 41 */
4551 DWORD REnumServicesStatusExA(
4552 SC_RPC_HANDLE hSCManager,
4553 SC_ENUM_TYPE InfoLevel,
4554 DWORD dwServiceType,
4555 DWORD dwServiceState,
4556 LPBYTE lpBuffer,
4557 DWORD cbBufSize,
4558 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4559 LPBOUNDED_DWORD_256K lpServicesReturned,
4560 LPBOUNDED_DWORD_256K lpResumeIndex,
4561 LPCSTR pszGroupName)
4562 {
4563 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
4564 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
4565 LPWSTR lpStringPtrW;
4566 LPSTR lpStringPtrA;
4567 LPWSTR pszGroupNameW = NULL;
4568 DWORD dwError;
4569 DWORD dwServiceCount;
4570
4571 DPRINT("REnumServicesStatusExA() called\n");
4572
4573 if (pszGroupName)
4574 {
4575 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
4576 if (!pszGroupNameW)
4577 {
4578 DPRINT1("Failed to allocate buffer!\n");
4579 return ERROR_NOT_ENOUGH_MEMORY;
4580 }
4581 MultiByteToWideChar(CP_ACP,
4582 0,
4583 pszGroupName,
4584 -1,
4585 pszGroupNameW,
4586 strlen(pszGroupName) + 1);
4587 }
4588
4589 if ((cbBufSize > 0) && (lpBuffer))
4590 {
4591 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
4592 if (!lpStatusPtrW)
4593 {
4594 DPRINT1("Failed to allocate buffer!\n");
4595 return ERROR_NOT_ENOUGH_MEMORY;
4596 }
4597 }
4598
4599 dwError = REnumServicesStatusExW(hSCManager,
4600 InfoLevel,
4601 dwServiceType,
4602 dwServiceState,
4603 (LPBYTE)lpStatusPtrW,
4604 cbBufSize,
4605 pcbBytesNeeded,
4606 lpServicesReturned,
4607 lpResumeIndex,
4608 pszGroupNameW);
4609
4610 /* if no services were returned then we are Done */
4611 if (*lpServicesReturned == 0) goto Done;
4612
4613 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
4614 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
4615 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
4616 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
4617 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4618
4619 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
4620 {
4621 /* Copy the service name */
4622 WideCharToMultiByte(CP_ACP,
4623 0,
4624 lpStringPtrW,
4625 -1,
4626 lpStringPtrA,
4627 wcslen(lpStringPtrW),
4628 0,
4629 0);
4630
4631 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4632 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4633 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4634
4635 /* Copy the display name */
4636 WideCharToMultiByte(CP_ACP,
4637 0,
4638 lpStringPtrW,
4639 -1,
4640 lpStringPtrA,
4641 wcslen(lpStringPtrW),
4642 0,
4643 0);
4644
4645 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4646 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4647 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4648
4649 /* Copy the status information */
4650 memcpy(&lpStatusPtrA->ServiceStatusProcess,
4651 &lpStatusPtrW->ServiceStatusProcess,
4652 sizeof(SERVICE_STATUS));
4653
4654 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
4655 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4656 lpStatusPtrA++;
4657 }
4658
4659 Done:;
4660 if (pszGroupNameW) HeapFree(GetProcessHeap(), 0, pszGroupNameW);
4661
4662 if (lpStatusPtrW) HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
4663
4664 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
4665
4666 return dwError;
4667 }
4668
4669
4670 /* Function 42 */
4671 DWORD REnumServicesStatusExW(
4672 SC_RPC_HANDLE hSCManager,
4673 SC_ENUM_TYPE InfoLevel,
4674 DWORD dwServiceType,
4675 DWORD dwServiceState,
4676 LPBYTE lpBuffer,
4677 DWORD cbBufSize,
4678 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4679 LPBOUNDED_DWORD_256K lpServicesReturned,
4680 LPBOUNDED_DWORD_256K lpResumeIndex,
4681 LPCWSTR pszGroupName)
4682 {
4683 PMANAGER_HANDLE hManager;
4684 PSERVICE lpService;
4685 DWORD dwError = ERROR_SUCCESS;
4686 PLIST_ENTRY ServiceEntry;
4687 PSERVICE CurrentService;
4688 DWORD dwState;
4689 DWORD dwRequiredSize;
4690 DWORD dwServiceCount;
4691 DWORD dwSize;
4692 DWORD dwLastResumeCount = 0;
4693 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
4694 LPWSTR lpStringPtr;
4695
4696 DPRINT("REnumServicesStatusExW() called\n");
4697
4698 if (ScmShutdown)
4699 return ERROR_SHUTDOWN_IN_PROGRESS;
4700
4701 if (InfoLevel != SC_ENUM_PROCESS_INFO)
4702 return ERROR_INVALID_LEVEL;
4703
4704 hManager = (PMANAGER_HANDLE)hSCManager;
4705 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
4706 {
4707 DPRINT1("Invalid manager handle!\n");
4708 return ERROR_INVALID_HANDLE;
4709 }
4710
4711 *pcbBytesNeeded = 0;
4712 *lpServicesReturned = 0;
4713
4714 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
4715 {
4716 DPRINT1("Not a valid Service Type!\n");
4717 return ERROR_INVALID_PARAMETER;
4718 }
4719
4720 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
4721 {
4722 DPRINT1("Not a valid Service State!\n");
4723 return ERROR_INVALID_PARAMETER;
4724 }
4725
4726 /* Check access rights */
4727 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4728 SC_MANAGER_ENUMERATE_SERVICE))
4729 {
4730 DPRINT1("Insufficient access rights! 0x%lx\n",
4731 hManager->Handle.DesiredAccess);
4732 return ERROR_ACCESS_DENIED;
4733 }
4734
4735 if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
4736
4737 /* Lock the service list shared */
4738
4739 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4740 if (lpService == NULL)
4741 {
4742 dwError = ERROR_SUCCESS;
4743 goto Done;
4744 }
4745
4746 dwRequiredSize = 0;
4747 dwServiceCount = 0;
4748
4749 for (ServiceEntry = &lpService->ServiceListEntry;
4750 ServiceEntry != &ServiceListHead;
4751 ServiceEntry = ServiceEntry->Flink)
4752 {
4753 CurrentService = CONTAINING_RECORD(ServiceEntry,
4754 SERVICE,
4755 ServiceListEntry);
4756
4757 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4758 continue;
4759
4760 dwState = SERVICE_ACTIVE;
4761 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4762 dwState = SERVICE_INACTIVE;
4763
4764 if ((dwState & dwServiceState) == 0)
4765 continue;
4766
4767 if (pszGroupName)
4768 {
4769 if (*pszGroupName == 0)
4770 {
4771 if (CurrentService->lpGroup != NULL)
4772 continue;
4773 }
4774 else
4775 {
4776 if ((CurrentService->lpGroup == NULL) ||
4777 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4778 continue;
4779 }
4780 }
4781
4782 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4783 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4784 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4785
4786 if (dwRequiredSize + dwSize <= cbBufSize)
4787 {
4788 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4789 dwRequiredSize += dwSize;
4790 dwServiceCount++;
4791 dwLastResumeCount = CurrentService->dwResumeCount;
4792 }
4793 else
4794 {
4795 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4796 break;
4797 }
4798
4799 }
4800
4801 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4802 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4803
4804 for (;
4805 ServiceEntry != &ServiceListHead;
4806 ServiceEntry = ServiceEntry->Flink)
4807 {
4808 CurrentService = CONTAINING_RECORD(ServiceEntry,
4809 SERVICE,
4810 ServiceListEntry);
4811
4812 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4813 continue;
4814
4815 dwState = SERVICE_ACTIVE;
4816 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4817 dwState = SERVICE_INACTIVE;
4818
4819 if ((dwState & dwServiceState) == 0)
4820 continue;
4821
4822 if (pszGroupName)
4823 {
4824 if (*pszGroupName == 0)
4825 {
4826 if (CurrentService->lpGroup != NULL)
4827 continue;
4828 }
4829 else
4830 {
4831 if ((CurrentService->lpGroup == NULL) ||
4832 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4833 continue;
4834 }
4835 }
4836
4837 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4838 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4839 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4840
4841 dwError = ERROR_MORE_DATA;
4842 }
4843
4844 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4845
4846 if (lpResumeIndex) *lpResumeIndex = dwLastResumeCount;
4847 *lpServicesReturned = dwServiceCount;
4848 *pcbBytesNeeded = dwRequiredSize;
4849
4850 /* If there was no services that matched */
4851 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
4852 {
4853 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4854 goto Done;
4855 }
4856
4857 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
4858 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4859 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4860
4861 dwRequiredSize = 0;
4862 for (ServiceEntry = &lpService->ServiceListEntry;
4863 ServiceEntry != &ServiceListHead;
4864 ServiceEntry = ServiceEntry->Flink)
4865 {
4866 CurrentService = CONTAINING_RECORD(ServiceEntry,
4867 SERVICE,
4868 ServiceListEntry);
4869
4870 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4871 continue;
4872
4873 dwState = SERVICE_ACTIVE;
4874 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4875 dwState = SERVICE_INACTIVE;
4876
4877 if ((dwState & dwServiceState) == 0)
4878 continue;
4879
4880 if (pszGroupName)
4881 {
4882 if (*pszGroupName == 0)
4883 {
4884 if (CurrentService->lpGroup != NULL)
4885 continue;
4886 }
4887 else
4888 {
4889 if ((CurrentService->lpGroup == NULL) ||
4890 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4891 continue;
4892 }
4893 }
4894
4895 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4896 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4897 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4898
4899 if (dwRequiredSize + dwSize <= cbBufSize)
4900 {
4901 /* Copy the service name */
4902 wcscpy(lpStringPtr,
4903 CurrentService->lpServiceName);
4904 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4905 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4906
4907 /* Copy the display name */
4908 wcscpy(lpStringPtr,
4909 CurrentService->lpDisplayName);
4910 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4911 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4912
4913 /* Copy the status information */
4914 memcpy(&lpStatusPtr->ServiceStatusProcess,
4915 &CurrentService->Status,
4916 sizeof(SERVICE_STATUS));
4917 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
4918 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4919
4920 lpStatusPtr++;
4921 dwRequiredSize += dwSize;
4922 }
4923 else
4924 {
4925 break;
4926 }
4927 }
4928
4929 if (dwError == 0)
4930 {
4931 *pcbBytesNeeded = 0;
4932 if (lpResumeIndex) *lpResumeIndex = 0;
4933 }
4934
4935 Done:;
4936 /* Unlock the service list */
4937
4938 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
4939
4940 return dwError;
4941 }
4942
4943
4944 /* Function 43 */
4945 DWORD RSendTSMessage(
4946 handle_t BindingHandle) /* FIXME */
4947 {
4948 UNIMPLEMENTED;
4949 return ERROR_CALL_NOT_IMPLEMENTED;
4950 }
4951
4952
4953 /* Function 44 */
4954 DWORD RCreateServiceWOW64A(
4955 handle_t BindingHandle,
4956 LPSTR lpServiceName,
4957 LPSTR lpDisplayName,
4958 DWORD dwDesiredAccess,
4959 DWORD dwServiceType,
4960 DWORD dwStartType,
4961 DWORD dwErrorControl,
4962 LPSTR lpBinaryPathName,
4963 LPSTR lpLoadOrderGroup,
4964 LPDWORD lpdwTagId,
4965 LPBYTE lpDependencies,
4966 DWORD dwDependSize,
4967 LPSTR lpServiceStartName,
4968 LPBYTE lpPassword,
4969 DWORD dwPwSize,
4970 LPSC_RPC_HANDLE lpServiceHandle)
4971 {
4972 UNIMPLEMENTED;
4973 return ERROR_CALL_NOT_IMPLEMENTED;
4974 }
4975
4976
4977 /* Function 45 */
4978 DWORD RCreateServiceWOW64W(
4979 handle_t BindingHandle,
4980 LPWSTR lpServiceName,
4981 LPWSTR lpDisplayName,
4982 DWORD dwDesiredAccess,
4983 DWORD dwServiceType,
4984 DWORD dwStartType,
4985 DWORD dwErrorControl,
4986 LPWSTR lpBinaryPathName,
4987 LPWSTR lpLoadOrderGroup,
4988 LPDWORD lpdwTagId,
4989 LPBYTE lpDependencies,
4990 DWORD dwDependSize,
4991 LPWSTR lpServiceStartName,
4992 LPBYTE lpPassword,
4993 DWORD dwPwSize,
4994 LPSC_RPC_HANDLE lpServiceHandle)
4995 {
4996 UNIMPLEMENTED;
4997 return ERROR_CALL_NOT_IMPLEMENTED;
4998 }
4999
5000
5001 /* Function 46 */
5002 DWORD RQueryServiceTagInfo(
5003 handle_t BindingHandle) /* FIXME */
5004 {
5005 UNIMPLEMENTED;
5006 return ERROR_CALL_NOT_IMPLEMENTED;
5007 }
5008
5009
5010 /* Function 47 */
5011 DWORD RNotifyServiceStatusChange(
5012 SC_RPC_HANDLE hService,
5013 SC_RPC_NOTIFY_PARAMS NotifyParams,
5014 GUID *pClientProcessGuid,
5015 GUID *pSCMProcessGuid,
5016 PBOOL pfCreateRemoteQueue,
5017 LPSC_NOTIFY_RPC_HANDLE phNotify)
5018 {
5019 UNIMPLEMENTED;
5020 return ERROR_CALL_NOT_IMPLEMENTED;
5021 }
5022
5023
5024 /* Function 48 */
5025 DWORD RGetNotifyResults(
5026 SC_NOTIFY_RPC_HANDLE hNotify,
5027 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5028 {
5029 UNIMPLEMENTED;
5030 return ERROR_CALL_NOT_IMPLEMENTED;
5031 }
5032
5033
5034 /* Function 49 */
5035 DWORD RCloseNotifyHandle(
5036 LPSC_NOTIFY_RPC_HANDLE phNotify,
5037 PBOOL pfApcFired)
5038 {
5039 UNIMPLEMENTED;
5040 return ERROR_CALL_NOT_IMPLEMENTED;
5041 }
5042
5043
5044 /* Function 50 */
5045 DWORD RControlServiceExA(
5046 SC_RPC_HANDLE hService,
5047 DWORD dwControl,
5048 DWORD dwInfoLevel)
5049 {
5050 UNIMPLEMENTED;
5051 return ERROR_CALL_NOT_IMPLEMENTED;
5052 }
5053
5054
5055 /* Function 51 */
5056 DWORD RControlServiceExW(
5057 SC_RPC_HANDLE hService,
5058 DWORD dwControl,
5059 DWORD dwInfoLevel)
5060 {
5061 UNIMPLEMENTED;
5062 return ERROR_CALL_NOT_IMPLEMENTED;
5063 }
5064
5065
5066 /* Function 52 */
5067 DWORD RSendPnPMessage(
5068 handle_t BindingHandle) /* FIXME */
5069 {
5070 UNIMPLEMENTED;
5071 return ERROR_CALL_NOT_IMPLEMENTED;
5072 }
5073
5074
5075 /* Function 53 */
5076 DWORD RValidatePnPService(
5077 handle_t BindingHandle) /* FIXME */
5078 {
5079 UNIMPLEMENTED;
5080 return ERROR_CALL_NOT_IMPLEMENTED;
5081 }
5082
5083
5084 /* Function 54 */
5085 DWORD ROpenServiceStatusHandle(
5086 handle_t BindingHandle) /* FIXME */
5087 {
5088 UNIMPLEMENTED;
5089 return ERROR_CALL_NOT_IMPLEMENTED;
5090 }
5091
5092
5093 /* Function 55 */
5094 DWORD RFunction55(
5095 handle_t BindingHandle) /* FIXME */
5096 {
5097 UNIMPLEMENTED;
5098 return ERROR_CALL_NOT_IMPLEMENTED;
5099 }
5100
5101
5102 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
5103 {
5104 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5105 }
5106
5107
5108 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5109 {
5110 HeapFree(GetProcessHeap(), 0, ptr);
5111 }
5112
5113
5114 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5115 {
5116 }
5117
5118
5119 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5120 {
5121 }
5122
5123
5124 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5125 {
5126 }
5127
5128 /* EOF */