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