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