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