5ffd2d91a412a7e34586592a1a20b80f678292eb
[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 0, windows
2776 puts null in lpDisplayName and puts 1 in lpcchBuffer */
2777 if (*lpcchBuffer == 0)
2778 {
2779 *lpcchBuffer = 1;
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 0, windows
2850 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2851 if (*lpcchBuffer == 0)
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)
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)
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 + 1,
3954 dwLength,
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 lpServiceDesriptonW;
4016 LPSERVICE_DESCRIPTIONA lpServiceDesriptonA;
4017
4018 lpServiceDesriptonA = Info.psd;
4019
4020 if (lpServiceDesriptonA &&
4021 lpServiceDesriptonA->lpDescription)
4022 {
4023 dwLength = (strlen(lpServiceDesriptonA->lpDescription) + 1) * sizeof(WCHAR);
4024
4025 lpServiceDesriptonW = HeapAlloc(GetProcessHeap(),
4026 0,
4027 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4028 if (!lpServiceDesriptonW)
4029 {
4030 return ERROR_NOT_ENOUGH_MEMORY;
4031 }
4032
4033 MultiByteToWideChar(CP_ACP,
4034 0,
4035 lpServiceDesriptonA->lpDescription,
4036 -1,
4037 lpServiceDesriptonW->lpDescription,
4038 dwLength);
4039
4040 ptr = lpServiceDesriptonW;
4041 }
4042 }
4043 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4044 {
4045 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4046 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4047 DWORD dwRebootLen = 0;
4048 DWORD dwCommandLen = 0;
4049
4050 lpServiceFailureActionsA = Info.psfa;
4051
4052 if (lpServiceFailureActionsA)
4053 {
4054 if (lpServiceFailureActionsA->lpRebootMsg)
4055 {
4056 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4057 }
4058 if (lpServiceFailureActionsA->lpCommand)
4059 {
4060 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4061 }
4062 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4063
4064 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4065 0,
4066 dwLength);
4067 if (!lpServiceFailureActionsW)
4068 {
4069 return ERROR_NOT_ENOUGH_MEMORY;
4070 }
4071
4072 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4073 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4074 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4075
4076 if (lpServiceFailureActionsA->lpRebootMsg)
4077 {
4078 MultiByteToWideChar(CP_ACP,
4079 0,
4080 lpServiceFailureActionsA->lpRebootMsg,
4081 -1,
4082 lpServiceFailureActionsW->lpRebootMsg,
4083 dwRebootLen);
4084 }
4085
4086 if (lpServiceFailureActionsA->lpCommand)
4087 {
4088 MultiByteToWideChar(CP_ACP,
4089 0,
4090 lpServiceFailureActionsA->lpCommand,
4091 -1,
4092 lpServiceFailureActionsW->lpCommand,
4093 dwCommandLen);
4094 }
4095
4096 ptr = lpServiceFailureActionsW;
4097 }
4098 }
4099
4100 dwRet = RChangeServiceConfig2W(hService, InfoW);
4101
4102 HeapFree(GetProcessHeap(), 0, ptr);
4103
4104 return dwRet;
4105 }
4106
4107
4108 /* Function 37 */
4109 DWORD RChangeServiceConfig2W(
4110 SC_RPC_HANDLE hService,
4111 SC_RPC_CONFIG_INFOW Info)
4112 {
4113 DWORD dwError = ERROR_SUCCESS;
4114 PSERVICE_HANDLE hSvc;
4115 PSERVICE lpService = NULL;
4116 HKEY hServiceKey = NULL;
4117
4118 DPRINT("RChangeServiceConfig2W() called\n");
4119 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4120
4121 if (ScmShutdown)
4122 return ERROR_SHUTDOWN_IN_PROGRESS;
4123
4124 hSvc = (PSERVICE_HANDLE)hService;
4125 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4126 {
4127 DPRINT1("Invalid handle tag!\n");
4128 return ERROR_INVALID_HANDLE;
4129 }
4130
4131 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4132 SERVICE_CHANGE_CONFIG))
4133 {
4134 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4135 return ERROR_ACCESS_DENIED;
4136 }
4137
4138 lpService = hSvc->ServiceEntry;
4139 if (lpService == NULL)
4140 {
4141 DPRINT1("lpService == NULL!\n");
4142 return ERROR_INVALID_HANDLE;
4143 }
4144
4145 /* FIXME: Lock database exclusively */
4146
4147 if (lpService->bDeleted)
4148 {
4149 /* FIXME: Unlock database */
4150 DPRINT1("The service has already been marked for delete!\n");
4151 return ERROR_SERVICE_MARKED_FOR_DELETE;
4152 }
4153
4154 /* Open the service key */
4155 dwError = ScmOpenServiceKey(lpService->szServiceName,
4156 KEY_SET_VALUE,
4157 &hServiceKey);
4158 if (dwError != ERROR_SUCCESS)
4159 goto done;
4160
4161 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4162 {
4163 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4164
4165 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)&Info;
4166 lpServiceDescription->lpDescription = (LPWSTR)(&Info + sizeof(LPSERVICE_DESCRIPTIONW));
4167
4168 if (lpServiceDescription != NULL &&
4169 lpServiceDescription->lpDescription != NULL)
4170 {
4171 RegSetValueExW(hServiceKey,
4172 L"Description",
4173 0,
4174 REG_SZ,
4175 (LPBYTE)lpServiceDescription->lpDescription,
4176 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4177
4178 if (dwError != ERROR_SUCCESS)
4179 goto done;
4180 }
4181 }
4182 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4183 {
4184 UNIMPLEMENTED;
4185 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4186 goto done;
4187 }
4188
4189 done:
4190 /* FIXME: Unlock database */
4191 if (hServiceKey != NULL)
4192 RegCloseKey(hServiceKey);
4193
4194 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4195
4196 return dwError;
4197 }
4198
4199
4200 /* Function 38 */
4201 DWORD RQueryServiceConfig2A(
4202 SC_RPC_HANDLE hService,
4203 DWORD dwInfoLevel,
4204 LPBYTE lpBuffer,
4205 DWORD cbBufSize,
4206 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4207 {
4208 DWORD dwError = ERROR_SUCCESS;
4209 PSERVICE_HANDLE hSvc;
4210 PSERVICE lpService = NULL;
4211 HKEY hServiceKey = NULL;
4212 LPWSTR lpDescriptionW = NULL;
4213 LPSTR lpDescription = NULL;
4214
4215 DPRINT("RQueryServiceConfig2W() called\n");
4216
4217 if (!lpBuffer)
4218 return ERROR_INVALID_ADDRESS;
4219
4220 if (ScmShutdown)
4221 return ERROR_SHUTDOWN_IN_PROGRESS;
4222
4223 hSvc = (PSERVICE_HANDLE)hService;
4224 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4225 {
4226 DPRINT1("Invalid handle tag!\n");
4227 return ERROR_INVALID_HANDLE;
4228 }
4229
4230 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4231 SERVICE_QUERY_CONFIG))
4232 {
4233 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4234 return ERROR_ACCESS_DENIED;
4235 }
4236
4237 lpService = hSvc->ServiceEntry;
4238 if (lpService == NULL)
4239 {
4240 DPRINT1("lpService == NULL!\n");
4241 return ERROR_INVALID_HANDLE;
4242 }
4243
4244 /* FIXME: Lock the service database shared */
4245
4246 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4247 KEY_READ,
4248 &hServiceKey);
4249 if (dwError != ERROR_SUCCESS)
4250 goto done;
4251
4252 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4253 {
4254 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4255 LPSTR lpStr;
4256
4257 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4258
4259 dwError = ScmReadString(hServiceKey,
4260 L"Description",
4261 &lpDescriptionW);
4262 if (dwError == ERROR_SUCCESS)
4263 {
4264 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1));
4265 }
4266
4267 if (cbBufSize >= *pcbBytesNeeded)
4268 {
4269
4270 if (dwError == ERROR_SUCCESS)
4271 {
4272 lpStr = (LPSTR)(lpServiceDescription + 1);
4273
4274 WideCharToMultiByte(CP_ACP,
4275 0,
4276 lpDescriptionW,
4277 -1,
4278 lpStr,
4279 wcslen(lpDescriptionW),
4280 NULL,
4281 NULL);
4282 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4283 }
4284 else
4285 {
4286 lpServiceDescription->lpDescription = NULL;
4287 }
4288 }
4289 else
4290 {
4291 dwError = ERROR_INSUFFICIENT_BUFFER;
4292 }
4293 }
4294 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4295 {
4296 UNIMPLEMENTED;
4297 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4298 goto done;
4299 }
4300
4301 done:
4302 if (lpDescription != NULL)
4303 HeapFree(GetProcessHeap(), 0, lpDescription);
4304
4305 if (hServiceKey != NULL)
4306 RegCloseKey(hServiceKey);
4307
4308 /* FIXME: Unlock database */
4309
4310 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4311
4312 return dwError;
4313 }
4314
4315
4316 /* Function 39 */
4317 DWORD RQueryServiceConfig2W(
4318 SC_RPC_HANDLE hService,
4319 DWORD dwInfoLevel,
4320 LPBYTE lpBuffer,
4321 DWORD cbBufSize,
4322 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4323 {
4324 DWORD dwError = ERROR_SUCCESS;
4325 PSERVICE_HANDLE hSvc;
4326 PSERVICE lpService = NULL;
4327 HKEY hServiceKey = NULL;
4328 DWORD dwRequiredSize;
4329 LPWSTR lpDescription = NULL;
4330
4331 DPRINT("RQueryServiceConfig2W() called\n");
4332
4333 if (!lpBuffer)
4334 return ERROR_INVALID_ADDRESS;
4335
4336 if (ScmShutdown)
4337 return ERROR_SHUTDOWN_IN_PROGRESS;
4338
4339 hSvc = (PSERVICE_HANDLE)hService;
4340 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4341 {
4342 DPRINT1("Invalid handle tag!\n");
4343 return ERROR_INVALID_HANDLE;
4344 }
4345
4346 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4347 SERVICE_QUERY_CONFIG))
4348 {
4349 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4350 return ERROR_ACCESS_DENIED;
4351 }
4352
4353 lpService = hSvc->ServiceEntry;
4354 if (lpService == NULL)
4355 {
4356 DPRINT1("lpService == NULL!\n");
4357 return ERROR_INVALID_HANDLE;
4358 }
4359
4360 /* FIXME: Lock the service database shared */
4361
4362 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4363 KEY_READ,
4364 &hServiceKey);
4365 if (dwError != ERROR_SUCCESS)
4366 goto done;
4367
4368 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4369 {
4370 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4371 LPWSTR lpStr;
4372
4373 dwError = ScmReadString(hServiceKey,
4374 L"Description",
4375 &lpDescription);
4376 if (dwError != ERROR_SUCCESS)
4377 goto done;
4378
4379 dwRequiredSize = sizeof(SERVICE_DESCRIPTIONW) + ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4380
4381 if (cbBufSize < dwRequiredSize)
4382 {
4383 *pcbBytesNeeded = dwRequiredSize;
4384 dwError = ERROR_INSUFFICIENT_BUFFER;
4385 goto done;
4386 }
4387
4388 lpStr = (LPWSTR)(lpServiceDescription + 1);
4389 wcscpy(lpStr, lpDescription);
4390 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4391 }
4392 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4393 {
4394 UNIMPLEMENTED;
4395 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4396 goto done;
4397 }
4398
4399 done:
4400 if (lpDescription != NULL)
4401 HeapFree(GetProcessHeap(), 0, lpDescription);
4402
4403 if (hServiceKey != NULL)
4404 RegCloseKey(hServiceKey);
4405
4406 /* FIXME: Unlock database */
4407
4408 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4409
4410 return dwError;
4411 }
4412
4413
4414 /* Function 40 */
4415 DWORD RQueryServiceStatusEx(
4416 SC_RPC_HANDLE hService,
4417 SC_STATUS_TYPE InfoLevel,
4418 LPBYTE lpBuffer,
4419 DWORD cbBufSize,
4420 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4421 {
4422 LPSERVICE_STATUS_PROCESS lpStatus;
4423 PSERVICE_HANDLE hSvc;
4424 PSERVICE lpService;
4425
4426 DPRINT("RQueryServiceStatusEx() called\n");
4427
4428 if (ScmShutdown)
4429 return ERROR_SHUTDOWN_IN_PROGRESS;
4430
4431 if (InfoLevel != SC_STATUS_PROCESS_INFO)
4432 return ERROR_INVALID_LEVEL;
4433
4434 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
4435
4436 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
4437 return ERROR_INSUFFICIENT_BUFFER;
4438
4439 hSvc = (PSERVICE_HANDLE)hService;
4440 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4441 {
4442 DPRINT1("Invalid handle tag!\n");
4443 return ERROR_INVALID_HANDLE;
4444 }
4445
4446 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4447 SERVICE_QUERY_STATUS))
4448 {
4449 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4450 return ERROR_ACCESS_DENIED;
4451 }
4452
4453 lpService = hSvc->ServiceEntry;
4454 if (lpService == NULL)
4455 {
4456 DPRINT1("lpService == NULL!\n");
4457 return ERROR_INVALID_HANDLE;
4458 }
4459
4460 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
4461
4462 /* Return service status information */
4463 RtlCopyMemory(lpStatus,
4464 &lpService->Status,
4465 sizeof(SERVICE_STATUS));
4466
4467 lpStatus->dwProcessId = lpService->ProcessId; /* FIXME */
4468 lpStatus->dwServiceFlags = 0; /* FIXME */
4469
4470 return ERROR_SUCCESS;
4471 }
4472
4473
4474 /* Function 41 */
4475 DWORD REnumServicesStatusExA(
4476 SC_RPC_HANDLE hSCManager,
4477 SC_ENUM_TYPE InfoLevel,
4478 DWORD dwServiceType,
4479 DWORD dwServiceState,
4480 LPBYTE lpBuffer,
4481 DWORD cbBufSize,
4482 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4483 LPBOUNDED_DWORD_256K lpServicesReturned,
4484 LPBOUNDED_DWORD_256K lpResumeIndex,
4485 LPCSTR pszGroupName)
4486 {
4487 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
4488 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
4489 LPWSTR lpStringPtrW;
4490 LPSTR lpStringPtrA;
4491 LPWSTR pszGroupNameW = NULL;
4492 DWORD dwError;
4493 DWORD dwServiceCount;
4494
4495 DPRINT("REnumServicesStatusExA() called\n");
4496
4497 if (pszGroupName)
4498 {
4499 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
4500 if (!pszGroupNameW)
4501 {
4502 DPRINT1("Failed to allocate buffer!\n");
4503 return ERROR_NOT_ENOUGH_MEMORY;
4504 }
4505 MultiByteToWideChar(CP_ACP,
4506 0,
4507 pszGroupName,
4508 -1,
4509 pszGroupNameW,
4510 strlen(pszGroupName) + 1);
4511 }
4512
4513 if ((cbBufSize > 0) && (lpBuffer))
4514 {
4515 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
4516 if (!lpStatusPtrW)
4517 {
4518 DPRINT1("Failed to allocate buffer!\n");
4519 return ERROR_NOT_ENOUGH_MEMORY;
4520 }
4521 }
4522
4523 dwError = REnumServicesStatusExW(hSCManager,
4524 InfoLevel,
4525 dwServiceType,
4526 dwServiceState,
4527 (LPBYTE)lpStatusPtrW,
4528 cbBufSize,
4529 pcbBytesNeeded,
4530 lpServicesReturned,
4531 lpResumeIndex,
4532 pszGroupNameW);
4533
4534 /* if no services were returned then we are Done */
4535 if (*lpServicesReturned == 0) goto Done;
4536
4537 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
4538 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
4539 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
4540 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
4541 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4542
4543 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
4544 {
4545 /* Copy the service name */
4546 WideCharToMultiByte(CP_ACP,
4547 0,
4548 lpStringPtrW,
4549 -1,
4550 lpStringPtrA,
4551 wcslen(lpStringPtrW),
4552 0,
4553 0);
4554
4555 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4556 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4557 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4558
4559 /* Copy the display name */
4560 WideCharToMultiByte(CP_ACP,
4561 0,
4562 lpStringPtrW,
4563 -1,
4564 lpStringPtrA,
4565 wcslen(lpStringPtrW),
4566 0,
4567 0);
4568
4569 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4570 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4571 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4572
4573 /* Copy the status information */
4574 memcpy(&lpStatusPtrA->ServiceStatusProcess,
4575 &lpStatusPtrW->ServiceStatusProcess,
4576 sizeof(SERVICE_STATUS));
4577
4578 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
4579 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4580 lpStatusPtrA++;
4581 }
4582
4583 Done:;
4584 if (pszGroupNameW) HeapFree(GetProcessHeap(), 0, pszGroupNameW);
4585
4586 if (lpStatusPtrW) HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
4587
4588 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
4589
4590 return dwError;
4591 }
4592
4593
4594 /* Function 42 */
4595 DWORD REnumServicesStatusExW(
4596 SC_RPC_HANDLE hSCManager,
4597 SC_ENUM_TYPE InfoLevel,
4598 DWORD dwServiceType,
4599 DWORD dwServiceState,
4600 LPBYTE lpBuffer,
4601 DWORD cbBufSize,
4602 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4603 LPBOUNDED_DWORD_256K lpServicesReturned,
4604 LPBOUNDED_DWORD_256K lpResumeIndex,
4605 LPCWSTR pszGroupName)
4606 {
4607 PMANAGER_HANDLE hManager;
4608 PSERVICE lpService;
4609 DWORD dwError = ERROR_SUCCESS;
4610 PLIST_ENTRY ServiceEntry;
4611 PSERVICE CurrentService;
4612 DWORD dwState;
4613 DWORD dwRequiredSize;
4614 DWORD dwServiceCount;
4615 DWORD dwSize;
4616 DWORD dwLastResumeCount = 0;
4617 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
4618 LPWSTR lpStringPtr;
4619
4620 DPRINT("REnumServicesStatusExW() called\n");
4621
4622 if (ScmShutdown)
4623 return ERROR_SHUTDOWN_IN_PROGRESS;
4624
4625 if (InfoLevel != SC_ENUM_PROCESS_INFO)
4626 return ERROR_INVALID_LEVEL;
4627
4628 hManager = (PMANAGER_HANDLE)hSCManager;
4629 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
4630 {
4631 DPRINT1("Invalid manager handle!\n");
4632 return ERROR_INVALID_HANDLE;
4633 }
4634
4635 *pcbBytesNeeded = 0;
4636 *lpServicesReturned = 0;
4637
4638 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
4639 {
4640 DPRINT1("Not a valid Service Type!\n");
4641 return ERROR_INVALID_PARAMETER;
4642 }
4643
4644 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
4645 {
4646 DPRINT1("Not a valid Service State!\n");
4647 return ERROR_INVALID_PARAMETER;
4648 }
4649
4650 /* Check access rights */
4651 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4652 SC_MANAGER_ENUMERATE_SERVICE))
4653 {
4654 DPRINT1("Insufficient access rights! 0x%lx\n",
4655 hManager->Handle.DesiredAccess);
4656 return ERROR_ACCESS_DENIED;
4657 }
4658
4659 if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
4660
4661 /* Lock the service list shared */
4662
4663 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4664 if (lpService == NULL)
4665 {
4666 dwError = ERROR_SUCCESS;
4667 goto Done;
4668 }
4669
4670 dwRequiredSize = 0;
4671 dwServiceCount = 0;
4672
4673 for (ServiceEntry = &lpService->ServiceListEntry;
4674 ServiceEntry != &ServiceListHead;
4675 ServiceEntry = ServiceEntry->Flink)
4676 {
4677 CurrentService = CONTAINING_RECORD(ServiceEntry,
4678 SERVICE,
4679 ServiceListEntry);
4680
4681 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4682 continue;
4683
4684 dwState = SERVICE_ACTIVE;
4685 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4686 dwState = SERVICE_INACTIVE;
4687
4688 if ((dwState & dwServiceState) == 0)
4689 continue;
4690
4691 if (pszGroupName)
4692 {
4693 if (*pszGroupName == 0)
4694 {
4695 if (CurrentService->lpGroup != NULL)
4696 continue;
4697 }
4698 else
4699 {
4700 if ((CurrentService->lpGroup == NULL) ||
4701 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4702 continue;
4703 }
4704 }
4705
4706 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4707 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4708 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4709
4710 if (dwRequiredSize + dwSize <= cbBufSize)
4711 {
4712 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4713 dwRequiredSize += dwSize;
4714 dwServiceCount++;
4715 dwLastResumeCount = CurrentService->dwResumeCount;
4716 }
4717 else
4718 {
4719 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4720 break;
4721 }
4722
4723 }
4724
4725 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4726 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4727
4728 for (;
4729 ServiceEntry != &ServiceListHead;
4730 ServiceEntry = ServiceEntry->Flink)
4731 {
4732 CurrentService = CONTAINING_RECORD(ServiceEntry,
4733 SERVICE,
4734 ServiceListEntry);
4735
4736 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4737 continue;
4738
4739 dwState = SERVICE_ACTIVE;
4740 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4741 dwState = SERVICE_INACTIVE;
4742
4743 if ((dwState & dwServiceState) == 0)
4744 continue;
4745
4746 if (pszGroupName)
4747 {
4748 if (*pszGroupName == 0)
4749 {
4750 if (CurrentService->lpGroup != NULL)
4751 continue;
4752 }
4753 else
4754 {
4755 if ((CurrentService->lpGroup == NULL) ||
4756 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4757 continue;
4758 }
4759 }
4760
4761 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4762 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4763 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4764
4765 dwError = ERROR_MORE_DATA;
4766 }
4767
4768 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4769
4770 if (lpResumeIndex) *lpResumeIndex = dwLastResumeCount;
4771 *lpServicesReturned = dwServiceCount;
4772 *pcbBytesNeeded = dwRequiredSize;
4773
4774 /* If there was no services that matched */
4775 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
4776 {
4777 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4778 goto Done;
4779 }
4780
4781 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
4782 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4783 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4784
4785 dwRequiredSize = 0;
4786 for (ServiceEntry = &lpService->ServiceListEntry;
4787 ServiceEntry != &ServiceListHead;
4788 ServiceEntry = ServiceEntry->Flink)
4789 {
4790 CurrentService = CONTAINING_RECORD(ServiceEntry,
4791 SERVICE,
4792 ServiceListEntry);
4793
4794 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4795 continue;
4796
4797 dwState = SERVICE_ACTIVE;
4798 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4799 dwState = SERVICE_INACTIVE;
4800
4801 if ((dwState & dwServiceState) == 0)
4802 continue;
4803
4804 if (pszGroupName)
4805 {
4806 if (*pszGroupName == 0)
4807 {
4808 if (CurrentService->lpGroup != NULL)
4809 continue;
4810 }
4811 else
4812 {
4813 if ((CurrentService->lpGroup == NULL) ||
4814 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4815 continue;
4816 }
4817 }
4818
4819 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4820 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4821 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4822
4823 if (dwRequiredSize + dwSize <= cbBufSize)
4824 {
4825 /* Copy the service name */
4826 wcscpy(lpStringPtr,
4827 CurrentService->lpServiceName);
4828 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4829 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4830
4831 /* Copy the display name */
4832 wcscpy(lpStringPtr,
4833 CurrentService->lpDisplayName);
4834 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4835 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4836
4837 /* Copy the status information */
4838 memcpy(&lpStatusPtr->ServiceStatusProcess,
4839 &CurrentService->Status,
4840 sizeof(SERVICE_STATUS));
4841 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
4842 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4843
4844 lpStatusPtr++;
4845 dwRequiredSize += dwSize;
4846 }
4847 else
4848 {
4849 break;
4850 }
4851 }
4852
4853 if (dwError == 0)
4854 {
4855 *pcbBytesNeeded = 0;
4856 if (lpResumeIndex) *lpResumeIndex = 0;
4857 }
4858
4859 Done:;
4860 /* Unlock the service list */
4861
4862 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
4863
4864 return dwError;
4865 }
4866
4867
4868 /* Function 43 */
4869 DWORD RSendTSMessage(
4870 handle_t BindingHandle) /* FIXME */
4871 {
4872 UNIMPLEMENTED;
4873 return ERROR_CALL_NOT_IMPLEMENTED;
4874 }
4875
4876
4877 /* Function 44 */
4878 DWORD RCreateServiceWOW64A(
4879 handle_t BindingHandle,
4880 LPSTR lpServiceName,
4881 LPSTR lpDisplayName,
4882 DWORD dwDesiredAccess,
4883 DWORD dwServiceType,
4884 DWORD dwStartType,
4885 DWORD dwErrorControl,
4886 LPSTR lpBinaryPathName,
4887 LPSTR lpLoadOrderGroup,
4888 LPDWORD lpdwTagId,
4889 LPBYTE lpDependencies,
4890 DWORD dwDependSize,
4891 LPSTR lpServiceStartName,
4892 LPBYTE lpPassword,
4893 DWORD dwPwSize,
4894 LPSC_RPC_HANDLE lpServiceHandle)
4895 {
4896 UNIMPLEMENTED;
4897 return ERROR_CALL_NOT_IMPLEMENTED;
4898 }
4899
4900
4901 /* Function 45 */
4902 DWORD RCreateServiceWOW64W(
4903 handle_t BindingHandle,
4904 LPWSTR lpServiceName,
4905 LPWSTR lpDisplayName,
4906 DWORD dwDesiredAccess,
4907 DWORD dwServiceType,
4908 DWORD dwStartType,
4909 DWORD dwErrorControl,
4910 LPWSTR lpBinaryPathName,
4911 LPWSTR lpLoadOrderGroup,
4912 LPDWORD lpdwTagId,
4913 LPBYTE lpDependencies,
4914 DWORD dwDependSize,
4915 LPWSTR lpServiceStartName,
4916 LPBYTE lpPassword,
4917 DWORD dwPwSize,
4918 LPSC_RPC_HANDLE lpServiceHandle)
4919 {
4920 UNIMPLEMENTED;
4921 return ERROR_CALL_NOT_IMPLEMENTED;
4922 }
4923
4924
4925 /* Function 46 */
4926 DWORD RQueryServiceTagInfo(
4927 handle_t BindingHandle) /* FIXME */
4928 {
4929 UNIMPLEMENTED;
4930 return ERROR_CALL_NOT_IMPLEMENTED;
4931 }
4932
4933
4934 /* Function 47 */
4935 DWORD RNotifyServiceStatusChange(
4936 SC_RPC_HANDLE hService,
4937 SC_RPC_NOTIFY_PARAMS NotifyParams,
4938 GUID *pClientProcessGuid,
4939 GUID *pSCMProcessGuid,
4940 PBOOL pfCreateRemoteQueue,
4941 LPSC_NOTIFY_RPC_HANDLE phNotify)
4942 {
4943 UNIMPLEMENTED;
4944 return ERROR_CALL_NOT_IMPLEMENTED;
4945 }
4946
4947
4948 /* Function 48 */
4949 DWORD RGetNotifyResults(
4950 SC_NOTIFY_RPC_HANDLE hNotify,
4951 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
4952 {
4953 UNIMPLEMENTED;
4954 return ERROR_CALL_NOT_IMPLEMENTED;
4955 }
4956
4957
4958 /* Function 49 */
4959 DWORD RCloseNotifyHandle(
4960 LPSC_NOTIFY_RPC_HANDLE phNotify,
4961 PBOOL pfApcFired)
4962 {
4963 UNIMPLEMENTED;
4964 return ERROR_CALL_NOT_IMPLEMENTED;
4965 }
4966
4967
4968 /* Function 50 */
4969 DWORD RControlServiceExA(
4970 SC_RPC_HANDLE hService,
4971 DWORD dwControl,
4972 DWORD dwInfoLevel)
4973 {
4974 UNIMPLEMENTED;
4975 return ERROR_CALL_NOT_IMPLEMENTED;
4976 }
4977
4978
4979 /* Function 51 */
4980 DWORD RControlServiceExW(
4981 SC_RPC_HANDLE hService,
4982 DWORD dwControl,
4983 DWORD dwInfoLevel)
4984 {
4985 UNIMPLEMENTED;
4986 return ERROR_CALL_NOT_IMPLEMENTED;
4987 }
4988
4989
4990 /* Function 52 */
4991 DWORD RSendPnPMessage(
4992 handle_t BindingHandle) /* FIXME */
4993 {
4994 UNIMPLEMENTED;
4995 return ERROR_CALL_NOT_IMPLEMENTED;
4996 }
4997
4998
4999 /* Function 53 */
5000 DWORD RValidatePnPService(
5001 handle_t BindingHandle) /* FIXME */
5002 {
5003 UNIMPLEMENTED;
5004 return ERROR_CALL_NOT_IMPLEMENTED;
5005 }
5006
5007
5008 /* Function 54 */
5009 DWORD ROpenServiceStatusHandle(
5010 handle_t BindingHandle) /* FIXME */
5011 {
5012 UNIMPLEMENTED;
5013 return ERROR_CALL_NOT_IMPLEMENTED;
5014 }
5015
5016
5017 /* Function 55 */
5018 DWORD RFunction55(
5019 handle_t BindingHandle) /* FIXME */
5020 {
5021 UNIMPLEMENTED;
5022 return ERROR_CALL_NOT_IMPLEMENTED;
5023 }
5024
5025
5026 void __RPC_FAR * __RPC_USER midl_user_allocate(size_t len)
5027 {
5028 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5029 }
5030
5031
5032 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5033 {
5034 HeapFree(GetProcessHeap(), 0, ptr);
5035 }
5036
5037
5038 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5039 {
5040 }
5041
5042
5043 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5044 {
5045 }
5046
5047
5048 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5049 {
5050 }
5051
5052 /* EOF */