- Implement REnumServicesStatusExA
[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 != ERROR_MORE_DATA)
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 PMANAGER_HANDLE hManager;
3379 PSERVICE lpService;
3380 DWORD dwError = ERROR_SUCCESS;
3381 PLIST_ENTRY ServiceEntry;
3382 PSERVICE CurrentService;
3383 DWORD dwState;
3384 DWORD dwRequiredSize;
3385 DWORD dwServiceCount;
3386 DWORD dwSize;
3387 DWORD dwLastResumeCount = 0;
3388 LPENUM_SERVICE_STATUSA lpStatusPtr;
3389 LPSTR lpStringPtr;
3390
3391 DPRINT("REnumServicesStatusA() called\n");
3392
3393 if (ScmShutdown)
3394 return ERROR_SHUTDOWN_IN_PROGRESS;
3395
3396 hManager = (PMANAGER_HANDLE)hSCManager;
3397 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
3398 {
3399 DPRINT1("Invalid manager handle!\n");
3400 return ERROR_INVALID_HANDLE;
3401 }
3402
3403 *pcbBytesNeeded = 0;
3404 *lpServicesReturned = 0;
3405
3406 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
3407 {
3408 DPRINT1("Not a valid Service Type!\n");
3409 return ERROR_INVALID_PARAMETER;
3410 }
3411
3412 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
3413 {
3414 DPRINT1("Not a valid Service State!\n");
3415 return ERROR_INVALID_PARAMETER;
3416 }
3417
3418 /* Check access rights */
3419 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
3420 SC_MANAGER_ENUMERATE_SERVICE))
3421 {
3422 DPRINT1("Insufficient access rights! 0x%lx\n",
3423 hManager->Handle.DesiredAccess);
3424 return ERROR_ACCESS_DENIED;
3425 }
3426
3427 if (lpResumeHandle) dwLastResumeCount = *lpResumeHandle;
3428
3429 /* FIXME: Lock the service list shared */
3430
3431 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
3432 if (lpService == NULL)
3433 {
3434 dwError = ERROR_SUCCESS;
3435 goto Done;
3436 }
3437
3438 dwRequiredSize = 0;
3439 dwServiceCount = 0;
3440
3441 for (ServiceEntry = &lpService->ServiceListEntry;
3442 ServiceEntry != &ServiceListHead;
3443 ServiceEntry = ServiceEntry->Flink)
3444 {
3445 CurrentService = CONTAINING_RECORD(ServiceEntry,
3446 SERVICE,
3447 ServiceListEntry);
3448
3449 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
3450 continue;
3451
3452 dwState = SERVICE_ACTIVE;
3453 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
3454 dwState = SERVICE_INACTIVE;
3455
3456 if ((dwState & dwServiceState) == 0)
3457 continue;
3458
3459 dwSize = sizeof(ENUM_SERVICE_STATUSA) +
3460 wcslen(CurrentService->lpServiceName) + 1 +
3461 wcslen(CurrentService->lpDisplayName) + 1;
3462
3463 if (dwRequiredSize + dwSize > dwBufSize)
3464 {
3465 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
3466 break;
3467 }
3468
3469 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
3470 dwRequiredSize += dwSize;
3471 dwServiceCount++;
3472 dwLastResumeCount = CurrentService->dwResumeCount;
3473 }
3474
3475 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
3476 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
3477
3478 for (;
3479 ServiceEntry != &ServiceListHead;
3480 ServiceEntry = ServiceEntry->Flink)
3481 {
3482 CurrentService = CONTAINING_RECORD(ServiceEntry,
3483 SERVICE,
3484 ServiceListEntry);
3485
3486 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
3487 continue;
3488
3489 dwState = SERVICE_ACTIVE;
3490 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
3491 dwState = SERVICE_INACTIVE;
3492
3493 if ((dwState & dwServiceState) == 0)
3494 continue;
3495
3496 dwRequiredSize += sizeof(ENUM_SERVICE_STATUSA) +
3497 wcslen(CurrentService->lpServiceName) + 1 +
3498 wcslen(CurrentService->lpDisplayName) + 1;
3499
3500 dwError = ERROR_MORE_DATA;
3501 }
3502
3503 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
3504
3505 if (lpResumeHandle) *lpResumeHandle = dwLastResumeCount;
3506 *lpServicesReturned = dwServiceCount;
3507 *pcbBytesNeeded = dwRequiredSize;
3508
3509 lpStatusPtr = (LPENUM_SERVICE_STATUSA)lpBuffer;
3510 lpStringPtr = (LPSTR)((ULONG_PTR)lpBuffer +
3511 dwServiceCount * sizeof(ENUM_SERVICE_STATUSA));
3512
3513 dwRequiredSize = 0;
3514 for (ServiceEntry = &lpService->ServiceListEntry;
3515 ServiceEntry != &ServiceListHead;
3516 ServiceEntry = ServiceEntry->Flink)
3517 {
3518 CurrentService = CONTAINING_RECORD(ServiceEntry,
3519 SERVICE,
3520 ServiceListEntry);
3521
3522 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
3523 continue;
3524
3525 dwState = SERVICE_ACTIVE;
3526 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
3527 dwState = SERVICE_INACTIVE;
3528
3529 if ((dwState & dwServiceState) == 0)
3530 continue;
3531
3532 dwSize = sizeof(ENUM_SERVICE_STATUSA) +
3533 wcslen(CurrentService->lpServiceName) + 1 +
3534 wcslen(CurrentService->lpDisplayName) + 1;
3535
3536 if (dwRequiredSize + dwSize > dwBufSize)
3537 break;
3538
3539 /* Copy the service name */
3540 WideCharToMultiByte(CP_ACP,
3541 0,
3542 CurrentService->lpServiceName,
3543 -1,
3544 lpStringPtr,
3545 wcslen(CurrentService->lpServiceName),
3546 0,
3547 0);
3548 lpStatusPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
3549 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
3550
3551 /* Copy the display name */
3552 WideCharToMultiByte(CP_ACP,
3553 0,
3554 CurrentService->lpDisplayName,
3555 -1,
3556 lpStringPtr,
3557 wcslen(CurrentService->lpDisplayName),
3558 0,
3559 0);
3560 lpStatusPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
3561 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
3562
3563 /* Copy the status information */
3564 memcpy(&lpStatusPtr->ServiceStatus,
3565 &CurrentService->Status,
3566 sizeof(SERVICE_STATUS));
3567
3568 lpStatusPtr++;
3569 dwRequiredSize += dwSize;
3570 }
3571
3572 if (dwError != ERROR_MORE_DATA)
3573 {
3574 *pcbBytesNeeded = 0;
3575 if (lpResumeHandle) *lpResumeHandle = 0;
3576 }
3577
3578 Done:;
3579 /* FIXME: Unlock the service list */
3580
3581 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3582
3583 return dwError;
3584 }
3585
3586
3587 /* Function 27 */
3588 DWORD ROpenSCManagerA(
3589 handle_t BindingHandle,
3590 LPSTR lpMachineName,
3591 LPSTR lpDatabaseName,
3592 DWORD dwDesiredAccess,
3593 LPSC_RPC_HANDLE lpScHandle)
3594 {
3595 UNICODE_STRING MachineName;
3596 UNICODE_STRING DatabaseName;
3597 DWORD dwError;
3598
3599 DPRINT("ROpenSCManagerA() called\n");
3600
3601 if (lpMachineName)
3602 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3603 lpMachineName);
3604
3605 if (lpDatabaseName)
3606 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3607 lpDatabaseName);
3608
3609 dwError = ROpenSCManagerW(BindingHandle,
3610 lpMachineName ? MachineName.Buffer : NULL,
3611 lpDatabaseName ? DatabaseName.Buffer : NULL,
3612 dwDesiredAccess,
3613 lpScHandle);
3614
3615 if (lpMachineName)
3616 RtlFreeUnicodeString(&MachineName);
3617
3618 if (lpDatabaseName)
3619 RtlFreeUnicodeString(&DatabaseName);
3620
3621 return dwError;
3622 }
3623
3624
3625 /* Function 28 */
3626 DWORD ROpenServiceA(
3627 handle_t BindingHandle,
3628 SC_RPC_HANDLE hSCManager,
3629 LPSTR lpServiceName,
3630 DWORD dwDesiredAccess,
3631 LPSC_RPC_HANDLE lpServiceHandle)
3632 {
3633 UNICODE_STRING ServiceName;
3634 DWORD dwError;
3635
3636 DPRINT("ROpenServiceA() called\n");
3637
3638 if (lpServiceName)
3639 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3640 lpServiceName);
3641
3642 dwError = ROpenServiceW(BindingHandle,
3643 hSCManager,
3644 lpServiceName ? ServiceName.Buffer : NULL,
3645 dwDesiredAccess,
3646 lpServiceHandle);
3647
3648 if (lpServiceName)
3649 RtlFreeUnicodeString(&ServiceName);
3650
3651 return dwError;
3652 }
3653
3654
3655 /* Function 29 */
3656 DWORD RQueryServiceConfigA(
3657 handle_t BindingHandle,
3658 SC_RPC_HANDLE hService,
3659 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3660 DWORD cbBufSize,
3661 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3662 {
3663 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3664 DWORD dwError = ERROR_SUCCESS;
3665 PSERVICE_HANDLE hSvc;
3666 PSERVICE lpService = NULL;
3667 HKEY hServiceKey = NULL;
3668 LPWSTR lpImagePath = NULL;
3669 LPWSTR lpServiceStartName = NULL;
3670 DWORD dwRequiredSize;
3671 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3672 CHAR lpEmptyString[]={0,0};
3673 LPSTR lpStr;
3674
3675 DPRINT("RQueryServiceConfigA() called\n");
3676
3677 if (ScmShutdown)
3678 return ERROR_SHUTDOWN_IN_PROGRESS;
3679
3680 hSvc = (PSERVICE_HANDLE)hService;
3681 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3682 {
3683 DPRINT1("Invalid handle tag!\n");
3684 return ERROR_INVALID_HANDLE;
3685 }
3686
3687 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3688 SERVICE_QUERY_CONFIG))
3689 {
3690 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3691 return ERROR_ACCESS_DENIED;
3692 }
3693
3694 lpService = hSvc->ServiceEntry;
3695 if (lpService == NULL)
3696 {
3697 DPRINT1("lpService == NULL!\n");
3698 return ERROR_INVALID_HANDLE;
3699 }
3700
3701 /* FIXME: Lock the service database shared */
3702
3703 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3704 KEY_READ,
3705 &hServiceKey);
3706 if (dwError != ERROR_SUCCESS)
3707 goto Done;
3708
3709 dwError = ScmReadString(hServiceKey,
3710 L"ImagePath",
3711 &lpImagePath);
3712 if (dwError != ERROR_SUCCESS)
3713 goto Done;
3714
3715 ScmReadString(hServiceKey,
3716 L"ObjectName",
3717 &lpServiceStartName);
3718
3719 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3720
3721 if (lpImagePath != NULL)
3722 dwRequiredSize += wcslen(lpImagePath) + 1;
3723 else
3724 dwRequiredSize += 2;
3725
3726 if (lpService->lpGroup != NULL)
3727 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
3728 else
3729 dwRequiredSize += 2;
3730
3731 /* FIXME: Add Dependencies length*/
3732 dwRequiredSize += 2;
3733
3734 if (lpServiceStartName != NULL)
3735 dwRequiredSize += wcslen(lpServiceStartName) + 1;
3736 else
3737 dwRequiredSize += 2;
3738
3739 if (lpService->lpDisplayName != NULL)
3740 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
3741 else
3742 dwRequiredSize += 2;
3743
3744 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3745 {
3746 dwError = ERROR_INSUFFICIENT_BUFFER;
3747 }
3748 else
3749 {
3750 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
3751 lpConfig->dwServiceType = lpService->Status.dwServiceType;
3752 lpConfig->dwStartType = lpService->dwStartType;
3753 lpConfig->dwErrorControl = lpService->dwErrorControl;
3754 lpConfig->dwTagId = lpService->dwTag;
3755
3756 lpStr = (LPSTR)(lpServiceConfig + 1);
3757
3758 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3759 Verified in WINXP*/
3760
3761 if (lpImagePath)
3762 {
3763 WideCharToMultiByte(CP_ACP,
3764 0,
3765 lpImagePath,
3766 -1,
3767 lpStr,
3768 wcslen(lpImagePath),
3769 0,
3770 0);
3771 }
3772 else
3773 {
3774 strcpy(lpStr, lpEmptyString);
3775 }
3776
3777 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3778 lpStr += (strlen((LPSTR)lpStr) + 1);
3779
3780 if (lpService->lpGroup)
3781 {
3782 WideCharToMultiByte(CP_ACP,
3783 0,
3784 lpService->lpGroup->lpGroupName,
3785 -1,
3786 lpStr,
3787 wcslen(lpService->lpGroup->lpGroupName),
3788 0,
3789 0);
3790 }
3791 else
3792 {
3793 strcpy(lpStr, lpEmptyString);
3794 }
3795
3796 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3797 lpStr += (strlen(lpStr) + 1);
3798
3799 /* FIXME: Append Dependencies */
3800 strcpy(lpStr, lpEmptyString);
3801
3802 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3803 lpStr += (strlen(lpStr) + 1);
3804
3805 if (lpServiceStartName)
3806 {
3807 WideCharToMultiByte(CP_ACP,
3808 0,
3809 lpServiceStartName,
3810 -1,
3811 lpStr,
3812 wcslen(lpServiceStartName),
3813 0,
3814 0);
3815 }
3816 else
3817 {
3818 strcpy(lpStr, lpEmptyString);
3819 }
3820
3821 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3822 lpStr += (strlen(lpStr) + 1);
3823
3824 if (lpService->lpDisplayName)
3825 {
3826 WideCharToMultiByte(CP_ACP,
3827 0,
3828 lpService->lpDisplayName,
3829 -1,
3830 lpStr,
3831 wcslen(lpService->lpDisplayName),
3832 0,
3833 0);
3834 }
3835 else
3836 {
3837 strcpy(lpStr, lpEmptyString);
3838 }
3839
3840 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3841 }
3842
3843 if (pcbBytesNeeded != NULL)
3844 *pcbBytesNeeded = dwRequiredSize;
3845
3846 Done:;
3847 if (lpImagePath != NULL)
3848 HeapFree(GetProcessHeap(), 0, lpImagePath);
3849
3850 if (lpServiceStartName != NULL)
3851 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3852
3853 if (hServiceKey != NULL)
3854 RegCloseKey(hServiceKey);
3855
3856 /* FIXME: Unlock the service database */
3857
3858 DPRINT("RQueryServiceConfigA() done\n");
3859
3860 return dwError;
3861 }
3862
3863
3864 /* Function 30 */
3865 DWORD RQueryServiceLockStatusA(
3866 handle_t BindingHandle,
3867 SC_RPC_HANDLE hSCManager,
3868 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
3869 DWORD cbBufSize,
3870 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3871 {
3872 UNIMPLEMENTED;
3873 return ERROR_CALL_NOT_IMPLEMENTED;
3874 }
3875
3876
3877 /* Function 31 */
3878 DWORD RStartServiceA(
3879 handle_t BindingHandle,
3880 SC_RPC_HANDLE hService,
3881 DWORD argc,
3882 LPSTRING_PTRSA argv)
3883 {
3884 DWORD dwError = ERROR_SUCCESS;
3885 PSERVICE_HANDLE hSvc;
3886 PSERVICE lpService = NULL;
3887
3888 DPRINT1("RStartServiceA() called\n");
3889
3890 if (ScmShutdown)
3891 return ERROR_SHUTDOWN_IN_PROGRESS;
3892
3893 hSvc = (PSERVICE_HANDLE)hService;
3894 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3895 {
3896 DPRINT1("Invalid handle tag!\n");
3897 return ERROR_INVALID_HANDLE;
3898 }
3899
3900 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3901 SERVICE_START))
3902 {
3903 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3904 return ERROR_ACCESS_DENIED;
3905 }
3906
3907 lpService = hSvc->ServiceEntry;
3908 if (lpService == NULL)
3909 {
3910 DPRINT1("lpService == NULL!\n");
3911 return ERROR_INVALID_HANDLE;
3912 }
3913
3914 if (lpService->dwStartType == SERVICE_DISABLED)
3915 return ERROR_SERVICE_DISABLED;
3916
3917 if (lpService->bDeleted)
3918 return ERROR_SERVICE_MARKED_FOR_DELETE;
3919
3920 /* FIXME: Convert argument vector to Unicode */
3921
3922 /* Start the service */
3923 dwError = ScmStartService(lpService, 0, NULL);
3924
3925 /* FIXME: Free argument vector */
3926
3927 return dwError;
3928 }
3929
3930
3931 /* Function 32 */
3932 DWORD RGetServiceDisplayNameA(
3933 handle_t BindingHandle,
3934 SC_RPC_HANDLE hSCManager,
3935 LPSTR lpServiceName,
3936 LPSTR lpDisplayName,
3937 LPBOUNDED_DWORD_4K lpcchBuffer)
3938 {
3939 // PMANAGER_HANDLE hManager;
3940 PSERVICE lpService;
3941 DWORD dwLength;
3942 DWORD dwError;
3943 LPWSTR lpServiceNameW;
3944
3945 DPRINT("RGetServiceDisplayNameA() called\n");
3946 DPRINT("hSCManager = %p\n", hSCManager);
3947 DPRINT("lpServiceName: %s\n", lpServiceName);
3948 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3949 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3950
3951 // hManager = (PMANAGER_HANDLE)hSCManager;
3952 // if (hManager->Handle.Tag != MANAGER_TAG)
3953 // {
3954 // DPRINT1("Invalid manager handle!\n");
3955 // return ERROR_INVALID_HANDLE;
3956 // }
3957
3958 dwLength = strlen(lpServiceName) + 1;
3959 lpServiceNameW = HeapAlloc(GetProcessHeap(),
3960 HEAP_ZERO_MEMORY,
3961 dwLength * sizeof(WCHAR));
3962 if (!lpServiceNameW)
3963 return ERROR_NOT_ENOUGH_MEMORY;
3964
3965 MultiByteToWideChar(CP_ACP,
3966 0,
3967 lpServiceName,
3968 strlen(lpServiceName),
3969 lpServiceNameW,
3970 dwLength);
3971
3972 lpService = ScmGetServiceEntryByName(lpServiceNameW);
3973
3974 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3975
3976 if (lpService == NULL)
3977 {
3978 DPRINT1("Could not find a service!\n");
3979
3980 /* If the service could not be found and lpcchBuffer is 0, windows
3981 puts null in lpDisplayName and puts 1 in lpcchBuffer */
3982 if (*lpcchBuffer == 0)
3983 {
3984 *lpcchBuffer = 1;
3985 *lpDisplayName = '\0';
3986 }
3987 return ERROR_SERVICE_DOES_NOT_EXIST;
3988 }
3989
3990 if (!lpService->lpDisplayName)
3991 {
3992 dwLength = wcslen(lpService->lpServiceName);
3993 if (lpServiceName != NULL &&
3994 *lpcchBuffer > dwLength)
3995 {
3996 WideCharToMultiByte(CP_ACP,
3997 0,
3998 lpService->lpServiceName,
3999 wcslen(lpService->lpServiceName),
4000 lpDisplayName,
4001 *lpcchBuffer,
4002 NULL,
4003 NULL);
4004 return ERROR_SUCCESS;
4005 }
4006 }
4007 else
4008 {
4009 dwLength = wcslen(lpService->lpDisplayName);
4010 if (lpDisplayName != NULL &&
4011 *lpcchBuffer > dwLength)
4012 {
4013 WideCharToMultiByte(CP_ACP,
4014 0,
4015 lpService->lpDisplayName,
4016 wcslen(lpService->lpDisplayName),
4017 lpDisplayName,
4018 *lpcchBuffer,
4019 NULL,
4020 NULL);
4021 return ERROR_SUCCESS;
4022 }
4023 }
4024
4025 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4026
4027 *lpcchBuffer = dwLength * 2;
4028
4029 return dwError;
4030 }
4031
4032
4033 /* Function 33 */
4034 DWORD RGetServiceKeyNameA(
4035 handle_t BindingHandle,
4036 SC_RPC_HANDLE hSCManager,
4037 LPSTR lpDisplayName,
4038 LPSTR lpServiceName,
4039 LPBOUNDED_DWORD_4K lpcchBuffer)
4040 {
4041 PSERVICE lpService;
4042 DWORD dwLength;
4043 DWORD dwError;
4044 LPWSTR lpDisplayNameW;
4045
4046 DPRINT("RGetServiceKeyNameA() called\n");
4047 DPRINT("hSCManager = %p\n", hSCManager);
4048 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4049 DPRINT("lpServiceName: %p\n", lpServiceName);
4050 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4051
4052 dwLength = strlen(lpDisplayName) + 1;
4053 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4054 HEAP_ZERO_MEMORY,
4055 dwLength * sizeof(WCHAR));
4056 if (!lpDisplayNameW)
4057 return ERROR_NOT_ENOUGH_MEMORY;
4058
4059 MultiByteToWideChar(CP_ACP,
4060 0,
4061 lpDisplayName,
4062 strlen(lpDisplayName),
4063 lpDisplayNameW,
4064 dwLength);
4065
4066 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4067
4068 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4069
4070 if (lpService == NULL)
4071 {
4072 DPRINT1("Could not find the service!\n");
4073
4074 /* If the service could not be found and lpcchBuffer is 0,
4075 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4076 if (*lpcchBuffer == 0)
4077 {
4078 *lpcchBuffer = 1;
4079 *lpServiceName = '\0';
4080 }
4081
4082 return ERROR_SERVICE_DOES_NOT_EXIST;
4083 }
4084
4085 dwLength = wcslen(lpService->lpServiceName);
4086 if (lpService != NULL &&
4087 *lpcchBuffer > dwLength)
4088 {
4089 WideCharToMultiByte(CP_ACP,
4090 0,
4091 lpService->lpServiceName,
4092 wcslen(lpService->lpServiceName),
4093 lpServiceName,
4094 dwLength,
4095 NULL,
4096 NULL);
4097 return ERROR_SUCCESS;
4098 }
4099
4100 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4101
4102 *lpcchBuffer = dwLength * 2;
4103
4104 return dwError;
4105 }
4106
4107
4108 /* Function 34 */
4109 DWORD RI_ScGetCurrentGroupStateW(
4110 handle_t BindingHandle,
4111 SC_RPC_HANDLE hSCManager,
4112 LPWSTR lpLoadOrderGroup,
4113 LPDWORD lpState)
4114 {
4115 UNIMPLEMENTED;
4116 return ERROR_CALL_NOT_IMPLEMENTED;
4117 }
4118
4119
4120 /* Function 35 */
4121 DWORD REnumServiceGroupW(
4122 handle_t BindingHandle,
4123 SC_RPC_HANDLE hSCManager,
4124 DWORD dwServiceType,
4125 DWORD dwServiceState,
4126 LPBYTE lpBuffer,
4127 DWORD cbBufSize,
4128 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4129 LPBOUNDED_DWORD_256K lpServicesReturned,
4130 LPBOUNDED_DWORD_256K lpResumeIndex,
4131 LPCWSTR pszGroupName)
4132 {
4133 UNIMPLEMENTED;
4134 return ERROR_CALL_NOT_IMPLEMENTED;
4135 }
4136
4137
4138 /* Function 36 */
4139 DWORD RChangeServiceConfig2A(
4140 handle_t BindingHandle,
4141 SC_RPC_HANDLE hService,
4142 SC_RPC_CONFIG_INFOA Info)
4143 {
4144 UNIMPLEMENTED;
4145 return ERROR_CALL_NOT_IMPLEMENTED;
4146 }
4147
4148
4149 /* Function 37 */
4150 DWORD RChangeServiceConfig2W(
4151 handle_t BindingHandle,
4152 SC_RPC_HANDLE hService,
4153 SC_RPC_CONFIG_INFOW Info)
4154 {
4155 DWORD dwError = ERROR_SUCCESS;
4156 PSERVICE_HANDLE hSvc;
4157 PSERVICE lpService = NULL;
4158 HKEY hServiceKey = NULL;
4159
4160 DPRINT("RChangeServiceConfig2W() called\n");
4161 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4162
4163 if (ScmShutdown)
4164 return ERROR_SHUTDOWN_IN_PROGRESS;
4165
4166 hSvc = (PSERVICE_HANDLE)hService;
4167 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4168 {
4169 DPRINT1("Invalid handle tag!\n");
4170 return ERROR_INVALID_HANDLE;
4171 }
4172
4173 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4174 SERVICE_CHANGE_CONFIG))
4175 {
4176 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4177 return ERROR_ACCESS_DENIED;
4178 }
4179
4180 lpService = hSvc->ServiceEntry;
4181 if (lpService == NULL)
4182 {
4183 DPRINT1("lpService == NULL!\n");
4184 return ERROR_INVALID_HANDLE;
4185 }
4186
4187 /* FIXME: Lock database exclusively */
4188
4189 if (lpService->bDeleted)
4190 {
4191 /* FIXME: Unlock database */
4192 DPRINT1("The service has already been marked for delete!\n");
4193 return ERROR_SERVICE_MARKED_FOR_DELETE;
4194 }
4195
4196 /* Open the service key */
4197 dwError = ScmOpenServiceKey(lpService->szServiceName,
4198 KEY_SET_VALUE,
4199 &hServiceKey);
4200 if (dwError != ERROR_SUCCESS)
4201 goto done;
4202
4203 if (Info.dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4204 {
4205 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4206
4207 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)&Info;
4208 lpServiceDescription->lpDescription = (LPWSTR)(&Info + sizeof(LPSERVICE_DESCRIPTIONW));
4209
4210 if (lpServiceDescription != NULL &&
4211 lpServiceDescription->lpDescription != NULL)
4212 {
4213 RegSetValueExW(hServiceKey,
4214 L"Description",
4215 0,
4216 REG_SZ,
4217 (LPBYTE)lpServiceDescription->lpDescription,
4218 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4219
4220 if (dwError != ERROR_SUCCESS)
4221 goto done;
4222 }
4223 }
4224 else if (Info.dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4225 {
4226 UNIMPLEMENTED;
4227 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4228 goto done;
4229 }
4230
4231 done:
4232 /* FIXME: Unlock database */
4233 if (hServiceKey != NULL)
4234 RegCloseKey(hServiceKey);
4235
4236 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4237
4238 return dwError;
4239 }
4240
4241
4242 /* Function 38 */
4243 DWORD RQueryServiceConfig2A(
4244 handle_t BindingHandle,
4245 SC_RPC_HANDLE hService,
4246 DWORD dwInfoLevel,
4247 LPBYTE lpBuffer,
4248 DWORD cbBufSize,
4249 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4250 {
4251 DWORD dwError = ERROR_SUCCESS;
4252 PSERVICE_HANDLE hSvc;
4253 PSERVICE lpService = NULL;
4254 HKEY hServiceKey = NULL;
4255 DWORD dwRequiredSize;
4256 LPWSTR lpDescriptionW = NULL;
4257 LPSTR lpDescription = NULL;
4258
4259 DPRINT("RQueryServiceConfig2W() called\n");
4260
4261 if (!lpBuffer)
4262 return ERROR_INVALID_ADDRESS;
4263
4264 if (ScmShutdown)
4265 return ERROR_SHUTDOWN_IN_PROGRESS;
4266
4267 hSvc = (PSERVICE_HANDLE)hService;
4268 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4269 {
4270 DPRINT1("Invalid handle tag!\n");
4271 return ERROR_INVALID_HANDLE;
4272 }
4273
4274 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4275 SERVICE_QUERY_CONFIG))
4276 {
4277 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4278 return ERROR_ACCESS_DENIED;
4279 }
4280
4281 lpService = hSvc->ServiceEntry;
4282 if (lpService == NULL)
4283 {
4284 DPRINT1("lpService == NULL!\n");
4285 return ERROR_INVALID_HANDLE;
4286 }
4287
4288 /* FIXME: Lock the service database shared */
4289
4290 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4291 KEY_READ,
4292 &hServiceKey);
4293 if (dwError != ERROR_SUCCESS)
4294 goto done;
4295
4296 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4297 {
4298 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4299 LPSTR lpStr;
4300
4301 dwError = ScmReadString(hServiceKey,
4302 L"Description",
4303 &lpDescriptionW);
4304 if (dwError != ERROR_SUCCESS)
4305 goto done;
4306
4307 dwRequiredSize = sizeof(SERVICE_DESCRIPTIONA) + ((wcslen(lpDescriptionW) + 1));
4308
4309 if (cbBufSize < dwRequiredSize)
4310 {
4311 *pcbBytesNeeded = dwRequiredSize;
4312 dwError = ERROR_INSUFFICIENT_BUFFER;
4313 goto done;
4314 }
4315
4316 lpStr = (LPSTR)(lpServiceDescription + 1);
4317
4318 WideCharToMultiByte(CP_ACP,
4319 0,
4320 lpDescriptionW,
4321 -1,
4322 lpStr,
4323 wcslen(lpDescriptionW),
4324 NULL,
4325 NULL);
4326 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4327 }
4328 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4329 {
4330 UNIMPLEMENTED;
4331 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4332 goto done;
4333 }
4334
4335 done:
4336 if (lpDescription != NULL)
4337 HeapFree(GetProcessHeap(), 0, lpDescription);
4338
4339 if (hServiceKey != NULL)
4340 RegCloseKey(hServiceKey);
4341
4342 /* FIXME: Unlock database */
4343
4344 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4345
4346 return dwError;
4347 }
4348
4349
4350 /* Function 39 */
4351 DWORD RQueryServiceConfig2W(
4352 handle_t BindingHandle,
4353 SC_RPC_HANDLE hService,
4354 DWORD dwInfoLevel,
4355 LPBYTE lpBuffer,
4356 DWORD cbBufSize,
4357 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4358 {
4359 DWORD dwError = ERROR_SUCCESS;
4360 PSERVICE_HANDLE hSvc;
4361 PSERVICE lpService = NULL;
4362 HKEY hServiceKey = NULL;
4363 DWORD dwRequiredSize;
4364 LPWSTR lpDescription = NULL;
4365
4366 DPRINT("RQueryServiceConfig2W() called\n");
4367
4368 if (!lpBuffer)
4369 return ERROR_INVALID_ADDRESS;
4370
4371 if (ScmShutdown)
4372 return ERROR_SHUTDOWN_IN_PROGRESS;
4373
4374 hSvc = (PSERVICE_HANDLE)hService;
4375 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4376 {
4377 DPRINT1("Invalid handle tag!\n");
4378 return ERROR_INVALID_HANDLE;
4379 }
4380
4381 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4382 SERVICE_QUERY_CONFIG))
4383 {
4384 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4385 return ERROR_ACCESS_DENIED;
4386 }
4387
4388 lpService = hSvc->ServiceEntry;
4389 if (lpService == NULL)
4390 {
4391 DPRINT1("lpService == NULL!\n");
4392 return ERROR_INVALID_HANDLE;
4393 }
4394
4395 /* FIXME: Lock the service database shared */
4396
4397 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4398 KEY_READ,
4399 &hServiceKey);
4400 if (dwError != ERROR_SUCCESS)
4401 goto done;
4402
4403 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4404 {
4405 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4406 LPWSTR lpStr;
4407
4408 dwError = ScmReadString(hServiceKey,
4409 L"Description",
4410 &lpDescription);
4411 if (dwError != ERROR_SUCCESS)
4412 goto done;
4413
4414 dwRequiredSize = sizeof(SERVICE_DESCRIPTIONW) + ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4415
4416 if (cbBufSize < dwRequiredSize)
4417 {
4418 *pcbBytesNeeded = dwRequiredSize;
4419 dwError = ERROR_INSUFFICIENT_BUFFER;
4420 goto done;
4421 }
4422
4423 lpStr = (LPWSTR)(lpServiceDescription + 1);
4424 wcscpy(lpStr, lpDescription);
4425 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4426 }
4427 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4428 {
4429 UNIMPLEMENTED;
4430 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4431 goto done;
4432 }
4433
4434 done:
4435 if (lpDescription != NULL)
4436 HeapFree(GetProcessHeap(), 0, lpDescription);
4437
4438 if (hServiceKey != NULL)
4439 RegCloseKey(hServiceKey);
4440
4441 /* FIXME: Unlock database */
4442
4443 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4444
4445 return dwError;
4446 }
4447
4448
4449 /* Function 40 */
4450 DWORD RQueryServiceStatusEx(
4451 handle_t BindingHandle,
4452 SC_RPC_HANDLE hService,
4453 SC_STATUS_TYPE InfoLevel,
4454 LPBYTE lpBuffer,
4455 DWORD cbBufSize,
4456 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4457 {
4458 LPSERVICE_STATUS_PROCESS lpStatus;
4459 PSERVICE_HANDLE hSvc;
4460 PSERVICE lpService;
4461
4462 DPRINT("RQueryServiceStatusEx() called\n");
4463
4464 if (ScmShutdown)
4465 return ERROR_SHUTDOWN_IN_PROGRESS;
4466
4467 if (InfoLevel != SC_STATUS_PROCESS_INFO)
4468 return ERROR_INVALID_LEVEL;
4469
4470 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
4471
4472 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
4473 return ERROR_INSUFFICIENT_BUFFER;
4474
4475 hSvc = (PSERVICE_HANDLE)hService;
4476 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4477 {
4478 DPRINT1("Invalid handle tag!\n");
4479 return ERROR_INVALID_HANDLE;
4480 }
4481
4482 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4483 SERVICE_QUERY_STATUS))
4484 {
4485 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4486 return ERROR_ACCESS_DENIED;
4487 }
4488
4489 lpService = hSvc->ServiceEntry;
4490 if (lpService == NULL)
4491 {
4492 DPRINT1("lpService == NULL!\n");
4493 return ERROR_INVALID_HANDLE;
4494 }
4495
4496 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
4497
4498 /* Return service status information */
4499 RtlCopyMemory(lpStatus,
4500 &lpService->Status,
4501 sizeof(SERVICE_STATUS));
4502
4503 lpStatus->dwProcessId = lpService->ProcessId; /* FIXME */
4504 lpStatus->dwServiceFlags = 0; /* FIXME */
4505
4506 return ERROR_SUCCESS;
4507 }
4508
4509
4510 /* Function 41 */
4511 DWORD REnumServicesStatusExA(
4512 handle_t BindingHandle,
4513 SC_RPC_HANDLE hSCManager,
4514 SC_ENUM_TYPE InfoLevel,
4515 DWORD dwServiceType,
4516 DWORD dwServiceState,
4517 LPBYTE lpBuffer,
4518 DWORD cbBufSize,
4519 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4520 LPBOUNDED_DWORD_256K lpServicesReturned,
4521 LPBOUNDED_DWORD_256K lpResumeIndex,
4522 LPCSTR pszGroupName)
4523 {
4524 PMANAGER_HANDLE hManager;
4525 PSERVICE lpService;
4526 DWORD dwError = ERROR_SUCCESS;
4527 PLIST_ENTRY ServiceEntry;
4528 PSERVICE CurrentService;
4529 DWORD dwState;
4530 DWORD dwRequiredSize;
4531 DWORD dwServiceCount;
4532 DWORD dwSize;
4533 DWORD dwLastResumeCount = 0;
4534 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtr;
4535 LPSTR lpStringPtr;
4536 LPWSTR pszGroupNameW = NULL;
4537
4538 DPRINT("REnumServicesStatusExA() called\n");
4539
4540 if (ScmShutdown)
4541 return ERROR_SHUTDOWN_IN_PROGRESS;
4542
4543 if (InfoLevel != SC_ENUM_PROCESS_INFO)
4544 return ERROR_INVALID_LEVEL;
4545
4546 hManager = (PMANAGER_HANDLE)hSCManager;
4547 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
4548 {
4549 DPRINT1("Invalid manager handle!\n");
4550 return ERROR_INVALID_HANDLE;
4551 }
4552
4553 *pcbBytesNeeded = 0;
4554 *lpServicesReturned = 0;
4555
4556 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
4557 {
4558 DPRINT1("Not a valid Service Type!\n");
4559 return ERROR_INVALID_PARAMETER;
4560 }
4561
4562 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
4563 {
4564 DPRINT1("Not a valid Service State!\n");
4565 return ERROR_INVALID_PARAMETER;
4566 }
4567
4568 /* Check access rights */
4569 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4570 SC_MANAGER_ENUMERATE_SERVICE))
4571 {
4572 DPRINT1("Insufficient access rights! 0x%lx\n",
4573 hManager->Handle.DesiredAccess);
4574 return ERROR_ACCESS_DENIED;
4575 }
4576
4577 if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
4578
4579 /* FIXME: Lock the service list shared */
4580
4581 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4582 if (lpService == NULL)
4583 {
4584 dwError = ERROR_SUCCESS;
4585 goto Done;
4586 }
4587
4588 dwRequiredSize = 0;
4589 dwServiceCount = 0;
4590
4591 if (pszGroupName)
4592 {
4593 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
4594 if (!pszGroupNameW)
4595 {
4596 DPRINT1("Failed to allocate buffer!\n");
4597 return ERROR_NOT_ENOUGH_MEMORY;
4598 }
4599 MultiByteToWideChar(CP_ACP,
4600 0,
4601 pszGroupName,
4602 -1,
4603 pszGroupNameW,
4604 strlen(pszGroupName) + 1);
4605 }
4606
4607 for (ServiceEntry = &lpService->ServiceListEntry;
4608 ServiceEntry != &ServiceListHead;
4609 ServiceEntry = ServiceEntry->Flink)
4610 {
4611 CurrentService = CONTAINING_RECORD(ServiceEntry,
4612 SERVICE,
4613 ServiceListEntry);
4614
4615 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4616 continue;
4617
4618 dwState = SERVICE_ACTIVE;
4619 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4620 dwState = SERVICE_INACTIVE;
4621
4622 if ((dwState & dwServiceState) == 0)
4623 continue;
4624
4625 if (pszGroupNameW)
4626 {
4627 if (*pszGroupNameW == 0)
4628 {
4629 if (CurrentService->lpGroup != NULL)
4630 continue;
4631 }
4632 else
4633 {
4634 if ((CurrentService->lpGroup == NULL) ||
4635 _wcsicmp(pszGroupNameW, CurrentService->lpGroup->lpGroupName))
4636 continue;
4637 }
4638 }
4639
4640 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4641 (wcslen(CurrentService->lpServiceName) + 1) +
4642 (wcslen(CurrentService->lpDisplayName) + 1);
4643
4644 if (dwRequiredSize + dwSize <= cbBufSize)
4645 {
4646 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4647 dwRequiredSize += dwSize;
4648 dwServiceCount++;
4649 dwLastResumeCount = CurrentService->dwResumeCount;
4650 }
4651 else
4652 {
4653 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4654 break;
4655 }
4656
4657 }
4658
4659 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4660 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4661
4662 for (;
4663 ServiceEntry != &ServiceListHead;
4664 ServiceEntry = ServiceEntry->Flink)
4665 {
4666 CurrentService = CONTAINING_RECORD(ServiceEntry,
4667 SERVICE,
4668 ServiceListEntry);
4669
4670 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4671 continue;
4672
4673 dwState = SERVICE_ACTIVE;
4674 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4675 dwState = SERVICE_INACTIVE;
4676
4677 if ((dwState & dwServiceState) == 0)
4678 continue;
4679
4680 if (pszGroupNameW)
4681 {
4682 if (*pszGroupNameW == 0)
4683 {
4684 if (CurrentService->lpGroup != NULL)
4685 continue;
4686 }
4687 else
4688 {
4689 if ((CurrentService->lpGroup == NULL) ||
4690 _wcsicmp(pszGroupNameW, CurrentService->lpGroup->lpGroupName))
4691 continue;
4692 }
4693 }
4694
4695 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4696 (wcslen(CurrentService->lpServiceName) + 1) +
4697 (wcslen(CurrentService->lpDisplayName) + 1));
4698
4699 dwError = ERROR_MORE_DATA;
4700 }
4701
4702 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4703
4704 if (lpResumeIndex) *lpResumeIndex = dwLastResumeCount;
4705 *lpServicesReturned = dwServiceCount;
4706 *pcbBytesNeeded = dwRequiredSize;
4707
4708 /* If there was no services that matched */
4709 if (!dwServiceCount)
4710 {
4711 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4712 goto Done;
4713 }
4714
4715 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
4716 lpStringPtr = (LPSTR)((ULONG_PTR)lpBuffer +
4717 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
4718
4719 dwRequiredSize = 0;
4720 for (ServiceEntry = &lpService->ServiceListEntry;
4721 ServiceEntry != &ServiceListHead;
4722 ServiceEntry = ServiceEntry->Flink)
4723 {
4724 CurrentService = CONTAINING_RECORD(ServiceEntry,
4725 SERVICE,
4726 ServiceListEntry);
4727
4728 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4729 continue;
4730
4731 dwState = SERVICE_ACTIVE;
4732 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4733 dwState = SERVICE_INACTIVE;
4734
4735 if ((dwState & dwServiceState) == 0)
4736 continue;
4737
4738 if (pszGroupNameW)
4739 {
4740 if (*pszGroupNameW == 0)
4741 {
4742 if (CurrentService->lpGroup != NULL)
4743 continue;
4744 }
4745 else
4746 {
4747 if ((CurrentService->lpGroup == NULL) ||
4748 _wcsicmp(pszGroupNameW, CurrentService->lpGroup->lpGroupName))
4749 continue;
4750 }
4751 }
4752
4753 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4754 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4755 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4756
4757 if (dwRequiredSize + dwSize <= cbBufSize)
4758 {
4759 /* Copy the service name */
4760 WideCharToMultiByte(CP_ACP,
4761 0,
4762 CurrentService->lpServiceName,
4763 -1,
4764 lpStringPtr,
4765 wcslen(CurrentService->lpServiceName),
4766 0,
4767 0);
4768 lpStatusPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4769 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4770
4771 /* Copy the display name */
4772 WideCharToMultiByte(CP_ACP,
4773 0,
4774 CurrentService->lpDisplayName,
4775 -1,
4776 lpStringPtr,
4777 wcslen(CurrentService->lpDisplayName),
4778 0,
4779 0);
4780 lpStatusPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4781 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4782
4783 /* Copy the status information */
4784 memcpy(&lpStatusPtr->ServiceStatusProcess,
4785 &CurrentService->Status,
4786 sizeof(SERVICE_STATUS));
4787 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
4788 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4789
4790 lpStatusPtr++;
4791 dwRequiredSize += dwSize;
4792 }
4793 else
4794 {
4795 break;
4796 }
4797 }
4798
4799 if (dwError != ERROR_MORE_DATA)
4800 {
4801 *pcbBytesNeeded = 0;
4802 if (lpResumeIndex) *lpResumeIndex = 0;
4803 }
4804
4805 Done:;
4806 /* Unlock the service list */
4807
4808 if (pszGroupNameW) HeapFree(GetProcessHeap(),0,pszGroupNameW);
4809
4810 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
4811
4812 return dwError;
4813 }
4814
4815
4816 /* Function 42 */
4817 DWORD REnumServicesStatusExW(
4818 handle_t BindingHandle,
4819 SC_RPC_HANDLE hSCManager,
4820 SC_ENUM_TYPE InfoLevel,
4821 DWORD dwServiceType,
4822 DWORD dwServiceState,
4823 LPBYTE lpBuffer,
4824 DWORD cbBufSize,
4825 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4826 LPBOUNDED_DWORD_256K lpServicesReturned,
4827 LPBOUNDED_DWORD_256K lpResumeIndex,
4828 LPCWSTR pszGroupName)
4829 {
4830 PMANAGER_HANDLE hManager;
4831 PSERVICE lpService;
4832 DWORD dwError = ERROR_SUCCESS;
4833 PLIST_ENTRY ServiceEntry;
4834 PSERVICE CurrentService;
4835 DWORD dwState;
4836 DWORD dwRequiredSize;
4837 DWORD dwServiceCount;
4838 DWORD dwSize;
4839 DWORD dwLastResumeCount = 0;
4840 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
4841 LPWSTR lpStringPtr;
4842
4843 DPRINT("REnumServicesStatusExW() called\n");
4844
4845 if (ScmShutdown)
4846 return ERROR_SHUTDOWN_IN_PROGRESS;
4847
4848 if (InfoLevel != SC_ENUM_PROCESS_INFO)
4849 return ERROR_INVALID_LEVEL;
4850
4851 hManager = (PMANAGER_HANDLE)hSCManager;
4852 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
4853 {
4854 DPRINT1("Invalid manager handle!\n");
4855 return ERROR_INVALID_HANDLE;
4856 }
4857
4858 *pcbBytesNeeded = 0;
4859 *lpServicesReturned = 0;
4860
4861 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
4862 {
4863 DPRINT1("Not a valid Service Type!\n");
4864 return ERROR_INVALID_PARAMETER;
4865 }
4866
4867 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
4868 {
4869 DPRINT1("Not a valid Service State!\n");
4870 return ERROR_INVALID_PARAMETER;
4871 }
4872
4873 /* Check access rights */
4874 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4875 SC_MANAGER_ENUMERATE_SERVICE))
4876 {
4877 DPRINT1("Insufficient access rights! 0x%lx\n",
4878 hManager->Handle.DesiredAccess);
4879 return ERROR_ACCESS_DENIED;
4880 }
4881
4882 if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
4883
4884 /* Lock the service list shared */
4885
4886 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4887 if (lpService == NULL)
4888 {
4889 dwError = ERROR_SUCCESS;
4890 goto Done;
4891 }
4892
4893 dwRequiredSize = 0;
4894 dwServiceCount = 0;
4895
4896 for (ServiceEntry = &lpService->ServiceListEntry;
4897 ServiceEntry != &ServiceListHead;
4898 ServiceEntry = ServiceEntry->Flink)
4899 {
4900 CurrentService = CONTAINING_RECORD(ServiceEntry,
4901 SERVICE,
4902 ServiceListEntry);
4903
4904 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4905 continue;
4906
4907 dwState = SERVICE_ACTIVE;
4908 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4909 dwState = SERVICE_INACTIVE;
4910
4911 if ((dwState & dwServiceState) == 0)
4912 continue;
4913
4914 if (pszGroupName)
4915 {
4916 if (*pszGroupName == 0)
4917 {
4918 if (CurrentService->lpGroup != NULL)
4919 continue;
4920 }
4921 else
4922 {
4923 if ((CurrentService->lpGroup == NULL) ||
4924 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4925 continue;
4926 }
4927 }
4928
4929 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4930 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4931 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4932
4933 if (dwRequiredSize + dwSize <= cbBufSize)
4934 {
4935 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4936 dwRequiredSize += dwSize;
4937 dwServiceCount++;
4938 dwLastResumeCount = CurrentService->dwResumeCount;
4939 }
4940 else
4941 {
4942 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4943 break;
4944 }
4945
4946 }
4947
4948 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4949 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4950
4951 for (;
4952 ServiceEntry != &ServiceListHead;
4953 ServiceEntry = ServiceEntry->Flink)
4954 {
4955 CurrentService = CONTAINING_RECORD(ServiceEntry,
4956 SERVICE,
4957 ServiceListEntry);
4958
4959 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4960 continue;
4961
4962 dwState = SERVICE_ACTIVE;
4963 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4964 dwState = SERVICE_INACTIVE;
4965
4966 if ((dwState & dwServiceState) == 0)
4967 continue;
4968
4969 if (pszGroupName)
4970 {
4971 if (*pszGroupName == 0)
4972 {
4973 if (CurrentService->lpGroup != NULL)
4974 continue;
4975 }
4976 else
4977 {
4978 if ((CurrentService->lpGroup == NULL) ||
4979 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4980 continue;
4981 }
4982 }
4983
4984 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4985 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4986 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4987
4988 dwError = ERROR_MORE_DATA;
4989 }
4990
4991 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4992
4993 if (lpResumeIndex) *lpResumeIndex = dwLastResumeCount;
4994 *lpServicesReturned = dwServiceCount;
4995 *pcbBytesNeeded = dwRequiredSize;
4996
4997 /* If there was no services that matched */
4998 if (!dwServiceCount)
4999 {
5000 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
5001 goto Done;
5002 }
5003
5004 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
5005 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
5006 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5007
5008 dwRequiredSize = 0;
5009 for (ServiceEntry = &lpService->ServiceListEntry;
5010 ServiceEntry != &ServiceListHead;
5011 ServiceEntry = ServiceEntry->Flink)
5012 {
5013 CurrentService = CONTAINING_RECORD(ServiceEntry,
5014 SERVICE,
5015 ServiceListEntry);
5016
5017 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5018 continue;
5019
5020 dwState = SERVICE_ACTIVE;
5021 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5022 dwState = SERVICE_INACTIVE;
5023
5024 if ((dwState & dwServiceState) == 0)
5025 continue;
5026
5027 if (pszGroupName)
5028 {
5029 if (*pszGroupName == 0)
5030 {
5031 if (CurrentService->lpGroup != NULL)
5032 continue;
5033 }
5034 else
5035 {
5036 if ((CurrentService->lpGroup == NULL) ||
5037 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5038 continue;
5039 }
5040 }
5041
5042 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5043 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5044 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5045
5046 if (dwRequiredSize + dwSize <= cbBufSize)
5047 {
5048 /* Copy the service name */
5049 wcscpy(lpStringPtr,
5050 CurrentService->lpServiceName);
5051 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5052 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
5053
5054 /* Copy the display name */
5055 wcscpy(lpStringPtr,
5056 CurrentService->lpDisplayName);
5057 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5058 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
5059
5060 /* Copy the status information */
5061 memcpy(&lpStatusPtr->ServiceStatusProcess,
5062 &CurrentService->Status,
5063 sizeof(SERVICE_STATUS));
5064 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
5065 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5066
5067 lpStatusPtr++;
5068 dwRequiredSize += dwSize;
5069 }
5070 else
5071 {
5072 break;
5073 }
5074 }
5075
5076 if (dwError != ERROR_MORE_DATA)
5077 {
5078 *pcbBytesNeeded = 0;
5079 if (lpResumeIndex) *lpResumeIndex = 0;
5080 }
5081
5082 Done:;
5083 /* Unlock the service list */
5084
5085 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
5086
5087 return dwError;
5088 }
5089
5090
5091 /* Function 43 */
5092 DWORD RSendTSMessage(
5093 handle_t BindingHandle)
5094 {
5095 UNIMPLEMENTED;
5096 return ERROR_CALL_NOT_IMPLEMENTED;
5097 }
5098
5099
5100 /* Function 44 */
5101 DWORD RCreateServiceWOW64A(
5102 handle_t BindingHandle,
5103 LPSTR lpServiceName,
5104 LPSTR lpDisplayName,
5105 DWORD dwDesiredAccess,
5106 DWORD dwServiceType,
5107 DWORD dwStartType,
5108 DWORD dwErrorControl,
5109 LPSTR lpBinaryPathName,
5110 LPSTR lpLoadOrderGroup,
5111 LPDWORD lpdwTagId,
5112 LPBYTE lpDependencies,
5113 DWORD dwDependSize,
5114 LPSTR lpServiceStartName,
5115 LPBYTE lpPassword,
5116 DWORD dwPwSize,
5117 LPSC_RPC_HANDLE lpServiceHandle)
5118 {
5119 UNIMPLEMENTED;
5120 return ERROR_CALL_NOT_IMPLEMENTED;
5121 }
5122
5123
5124 /* Function 45 */
5125 DWORD RCreateServiceWOW64W(
5126 handle_t BindingHandle,
5127 LPWSTR lpServiceName,
5128 LPWSTR lpDisplayName,
5129 DWORD dwDesiredAccess,
5130 DWORD dwServiceType,
5131 DWORD dwStartType,
5132 DWORD dwErrorControl,
5133 LPWSTR lpBinaryPathName,
5134 LPWSTR lpLoadOrderGroup,
5135 LPDWORD lpdwTagId,
5136 LPBYTE lpDependencies,
5137 DWORD dwDependSize,
5138 LPWSTR lpServiceStartName,
5139 LPBYTE lpPassword,
5140 DWORD dwPwSize,
5141 LPSC_RPC_HANDLE lpServiceHandle)
5142 {
5143 UNIMPLEMENTED;
5144 return ERROR_CALL_NOT_IMPLEMENTED;
5145 }
5146
5147
5148 /* Function 46 */
5149 DWORD RQueryServiceTagInfo(
5150 handle_t BindingHandle)
5151 {
5152 UNIMPLEMENTED;
5153 return ERROR_CALL_NOT_IMPLEMENTED;
5154 }
5155
5156
5157 /* Function 47 */
5158 DWORD RNotifyServiceStatusChange(
5159 handle_t BindingHandle,
5160 SC_RPC_HANDLE hService,
5161 SC_RPC_NOTIFY_PARAMS NotifyParams,
5162 GUID *pClientProcessGuid,
5163 GUID *pSCMProcessGuid,
5164 PBOOL pfCreateRemoteQueue,
5165 LPSC_NOTIFY_RPC_HANDLE phNotify)
5166 {
5167 UNIMPLEMENTED;
5168 return ERROR_CALL_NOT_IMPLEMENTED;
5169 }
5170
5171
5172 /* Function 48 */
5173 DWORD RGetNotifyResults(
5174 handle_t BindingHandle,
5175 SC_NOTIFY_RPC_HANDLE hNotify,
5176 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5177 {
5178 UNIMPLEMENTED;
5179 return ERROR_CALL_NOT_IMPLEMENTED;
5180 }
5181
5182
5183 /* Function 49 */
5184 DWORD RCloseNotifyHandle(
5185 handle_t BindingHandle,
5186 LPSC_NOTIFY_RPC_HANDLE phNotify,
5187 PBOOL pfApcFired)
5188 {
5189 UNIMPLEMENTED;
5190 return ERROR_CALL_NOT_IMPLEMENTED;
5191 }
5192
5193
5194 /* Function 50 */
5195 DWORD RControlServiceExA(
5196 handle_t BindingHandle,
5197 SC_RPC_HANDLE hService,
5198 DWORD dwControl,
5199 DWORD dwInfoLevel)
5200 {
5201 UNIMPLEMENTED;
5202 return ERROR_CALL_NOT_IMPLEMENTED;
5203 }
5204
5205
5206 /* Function 51 */
5207 DWORD RControlServiceExW(
5208 handle_t BindingHandle,
5209 SC_RPC_HANDLE hService,
5210 DWORD dwControl,
5211 DWORD dwInfoLevel)
5212 {
5213 UNIMPLEMENTED;
5214 return ERROR_CALL_NOT_IMPLEMENTED;
5215 }
5216
5217
5218 /* Function 52 */
5219 DWORD RSendPnPMessage(
5220 handle_t BindingHandle)
5221 {
5222 UNIMPLEMENTED;
5223 return ERROR_CALL_NOT_IMPLEMENTED;
5224 }
5225
5226
5227 /* Function 53 */
5228 DWORD RValidatePnPService(
5229 handle_t BindingHandle)
5230 {
5231 UNIMPLEMENTED;
5232 return ERROR_CALL_NOT_IMPLEMENTED;
5233 }
5234
5235
5236 /* Function 54 */
5237 DWORD ROpenServiceStatusHandle(
5238 handle_t BindingHandle)
5239 {
5240 UNIMPLEMENTED;
5241 return ERROR_CALL_NOT_IMPLEMENTED;
5242 }
5243
5244
5245 /* Function 55 */
5246 DWORD RFunction55(
5247 handle_t BindingHandle)
5248 {
5249 UNIMPLEMENTED;
5250 return ERROR_CALL_NOT_IMPLEMENTED;
5251 }
5252
5253
5254 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
5255 {
5256 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5257 }
5258
5259
5260 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5261 {
5262 HeapFree(GetProcessHeap(), 0, ptr);
5263 }
5264
5265
5266 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5267 {
5268 }
5269
5270
5271 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5272 {
5273 }
5274
5275
5276 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5277 {
5278 }
5279
5280
5281 /* EOF */