Fix a typo. Use lpStartServiceName instead of lpServiceName.
[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 /* FIXME: Handle lpServiceStartName propertly! */
1973 /* If a non driver and NULL for lpServiceStartName, write ObjectName as LocalSystem */
1974 if ((dwServiceType & SERVICE_WIN32) && (!lpServiceStartName))
1975 {
1976 dwError = RegSetValueExW(hServiceKey,
1977 L"ObjectName",
1978 0,
1979 REG_SZ,
1980 (LPBYTE)L"LocalSystem",
1981 24);
1982 if (dwError != ERROR_SUCCESS)
1983 goto done;
1984 }
1985
1986 if (lpPassword != NULL)
1987 {
1988 /* FIXME: Write password */
1989 }
1990
1991 dwError = ScmCreateServiceHandle(lpService,
1992 &hServiceHandle);
1993 if (dwError != ERROR_SUCCESS)
1994 goto done;
1995
1996 dwError = ScmCheckAccess(hServiceHandle,
1997 dwDesiredAccess);
1998 if (dwError != ERROR_SUCCESS)
1999 goto done;
2000
2001 lpService->dwRefCount = 1;
2002 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2003
2004 done:;
2005 if (hServiceKey != NULL)
2006 RegCloseKey(hServiceKey);
2007
2008 if (dwError == ERROR_SUCCESS)
2009 {
2010 DPRINT("hService %p\n", hServiceHandle);
2011 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2012
2013 if (lpdwTagId != NULL)
2014 *lpdwTagId = lpService->dwTag;
2015 }
2016 else
2017 {
2018 /* Release the display name buffer */
2019 if (lpService->lpServiceName != NULL)
2020 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2021
2022 if (hServiceHandle)
2023 {
2024 /* Remove the service handle */
2025 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2026 }
2027
2028 if (lpService != NULL)
2029 {
2030 /* FIXME: remove the service entry */
2031 }
2032 }
2033
2034 if (lpImagePath != NULL)
2035 HeapFree(GetProcessHeap(), 0, lpImagePath);
2036
2037 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2038
2039 return dwError;
2040 }
2041
2042
2043 /* Function 13 */
2044 DWORD REnumDependentServicesW(
2045 SC_RPC_HANDLE hService,
2046 DWORD dwServiceState,
2047 LPBYTE lpServices,
2048 DWORD cbBufSize,
2049 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2050 LPBOUNDED_DWORD_256K lpServicesReturned)
2051 {
2052 DWORD dwError = ERROR_SUCCESS;
2053 DWORD dwServicesReturned = 0;
2054 DWORD dwServiceCount;
2055 HKEY hServicesKey = NULL;
2056 LPSC_RPC_HANDLE hSCObject;
2057 PSERVICE_HANDLE hSvc;
2058 PSERVICE lpService = NULL;
2059 PSERVICE *lpServicesArray = NULL;
2060 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2061 LPWSTR lpStr;
2062
2063 *pcbBytesNeeded = 0;
2064 *lpServicesReturned = 0;
2065
2066 DPRINT("REnumDependentServicesW() called\n");
2067
2068 hSCObject = &hService;
2069 hSvc = (PSERVICE_HANDLE) *hSCObject;
2070 lpService = hSvc->ServiceEntry;
2071
2072 /* Check access rights */
2073 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2074 SC_MANAGER_ENUMERATE_SERVICE))
2075 {
2076 DPRINT1("Insufficient access rights! 0x%lx\n",
2077 hSvc->Handle.DesiredAccess);
2078 return ERROR_ACCESS_DENIED;
2079 }
2080
2081 /* Open the Services Reg key */
2082 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2083 L"System\\CurrentControlSet\\Services",
2084 0,
2085 KEY_READ,
2086 &hServicesKey);
2087 if (dwError != ERROR_SUCCESS)
2088 return dwError;
2089
2090 /* First determine the bytes needed and get the number of dependent services */
2091 dwError = Int_EnumDependentServicesW(hServicesKey,
2092 lpService,
2093 dwServiceState,
2094 NULL,
2095 pcbBytesNeeded,
2096 &dwServicesReturned);
2097 if (dwError != ERROR_SUCCESS)
2098 goto Done;
2099
2100 /* If buffer size is less than the bytes needed or pointer is null */
2101 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2102 {
2103 dwError = ERROR_MORE_DATA;
2104 goto Done;
2105 }
2106
2107 /* Allocate memory for array of service pointers */
2108 lpServicesArray = HeapAlloc(GetProcessHeap(),
2109 0,
2110 (dwServicesReturned + 1) * sizeof(PSERVICE));
2111 if (!lpServicesArray)
2112 {
2113 DPRINT1("Could not allocate a buffer!!\n");
2114 dwError = ERROR_NOT_ENOUGH_MEMORY;
2115 goto Done;
2116 }
2117
2118 dwServicesReturned = 0;
2119 *pcbBytesNeeded = 0;
2120
2121 dwError = Int_EnumDependentServicesW(hServicesKey,
2122 lpService,
2123 dwServiceState,
2124 lpServicesArray,
2125 pcbBytesNeeded,
2126 &dwServicesReturned);
2127 if (dwError != ERROR_SUCCESS)
2128 {
2129 goto Done;
2130 }
2131
2132 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2133 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2134
2135 /* Copy EnumDepenedentService to Buffer */
2136 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2137 {
2138 lpService = lpServicesArray[dwServiceCount];
2139
2140 /* Copy status info */
2141 memcpy(&lpServicesPtr->ServiceStatus,
2142 &lpService->Status,
2143 sizeof(SERVICE_STATUS));
2144
2145 /* Copy display name */
2146 wcscpy(lpStr, lpService->lpDisplayName);
2147 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2148 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2149
2150 /* Copy service name */
2151 wcscpy(lpStr, lpService->lpServiceName);
2152 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2153 lpStr += (wcslen(lpService->lpServiceName) + 1);
2154
2155 lpServicesPtr ++;
2156 }
2157
2158 *lpServicesReturned = dwServicesReturned;
2159
2160 Done:
2161 if (lpServicesArray != NULL)
2162 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2163
2164 RegCloseKey(hServicesKey);
2165
2166 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2167
2168 return dwError;
2169 }
2170
2171
2172 /* Function 14 */
2173 DWORD REnumServicesStatusW(
2174 SC_RPC_HANDLE hSCManager,
2175 DWORD dwServiceType,
2176 DWORD dwServiceState,
2177 LPBYTE lpBuffer,
2178 DWORD dwBufSize,
2179 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2180 LPBOUNDED_DWORD_256K lpServicesReturned,
2181 LPBOUNDED_DWORD_256K lpResumeHandle)
2182 {
2183 PMANAGER_HANDLE hManager;
2184 PSERVICE lpService;
2185 DWORD dwError = ERROR_SUCCESS;
2186 PLIST_ENTRY ServiceEntry;
2187 PSERVICE CurrentService;
2188 DWORD dwState;
2189 DWORD dwRequiredSize;
2190 DWORD dwServiceCount;
2191 DWORD dwSize;
2192 DWORD dwLastResumeCount = 0;
2193 LPENUM_SERVICE_STATUSW lpStatusPtr;
2194 LPWSTR lpStringPtr;
2195
2196 DPRINT("REnumServicesStatusW() called\n");
2197
2198 if (ScmShutdown)
2199 return ERROR_SHUTDOWN_IN_PROGRESS;
2200
2201 hManager = (PMANAGER_HANDLE)hSCManager;
2202 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2203 {
2204 DPRINT1("Invalid manager handle!\n");
2205 return ERROR_INVALID_HANDLE;
2206 }
2207
2208 *pcbBytesNeeded = 0;
2209 *lpServicesReturned = 0;
2210
2211 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2212 {
2213 DPRINT("Not a valid Service Type!\n");
2214 return ERROR_INVALID_PARAMETER;
2215 }
2216
2217 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2218 {
2219 DPRINT("Not a valid Service State!\n");
2220 return ERROR_INVALID_PARAMETER;
2221 }
2222
2223 /* Check access rights */
2224 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2225 SC_MANAGER_ENUMERATE_SERVICE))
2226 {
2227 DPRINT1("Insufficient access rights! 0x%lx\n",
2228 hManager->Handle.DesiredAccess);
2229 return ERROR_ACCESS_DENIED;
2230 }
2231
2232 if (lpResumeHandle)
2233 dwLastResumeCount = *lpResumeHandle;
2234
2235 /* FIXME: Lock the service list shared */
2236
2237 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2238 if (lpService == NULL)
2239 {
2240 dwError = ERROR_SUCCESS;
2241 goto Done;
2242 }
2243
2244 dwRequiredSize = 0;
2245 dwServiceCount = 0;
2246
2247 for (ServiceEntry = &lpService->ServiceListEntry;
2248 ServiceEntry != &ServiceListHead;
2249 ServiceEntry = ServiceEntry->Flink)
2250 {
2251 CurrentService = CONTAINING_RECORD(ServiceEntry,
2252 SERVICE,
2253 ServiceListEntry);
2254
2255 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2256 continue;
2257
2258 dwState = SERVICE_ACTIVE;
2259 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2260 dwState = SERVICE_INACTIVE;
2261
2262 if ((dwState & dwServiceState) == 0)
2263 continue;
2264
2265 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2266 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2267 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2268
2269 if (dwRequiredSize + dwSize > dwBufSize)
2270 {
2271 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2272 break;
2273 }
2274
2275 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2276 dwRequiredSize += dwSize;
2277 dwServiceCount++;
2278 dwLastResumeCount = CurrentService->dwResumeCount;
2279 }
2280
2281 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2282 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2283
2284 for (;
2285 ServiceEntry != &ServiceListHead;
2286 ServiceEntry = ServiceEntry->Flink)
2287 {
2288 CurrentService = CONTAINING_RECORD(ServiceEntry,
2289 SERVICE,
2290 ServiceListEntry);
2291
2292 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2293 continue;
2294
2295 dwState = SERVICE_ACTIVE;
2296 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2297 dwState = SERVICE_INACTIVE;
2298
2299 if ((dwState & dwServiceState) == 0)
2300 continue;
2301
2302 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2303 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2304 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2305
2306 dwError = ERROR_MORE_DATA;
2307 }
2308
2309 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2310
2311 if (lpResumeHandle)
2312 *lpResumeHandle = dwLastResumeCount;
2313
2314 *lpServicesReturned = dwServiceCount;
2315 *pcbBytesNeeded = dwRequiredSize;
2316
2317 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2318 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2319 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2320
2321 dwRequiredSize = 0;
2322 for (ServiceEntry = &lpService->ServiceListEntry;
2323 ServiceEntry != &ServiceListHead;
2324 ServiceEntry = ServiceEntry->Flink)
2325 {
2326 CurrentService = CONTAINING_RECORD(ServiceEntry,
2327 SERVICE,
2328 ServiceListEntry);
2329
2330 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2331 continue;
2332
2333 dwState = SERVICE_ACTIVE;
2334 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2335 dwState = SERVICE_INACTIVE;
2336
2337 if ((dwState & dwServiceState) == 0)
2338 continue;
2339
2340 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2341 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2342 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2343
2344 if (dwRequiredSize + dwSize > dwBufSize)
2345 break;
2346
2347 /* Copy the service name */
2348 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2349 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2350 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2351
2352 /* Copy the display name */
2353 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2354 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2355 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2356
2357 /* Copy the status information */
2358 memcpy(&lpStatusPtr->ServiceStatus,
2359 &CurrentService->Status,
2360 sizeof(SERVICE_STATUS));
2361
2362 lpStatusPtr++;
2363 dwRequiredSize += dwSize;
2364 }
2365
2366 if (dwError == 0)
2367 {
2368 *pcbBytesNeeded = 0;
2369 if (lpResumeHandle) *lpResumeHandle = 0;
2370 }
2371
2372 Done:;
2373 /* FIXME: Unlock the service list */
2374
2375 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2376
2377 return dwError;
2378 }
2379
2380
2381 /* Function 15 */
2382 DWORD ROpenSCManagerW(
2383 LPWSTR lpMachineName,
2384 LPWSTR lpDatabaseName,
2385 DWORD dwDesiredAccess,
2386 LPSC_RPC_HANDLE lpScHandle)
2387 {
2388 DWORD dwError;
2389 SC_HANDLE hHandle;
2390
2391 DPRINT("ROpenSCManagerW() called\n");
2392 DPRINT("lpMachineName = %p\n", lpMachineName);
2393 DPRINT("lpMachineName: %S\n", lpMachineName);
2394 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2395 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2396 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2397
2398 if (ScmShutdown)
2399 return ERROR_SHUTDOWN_IN_PROGRESS;
2400
2401 if (!lpScHandle)
2402 return ERROR_INVALID_PARAMETER;
2403
2404 dwError = ScmCreateManagerHandle(lpDatabaseName,
2405 &hHandle);
2406 if (dwError != ERROR_SUCCESS)
2407 {
2408 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2409 return dwError;
2410 }
2411
2412 /* Check the desired access */
2413 dwError = ScmCheckAccess(hHandle,
2414 dwDesiredAccess | SC_MANAGER_CONNECT);
2415 if (dwError != ERROR_SUCCESS)
2416 {
2417 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2418 HeapFree(GetProcessHeap(), 0, hHandle);
2419 return dwError;
2420 }
2421
2422 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2423 DPRINT("*hScm = %p\n", *lpScHandle);
2424
2425 DPRINT("ROpenSCManagerW() done\n");
2426
2427 return ERROR_SUCCESS;
2428 }
2429
2430
2431 /* Function 16 */
2432 DWORD ROpenServiceW(
2433 SC_RPC_HANDLE hSCManager,
2434 LPWSTR lpServiceName,
2435 DWORD dwDesiredAccess,
2436 LPSC_RPC_HANDLE lpServiceHandle)
2437 {
2438 PSERVICE lpService;
2439 PMANAGER_HANDLE hManager;
2440 SC_HANDLE hHandle;
2441 DWORD dwError;
2442
2443 DPRINT("ROpenServiceW() called\n");
2444 DPRINT("hSCManager = %p\n", hSCManager);
2445 DPRINT("lpServiceName = %p\n", lpServiceName);
2446 DPRINT("lpServiceName: %S\n", lpServiceName);
2447 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2448
2449 if (ScmShutdown)
2450 return ERROR_SHUTDOWN_IN_PROGRESS;
2451
2452 hManager = (PMANAGER_HANDLE)hSCManager;
2453 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2454 {
2455 DPRINT1("Invalid manager handle!\n");
2456 return ERROR_INVALID_HANDLE;
2457 }
2458
2459 if (!lpServiceHandle)
2460 return ERROR_INVALID_PARAMETER;
2461
2462 if (!lpServiceName)
2463 return ERROR_INVALID_ADDRESS;
2464
2465 /* FIXME: Lock the service list */
2466
2467 /* Get service database entry */
2468 lpService = ScmGetServiceEntryByName(lpServiceName);
2469 if (lpService == NULL)
2470 {
2471 DPRINT("Could not find a service!\n");
2472 return ERROR_SERVICE_DOES_NOT_EXIST;
2473 }
2474
2475 /* Create a service handle */
2476 dwError = ScmCreateServiceHandle(lpService,
2477 &hHandle);
2478 if (dwError != ERROR_SUCCESS)
2479 {
2480 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2481 return dwError;
2482 }
2483
2484 /* Check the desired access */
2485 dwError = ScmCheckAccess(hHandle,
2486 dwDesiredAccess);
2487 if (dwError != ERROR_SUCCESS)
2488 {
2489 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2490 HeapFree(GetProcessHeap(), 0, hHandle);
2491 return dwError;
2492 }
2493
2494 lpService->dwRefCount++;
2495 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2496
2497 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2498 DPRINT("*hService = %p\n", *lpServiceHandle);
2499
2500 DPRINT("ROpenServiceW() done\n");
2501
2502 return ERROR_SUCCESS;
2503 }
2504
2505
2506 /* Function 17 */
2507 DWORD RQueryServiceConfigW(
2508 SC_RPC_HANDLE hService,
2509 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2510 DWORD cbBufSize,
2511 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2512 {
2513 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2514 DWORD dwError = ERROR_SUCCESS;
2515 PSERVICE_HANDLE hSvc;
2516 PSERVICE lpService = NULL;
2517 HKEY hServiceKey = NULL;
2518 LPWSTR lpImagePath = NULL;
2519 LPWSTR lpServiceStartName = NULL;
2520 DWORD dwRequiredSize;
2521 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2522 WCHAR lpEmptyString[] = {0,0};
2523 LPWSTR lpStr;
2524
2525 DPRINT("RQueryServiceConfigW() called\n");
2526
2527 if (ScmShutdown)
2528 return ERROR_SHUTDOWN_IN_PROGRESS;
2529
2530 hSvc = (PSERVICE_HANDLE)hService;
2531 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2532 {
2533 DPRINT1("Invalid handle tag!\n");
2534 return ERROR_INVALID_HANDLE;
2535 }
2536
2537 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2538 SERVICE_QUERY_CONFIG))
2539 {
2540 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2541 return ERROR_ACCESS_DENIED;
2542 }
2543
2544 lpService = hSvc->ServiceEntry;
2545 if (lpService == NULL)
2546 {
2547 DPRINT1("lpService == NULL!\n");
2548 return ERROR_INVALID_HANDLE;
2549 }
2550
2551 /* FIXME: Lock the service database shared */
2552
2553 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2554 KEY_READ,
2555 &hServiceKey);
2556 if (dwError != ERROR_SUCCESS)
2557 goto Done;
2558
2559 dwError = ScmReadString(hServiceKey,
2560 L"ImagePath",
2561 &lpImagePath);
2562 if (dwError != ERROR_SUCCESS)
2563 goto Done;
2564
2565 ScmReadString(hServiceKey,
2566 L"ObjectName",
2567 &lpServiceStartName);
2568
2569 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2570
2571 if (lpImagePath != NULL)
2572 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2573 else
2574 dwRequiredSize += 2 * sizeof(WCHAR);
2575
2576 if (lpService->lpGroup != NULL)
2577 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2578 else
2579 dwRequiredSize += 2 * sizeof(WCHAR);
2580
2581 /* FIXME: Add Dependencies length*/
2582
2583 if (lpServiceStartName != NULL)
2584 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2585 else
2586 dwRequiredSize += 2 * sizeof(WCHAR);
2587
2588 if (lpService->lpDisplayName != NULL)
2589 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2590 else
2591 dwRequiredSize += 2 * sizeof(WCHAR);
2592
2593 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2594 {
2595 dwError = ERROR_INSUFFICIENT_BUFFER;
2596 }
2597 else
2598 {
2599 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2600 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2601 lpConfig->dwStartType = lpService->dwStartType;
2602 lpConfig->dwErrorControl = lpService->dwErrorControl;
2603 lpConfig->dwTagId = lpService->dwTag;
2604
2605 lpStr = (LPWSTR)(lpConfig + 1);
2606
2607 if (lpImagePath != NULL)
2608 {
2609 wcscpy(lpStr, lpImagePath);
2610 }
2611 else
2612 {
2613 wcscpy(lpStr, lpEmptyString);
2614 }
2615
2616 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2617 lpStr += (wcslen(lpStr) + 1);
2618
2619 if (lpService->lpGroup != NULL)
2620 {
2621 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2622 }
2623 else
2624 {
2625 wcscpy(lpStr, lpEmptyString);
2626 }
2627
2628 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2629 lpStr += (wcslen(lpStr) + 1);
2630
2631 /* FIXME: Append Dependencies */
2632 wcscpy(lpStr, lpEmptyString);
2633
2634 lpStr += (wcslen(lpStr) + 1);
2635 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2636
2637 if (lpServiceStartName != NULL)
2638 {
2639 wcscpy(lpStr, lpServiceStartName);
2640 }
2641 else
2642 {
2643 wcscpy(lpStr, lpEmptyString);
2644 }
2645
2646 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2647 lpStr += (wcslen(lpStr) + 1);
2648
2649 if (lpService->lpDisplayName != NULL)
2650 {
2651 wcscpy(lpStr, lpService->lpDisplayName);
2652 }
2653 else
2654 {
2655 wcscpy(lpStr, lpEmptyString);
2656 }
2657
2658 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2659 }
2660
2661 if (pcbBytesNeeded != NULL)
2662 *pcbBytesNeeded = dwRequiredSize;
2663
2664 Done:;
2665 if (lpImagePath != NULL)
2666 HeapFree(GetProcessHeap(), 0, lpImagePath);
2667
2668 if (lpServiceStartName != NULL)
2669 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2670
2671 if (hServiceKey != NULL)
2672 RegCloseKey(hServiceKey);
2673
2674 /* FIXME: Unlock the service database */
2675
2676 DPRINT("RQueryServiceConfigW() done\n");
2677
2678 return dwError;
2679 }
2680
2681
2682 /* Function 18 */
2683 DWORD RQueryServiceLockStatusW(
2684 SC_RPC_HANDLE hSCManager,
2685 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2686 DWORD cbBufSize,
2687 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2688 {
2689 UNIMPLEMENTED;
2690 return ERROR_CALL_NOT_IMPLEMENTED;
2691 }
2692
2693
2694 /* Function 19 */
2695 DWORD RStartServiceW(
2696 SC_RPC_HANDLE hService,
2697 DWORD argc,
2698 LPSTRING_PTRSW argv)
2699 {
2700 DWORD dwError = ERROR_SUCCESS;
2701 PSERVICE_HANDLE hSvc;
2702 PSERVICE lpService = NULL;
2703
2704 DPRINT("RStartServiceW() called\n");
2705
2706 if (ScmShutdown)
2707 return ERROR_SHUTDOWN_IN_PROGRESS;
2708
2709 hSvc = (PSERVICE_HANDLE)hService;
2710 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2711 {
2712 DPRINT1("Invalid handle tag!\n");
2713 return ERROR_INVALID_HANDLE;
2714 }
2715
2716 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2717 SERVICE_START))
2718 {
2719 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2720 return ERROR_ACCESS_DENIED;
2721 }
2722
2723 lpService = hSvc->ServiceEntry;
2724 if (lpService == NULL)
2725 {
2726 DPRINT1("lpService == NULL!\n");
2727 return ERROR_INVALID_HANDLE;
2728 }
2729
2730 if (lpService->dwStartType == SERVICE_DISABLED)
2731 return ERROR_SERVICE_DISABLED;
2732
2733 if (lpService->bDeleted)
2734 return ERROR_SERVICE_MARKED_FOR_DELETE;
2735
2736 if (argv) {
2737 UNIMPLEMENTED;
2738 argv = NULL;
2739 }
2740
2741 /* Start the service */
2742 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2743
2744 return dwError;
2745 }
2746
2747
2748 /* Function 20 */
2749 DWORD RGetServiceDisplayNameW(
2750 SC_RPC_HANDLE hSCManager,
2751 LPCWSTR lpServiceName,
2752 LPWSTR lpDisplayName,
2753 DWORD *lpcchBuffer)
2754 {
2755 // PMANAGER_HANDLE hManager;
2756 PSERVICE lpService;
2757 DWORD dwLength;
2758 DWORD dwError;
2759
2760 DPRINT("RGetServiceDisplayNameW() called\n");
2761 DPRINT("hSCManager = %p\n", hSCManager);
2762 DPRINT("lpServiceName: %S\n", lpServiceName);
2763 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2764 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2765
2766 // hManager = (PMANAGER_HANDLE)hSCManager;
2767 // if (hManager->Handle.Tag != MANAGER_TAG)
2768 // {
2769 // DPRINT1("Invalid manager handle!\n");
2770 // return ERROR_INVALID_HANDLE;
2771 // }
2772
2773 /* Get service database entry */
2774 lpService = ScmGetServiceEntryByName(lpServiceName);
2775 if (lpService == NULL)
2776 {
2777 DPRINT1("Could not find a service!\n");
2778
2779 /* If the service could not be found and lpcchBuffer is less than 2, windows
2780 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2781 if (*lpcchBuffer < 2)
2782 {
2783 *lpcchBuffer = 2;
2784 if (lpDisplayName != NULL)
2785 {
2786 *lpDisplayName = '\0';
2787 }
2788 }
2789
2790 return ERROR_SERVICE_DOES_NOT_EXIST;
2791 }
2792
2793 if (!lpService->lpDisplayName)
2794 {
2795 dwLength = wcslen(lpService->lpServiceName);
2796
2797 if (lpDisplayName != NULL &&
2798 *lpcchBuffer > dwLength)
2799 {
2800 wcscpy(lpDisplayName, lpService->lpServiceName);
2801 }
2802 }
2803 else
2804 {
2805 dwLength = wcslen(lpService->lpDisplayName);
2806
2807 if (lpDisplayName != NULL &&
2808 *lpcchBuffer > dwLength)
2809 {
2810 wcscpy(lpDisplayName, lpService->lpDisplayName);
2811 }
2812 }
2813
2814 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2815
2816 *lpcchBuffer = dwLength;
2817
2818 return dwError;
2819 }
2820
2821
2822 /* Function 21 */
2823 DWORD RGetServiceKeyNameW(
2824 SC_RPC_HANDLE hSCManager,
2825 LPCWSTR lpDisplayName,
2826 LPWSTR lpServiceName,
2827 DWORD *lpcchBuffer)
2828 {
2829 // PMANAGER_HANDLE hManager;
2830 PSERVICE lpService;
2831 DWORD dwLength;
2832 DWORD dwError;
2833
2834 DPRINT("RGetServiceKeyNameW() called\n");
2835 DPRINT("hSCManager = %p\n", hSCManager);
2836 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2837 DPRINT("lpServiceName: %p\n", lpServiceName);
2838 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2839
2840 // hManager = (PMANAGER_HANDLE)hSCManager;
2841 // if (hManager->Handle.Tag != MANAGER_TAG)
2842 // {
2843 // DPRINT1("Invalid manager handle!\n");
2844 // return ERROR_INVALID_HANDLE;
2845 // }
2846
2847 /* Get service database entry */
2848 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2849 if (lpService == NULL)
2850 {
2851 DPRINT1("Could not find a service!\n");
2852
2853 /* If the service could not be found and lpcchBuffer is less than 2, windows
2854 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2855 if (*lpcchBuffer < 2)
2856 {
2857 *lpcchBuffer = 2;
2858 if (lpServiceName != NULL)
2859 {
2860 *lpServiceName = '\0';
2861 }
2862 }
2863
2864 return ERROR_SERVICE_DOES_NOT_EXIST;
2865 }
2866
2867 dwLength = wcslen(lpService->lpServiceName);
2868
2869 if (lpServiceName != NULL &&
2870 *lpcchBuffer > dwLength)
2871 {
2872 wcscpy(lpServiceName, lpService->lpServiceName);
2873 *lpcchBuffer = dwLength;
2874 return ERROR_SUCCESS;
2875 }
2876
2877 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2878
2879 *lpcchBuffer = dwLength;
2880
2881 return dwError;
2882 }
2883
2884
2885 /* Function 22 */
2886 DWORD RI_ScSetServiceBitsA(
2887 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
2888 DWORD dwServiceBits,
2889 int bSetBitsOn,
2890 int bUpdateImmediately,
2891 char *lpString)
2892 {
2893 UNIMPLEMENTED;
2894 return ERROR_CALL_NOT_IMPLEMENTED;
2895 }
2896
2897
2898 /* Function 23 */
2899 DWORD RChangeServiceConfigA(
2900 SC_RPC_HANDLE hService,
2901 DWORD dwServiceType,
2902 DWORD dwStartType,
2903 DWORD dwErrorControl,
2904 LPSTR lpBinaryPathName,
2905 LPSTR lpLoadOrderGroup,
2906 LPDWORD lpdwTagId,
2907 LPSTR lpDependencies,
2908 DWORD dwDependSize,
2909 LPSTR lpServiceStartName,
2910 LPBYTE lpPassword,
2911 DWORD dwPwSize,
2912 LPSTR lpDisplayName)
2913 {
2914 DWORD dwError = ERROR_SUCCESS;
2915 PSERVICE_HANDLE hSvc;
2916 PSERVICE lpService = NULL;
2917 HKEY hServiceKey = NULL;
2918 LPWSTR lpDisplayNameW = NULL;
2919 // LPWSTR lpBinaryPathNameW = NULL;
2920 LPWSTR lpLoadOrderGroupW = NULL;
2921 LPWSTR lpDependenciesW = NULL;
2922 // LPWSTR lpPasswordW = NULL;
2923
2924 DPRINT("RChangeServiceConfigA() called\n");
2925 DPRINT("dwServiceType = %lu\n", dwServiceType);
2926 DPRINT("dwStartType = %lu\n", dwStartType);
2927 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2928 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2929 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2930 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2931
2932 if (ScmShutdown)
2933 return ERROR_SHUTDOWN_IN_PROGRESS;
2934
2935 hSvc = (PSERVICE_HANDLE)hService;
2936 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2937 {
2938 DPRINT1("Invalid handle tag!\n");
2939 return ERROR_INVALID_HANDLE;
2940 }
2941
2942 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2943 SERVICE_CHANGE_CONFIG))
2944 {
2945 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2946 return ERROR_ACCESS_DENIED;
2947 }
2948
2949 lpService = hSvc->ServiceEntry;
2950 if (lpService == NULL)
2951 {
2952 DPRINT1("lpService == NULL!\n");
2953 return ERROR_INVALID_HANDLE;
2954 }
2955
2956 /* FIXME: Lock database exclusively */
2957
2958 if (lpService->bDeleted)
2959 {
2960 /* FIXME: Unlock database */
2961 DPRINT1("The service has already been marked for delete!\n");
2962 return ERROR_SERVICE_MARKED_FOR_DELETE;
2963 }
2964
2965 /* Open the service key */
2966 dwError = ScmOpenServiceKey(lpService->szServiceName,
2967 KEY_SET_VALUE,
2968 &hServiceKey);
2969 if (dwError != ERROR_SUCCESS)
2970 goto done;
2971
2972 /* Write service data to the registry */
2973
2974 if (lpDisplayName != NULL && *lpDisplayName != 0)
2975 {
2976 /* Set the display name */
2977 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2978 0,
2979 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
2980 if (lpDisplayNameW == NULL)
2981 {
2982 dwError = ERROR_NOT_ENOUGH_MEMORY;
2983 goto done;
2984 }
2985
2986 MultiByteToWideChar(CP_ACP,
2987 0,
2988 lpDisplayName,
2989 -1,
2990 lpDisplayNameW,
2991 strlen(lpDisplayName) + 1);
2992
2993 RegSetValueExW(hServiceKey,
2994 L"DisplayName",
2995 0,
2996 REG_SZ,
2997 (LPBYTE)lpDisplayNameW,
2998 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2999
3000 /* Update lpService->lpDisplayName */
3001 if (lpService->lpDisplayName)
3002 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3003
3004 lpService->lpDisplayName = lpDisplayNameW;
3005 }
3006
3007 if (dwServiceType != SERVICE_NO_CHANGE)
3008 {
3009 /* Set the service type */
3010 dwError = RegSetValueExW(hServiceKey,
3011 L"Type",
3012 0,
3013 REG_DWORD,
3014 (LPBYTE)&dwServiceType,
3015 sizeof(DWORD));
3016 if (dwError != ERROR_SUCCESS)
3017 goto done;
3018
3019 lpService->Status.dwServiceType = dwServiceType;
3020 }
3021
3022 if (dwStartType != SERVICE_NO_CHANGE)
3023 {
3024 /* Set the start value */
3025 dwError = RegSetValueExW(hServiceKey,
3026 L"Start",
3027 0,
3028 REG_DWORD,
3029 (LPBYTE)&dwStartType,
3030 sizeof(DWORD));
3031 if (dwError != ERROR_SUCCESS)
3032 goto done;
3033
3034 lpService->dwStartType = dwStartType;
3035 }
3036
3037 if (dwErrorControl != SERVICE_NO_CHANGE)
3038 {
3039 /* Set the error control value */
3040 dwError = RegSetValueExW(hServiceKey,
3041 L"ErrorControl",
3042 0,
3043 REG_DWORD,
3044 (LPBYTE)&dwErrorControl,
3045 sizeof(DWORD));
3046 if (dwError != ERROR_SUCCESS)
3047 goto done;
3048
3049 lpService->dwErrorControl = dwErrorControl;
3050 }
3051
3052 #if 0
3053 /* FIXME: set the new ImagePath value */
3054
3055 /* Set the image path */
3056 if (dwServiceType & SERVICE_WIN32)
3057 {
3058 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3059 {
3060 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3061 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, wcslen(lpBinaryPathNameW)+1);
3062 dwError = RegSetValueExW(hServiceKey,
3063 L"ImagePath",
3064 0,
3065 REG_EXPAND_SZ,
3066 (LPBYTE)lpBinaryPathNameW,
3067 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3068 if (dwError != ERROR_SUCCESS)
3069 goto done;
3070 }
3071 }
3072 else if (dwServiceType & SERVICE_DRIVER)
3073 {
3074 if (lpImagePath != NULL && *lpImagePath != 0)
3075 {
3076 dwError = RegSetValueExW(hServiceKey,
3077 L"ImagePath",
3078 0,
3079 REG_EXPAND_SZ,
3080 (LPBYTE)lpImagePath,
3081 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3082 if (dwError != ERROR_SUCCESS)
3083 goto done;
3084 }
3085 }
3086 #endif
3087
3088 /* Set the group name */
3089 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3090 {
3091 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3092 0,
3093 (strlen(lpLoadOrderGroup)+1) * sizeof(WCHAR));
3094 if (lpLoadOrderGroupW == NULL)
3095 {
3096 dwError = ERROR_NOT_ENOUGH_MEMORY;
3097 goto done;
3098 }
3099
3100 MultiByteToWideChar(CP_ACP,
3101 0,
3102 lpLoadOrderGroup,
3103 -1,
3104 lpLoadOrderGroupW,
3105 wcslen(lpLoadOrderGroupW) + 1);
3106
3107 dwError = RegSetValueExW(hServiceKey,
3108 L"Group",
3109 0,
3110 REG_SZ,
3111 (LPBYTE)lpLoadOrderGroupW,
3112 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3113 if (dwError != ERROR_SUCCESS)
3114 goto done;
3115
3116 /* FIXME: Update lpService->lpServiceGroup */
3117
3118 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3119 }
3120
3121 if (lpdwTagId != NULL)
3122 {
3123 dwError = ScmAssignNewTag(lpService);
3124 if (dwError != ERROR_SUCCESS)
3125 goto done;
3126
3127 dwError = RegSetValueExW(hServiceKey,
3128 L"Tag",
3129 0,
3130 REG_DWORD,
3131 (LPBYTE)&lpService->dwTag,
3132 sizeof(DWORD));
3133 if (dwError != ERROR_SUCCESS)
3134 goto done;
3135
3136 *lpdwTagId = lpService->dwTag;
3137 }
3138
3139 /* Write dependencies */
3140 if (lpDependencies != NULL && *lpDependencies != 0)
3141 {
3142 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3143 0,
3144 (strlen(lpDependencies)+1) * sizeof(WCHAR));
3145 if (lpDependenciesW == NULL)
3146 {
3147 dwError = ERROR_NOT_ENOUGH_MEMORY;
3148 goto done;
3149 }
3150
3151 MultiByteToWideChar(CP_ACP,
3152 0,
3153 lpDependencies,
3154 dwDependSize,
3155 lpDependenciesW,
3156 wcslen(lpDependenciesW)+1);
3157
3158 dwError = ScmWriteDependencies(hServiceKey,
3159 (LPWSTR)lpDependenciesW,
3160 dwDependSize);
3161
3162 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3163 }
3164
3165 if (lpPassword != NULL)
3166 {
3167 /* FIXME: Write password */
3168 }
3169
3170 /* FIXME: Unlock database */
3171
3172 done:
3173 if (hServiceKey != NULL)
3174 RegCloseKey(hServiceKey);
3175
3176 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3177
3178 return dwError;
3179 }
3180
3181
3182 /* Function 24 */
3183 DWORD RCreateServiceA(
3184 SC_RPC_HANDLE hSCManager,
3185 LPSTR lpServiceName,
3186 LPSTR lpDisplayName,
3187 DWORD dwDesiredAccess,
3188 DWORD dwServiceType,
3189 DWORD dwStartType,
3190 DWORD dwErrorControl,
3191 LPSTR lpBinaryPathName,
3192 LPSTR lpLoadOrderGroup,
3193 LPDWORD lpdwTagId,
3194 LPBYTE lpDependencies,
3195 DWORD dwDependSize,
3196 LPSTR lpServiceStartName,
3197 LPBYTE lpPassword,
3198 DWORD dwPwSize,
3199 LPSC_RPC_HANDLE lpServiceHandle)
3200 {
3201 UNIMPLEMENTED;
3202 return ERROR_CALL_NOT_IMPLEMENTED;
3203 }
3204
3205
3206 /* Function 25 */
3207 DWORD REnumDependentServicesA(
3208 SC_RPC_HANDLE hService,
3209 DWORD dwServiceState,
3210 LPBYTE lpServices,
3211 DWORD cbBufSize,
3212 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3213 LPBOUNDED_DWORD_256K lpServicesReturned)
3214 {
3215 DWORD dwError = ERROR_SUCCESS;
3216 DWORD dwServicesReturned = 0;
3217 DWORD dwServiceCount;
3218 HKEY hServicesKey = NULL;
3219 LPSC_RPC_HANDLE hSCObject;
3220 PSERVICE_HANDLE hSvc;
3221 PSERVICE lpService = NULL;
3222 PSERVICE *lpServicesArray = NULL;
3223 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3224 LPSTR lpStr;
3225
3226 *pcbBytesNeeded = 0;
3227 *lpServicesReturned = 0;
3228
3229 DPRINT("REnumDependentServicesA() called\n");
3230
3231 hSCObject = &hService;
3232 hSvc = (PSERVICE_HANDLE) *hSCObject;
3233 lpService = hSvc->ServiceEntry;
3234
3235 /* Check access rights */
3236 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3237 SC_MANAGER_ENUMERATE_SERVICE))
3238 {
3239 DPRINT1("Insufficient access rights! 0x%lx\n",
3240 hSvc->Handle.DesiredAccess);
3241 return ERROR_ACCESS_DENIED;
3242 }
3243
3244 /* Open the Services Reg key */
3245 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3246 L"System\\CurrentControlSet\\Services",
3247 0,
3248 KEY_READ,
3249 &hServicesKey);
3250
3251 if (dwError != ERROR_SUCCESS)
3252 return dwError;
3253
3254 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3255 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3256 are the same for both. Verified in WINXP. */
3257
3258 /* First determine the bytes needed and get the number of dependent services*/
3259 dwError = Int_EnumDependentServicesW(hServicesKey,
3260 lpService,
3261 dwServiceState,
3262 NULL,
3263 pcbBytesNeeded,
3264 &dwServicesReturned);
3265 if (dwError != ERROR_SUCCESS)
3266 goto Done;
3267
3268 /* If buffer size is less than the bytes needed or pointer is null*/
3269 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3270 {
3271 dwError = ERROR_MORE_DATA;
3272 goto Done;
3273 }
3274
3275 /* Allocate memory for array of service pointers */
3276 lpServicesArray = HeapAlloc(GetProcessHeap(),
3277 0,
3278 (dwServicesReturned + 1) * sizeof(PSERVICE));
3279 if (!lpServicesArray)
3280 {
3281 DPRINT1("Could not allocate a buffer!!\n");
3282 dwError = ERROR_NOT_ENOUGH_MEMORY;
3283 goto Done;
3284 }
3285
3286 dwServicesReturned = 0;
3287 *pcbBytesNeeded = 0;
3288
3289 dwError = Int_EnumDependentServicesW(hServicesKey,
3290 lpService,
3291 dwServiceState,
3292 lpServicesArray,
3293 pcbBytesNeeded,
3294 &dwServicesReturned);
3295 if (dwError != ERROR_SUCCESS)
3296 {
3297 goto Done;
3298 }
3299
3300 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3301 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3302
3303 /* Copy EnumDepenedentService to Buffer */
3304 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3305 {
3306 lpService = lpServicesArray[dwServiceCount];
3307
3308 /* Copy the status info */
3309 memcpy(&lpServicesPtr->ServiceStatus,
3310 &lpService->Status,
3311 sizeof(SERVICE_STATUS));
3312
3313 /* Copy display name */
3314 WideCharToMultiByte(CP_ACP,
3315 0,
3316 lpService->lpDisplayName,
3317 -1,
3318 lpStr,
3319 wcslen(lpService->lpDisplayName),
3320 0,
3321 0);
3322 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3323 lpStr += strlen(lpStr) + 1;
3324
3325 /* Copy service name */
3326 WideCharToMultiByte(CP_ACP,
3327 0,
3328 lpService->lpServiceName,
3329 -1,
3330 lpStr,
3331 wcslen(lpService->lpServiceName),
3332 0,
3333 0);
3334 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3335 lpStr += strlen(lpStr) + 1;
3336
3337 lpServicesPtr ++;
3338 }
3339
3340 *lpServicesReturned = dwServicesReturned;
3341
3342 Done:
3343 if (lpServicesArray)
3344 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3345
3346 RegCloseKey(hServicesKey);
3347
3348 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3349
3350 return dwError;
3351 }
3352
3353
3354 /* Function 26 */
3355 DWORD REnumServicesStatusA(
3356 SC_RPC_HANDLE hSCManager,
3357 DWORD dwServiceType,
3358 DWORD dwServiceState,
3359 LPBYTE lpBuffer,
3360 DWORD dwBufSize,
3361 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3362 LPBOUNDED_DWORD_256K lpServicesReturned,
3363 LPBOUNDED_DWORD_256K lpResumeHandle)
3364 {
3365 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3366 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3367 LPWSTR lpStringPtrW;
3368 LPSTR lpStringPtrA;
3369 DWORD dwError;
3370 DWORD dwServiceCount;
3371
3372 DPRINT("REnumServicesStatusA() called\n");
3373
3374 if ((dwBufSize > 0) && (lpBuffer))
3375 {
3376 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3377 if (!lpStatusPtrW)
3378 {
3379 DPRINT1("Failed to allocate buffer!\n");
3380 return ERROR_NOT_ENOUGH_MEMORY;
3381 }
3382 }
3383
3384 dwError = REnumServicesStatusW(hSCManager,
3385 dwServiceType,
3386 dwServiceState,
3387 (LPBYTE)lpStatusPtrW,
3388 dwBufSize,
3389 pcbBytesNeeded,
3390 lpServicesReturned,
3391 lpResumeHandle);
3392
3393 /* if no services were returned then we are Done */
3394 if (*lpServicesReturned == 0)
3395 goto Done;
3396
3397 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3398 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3399 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3400 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3401 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3402
3403 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3404 {
3405 /* Copy the service name */
3406 WideCharToMultiByte(CP_ACP,
3407 0,
3408 lpStringPtrW,
3409 -1,
3410 lpStringPtrA,
3411 wcslen(lpStringPtrW),
3412 0,
3413 0);
3414
3415 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3416 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3417 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3418
3419 /* Copy the display name */
3420 WideCharToMultiByte(CP_ACP,
3421 0,
3422 lpStringPtrW,
3423 -1,
3424 lpStringPtrA,
3425 wcslen(lpStringPtrW),
3426 0,
3427 0);
3428
3429 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3430 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3431 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3432
3433 /* Copy the status information */
3434 memcpy(&lpStatusPtrA->ServiceStatus,
3435 &lpStatusPtrW->ServiceStatus,
3436 sizeof(SERVICE_STATUS));
3437
3438 lpStatusPtrA++;
3439 }
3440
3441 Done:;
3442 if (lpStatusPtrW)
3443 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3444
3445 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3446
3447 return dwError;
3448 }
3449
3450
3451 /* Function 27 */
3452 DWORD ROpenSCManagerA(
3453 LPSTR lpMachineName,
3454 LPSTR lpDatabaseName,
3455 DWORD dwDesiredAccess,
3456 LPSC_RPC_HANDLE lpScHandle)
3457 {
3458 UNICODE_STRING MachineName;
3459 UNICODE_STRING DatabaseName;
3460 DWORD dwError;
3461
3462 DPRINT("ROpenSCManagerA() called\n");
3463
3464 if (lpMachineName)
3465 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3466 lpMachineName);
3467
3468 if (lpDatabaseName)
3469 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3470 lpDatabaseName);
3471
3472 dwError = ROpenSCManagerW(//BindingHandle,
3473 lpMachineName ? MachineName.Buffer : NULL,
3474 lpDatabaseName ? DatabaseName.Buffer : NULL,
3475 dwDesiredAccess,
3476 lpScHandle);
3477
3478 if (lpMachineName)
3479 RtlFreeUnicodeString(&MachineName);
3480
3481 if (lpDatabaseName)
3482 RtlFreeUnicodeString(&DatabaseName);
3483
3484 return dwError;
3485 }
3486
3487
3488 /* Function 28 */
3489 DWORD ROpenServiceA(
3490 SC_RPC_HANDLE hSCManager,
3491 LPSTR lpServiceName,
3492 DWORD dwDesiredAccess,
3493 LPSC_RPC_HANDLE lpServiceHandle)
3494 {
3495 UNICODE_STRING ServiceName;
3496 DWORD dwError;
3497
3498 DPRINT("ROpenServiceA() called\n");
3499
3500 if (lpServiceName)
3501 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3502 lpServiceName);
3503
3504 dwError = ROpenServiceW(//BindingHandle,
3505 hSCManager,
3506 lpServiceName ? ServiceName.Buffer : NULL,
3507 dwDesiredAccess,
3508 lpServiceHandle);
3509
3510 if (lpServiceName)
3511 RtlFreeUnicodeString(&ServiceName);
3512
3513 return dwError;
3514 }
3515
3516
3517 /* Function 29 */
3518 DWORD RQueryServiceConfigA(
3519 SC_RPC_HANDLE hService,
3520 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3521 DWORD cbBufSize,
3522 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3523 {
3524 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3525 DWORD dwError = ERROR_SUCCESS;
3526 PSERVICE_HANDLE hSvc;
3527 PSERVICE lpService = NULL;
3528 HKEY hServiceKey = NULL;
3529 LPWSTR lpImagePath = NULL;
3530 LPWSTR lpServiceStartName = NULL;
3531 DWORD dwRequiredSize;
3532 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3533 CHAR lpEmptyString[]={0,0};
3534 LPSTR lpStr;
3535
3536 DPRINT("RQueryServiceConfigA() called\n");
3537
3538 if (ScmShutdown)
3539 return ERROR_SHUTDOWN_IN_PROGRESS;
3540
3541 hSvc = (PSERVICE_HANDLE)hService;
3542 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3543 {
3544 DPRINT1("Invalid handle tag!\n");
3545 return ERROR_INVALID_HANDLE;
3546 }
3547
3548 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3549 SERVICE_QUERY_CONFIG))
3550 {
3551 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3552 return ERROR_ACCESS_DENIED;
3553 }
3554
3555 lpService = hSvc->ServiceEntry;
3556 if (lpService == NULL)
3557 {
3558 DPRINT1("lpService == NULL!\n");
3559 return ERROR_INVALID_HANDLE;
3560 }
3561
3562 /* FIXME: Lock the service database shared */
3563
3564 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3565 KEY_READ,
3566 &hServiceKey);
3567 if (dwError != ERROR_SUCCESS)
3568 goto Done;
3569
3570 dwError = ScmReadString(hServiceKey,
3571 L"ImagePath",
3572 &lpImagePath);
3573 if (dwError != ERROR_SUCCESS)
3574 goto Done;
3575
3576 ScmReadString(hServiceKey,
3577 L"ObjectName",
3578 &lpServiceStartName);
3579
3580 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3581
3582 if (lpImagePath != NULL)
3583 dwRequiredSize += wcslen(lpImagePath) + 1;
3584 else
3585 dwRequiredSize += 2;
3586
3587 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3588 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
3589 else
3590 dwRequiredSize += 2;
3591
3592 /* FIXME: Add Dependencies length*/
3593 dwRequiredSize += 2;
3594
3595 if (lpServiceStartName != NULL)
3596 dwRequiredSize += wcslen(lpServiceStartName) + 1;
3597 else
3598 dwRequiredSize += 2;
3599
3600 if (lpService->lpDisplayName != NULL)
3601 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
3602 else
3603 dwRequiredSize += 2;
3604
3605 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3606 {
3607 dwError = ERROR_INSUFFICIENT_BUFFER;
3608 }
3609 else
3610 {
3611 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
3612 lpConfig->dwServiceType = lpService->Status.dwServiceType;
3613 lpConfig->dwStartType = lpService->dwStartType;
3614 lpConfig->dwErrorControl = lpService->dwErrorControl;
3615 lpConfig->dwTagId = lpService->dwTag;
3616
3617 lpStr = (LPSTR)(lpServiceConfig + 1);
3618
3619 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3620 Verified in WINXP*/
3621
3622 if (lpImagePath)
3623 {
3624 WideCharToMultiByte(CP_ACP,
3625 0,
3626 lpImagePath,
3627 -1,
3628 lpStr,
3629 wcslen(lpImagePath)+1,
3630 0,
3631 0);
3632 }
3633 else
3634 {
3635 strcpy(lpStr, lpEmptyString);
3636 }
3637
3638 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3639 lpStr += (strlen((LPSTR)lpStr) + 1);
3640
3641 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
3642 {
3643 WideCharToMultiByte(CP_ACP,
3644 0,
3645 lpService->lpGroup->lpGroupName,
3646 -1,
3647 lpStr,
3648 wcslen(lpService->lpGroup->lpGroupName)+1,
3649 0,
3650 0);
3651 }
3652 else
3653 {
3654 strcpy(lpStr, lpEmptyString);
3655 }
3656
3657 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3658 lpStr += (strlen(lpStr) + 1);
3659
3660 /* FIXME: Append Dependencies */
3661 strcpy(lpStr, lpEmptyString);
3662
3663 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3664 lpStr += (strlen(lpStr) + 1);
3665
3666 if (lpServiceStartName)
3667 {
3668 WideCharToMultiByte(CP_ACP,
3669 0,
3670 lpServiceStartName,
3671 -1,
3672 lpStr,
3673 wcslen(lpServiceStartName)+1,
3674 0,
3675 0);
3676 }
3677 else
3678 {
3679 strcpy(lpStr, lpEmptyString);
3680 }
3681
3682 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3683 lpStr += (strlen(lpStr) + 1);
3684
3685 if (lpService->lpDisplayName)
3686 {
3687 WideCharToMultiByte(CP_ACP,
3688 0,
3689 lpService->lpDisplayName,
3690 -1,
3691 lpStr,
3692 wcslen(lpService->lpDisplayName)+1,
3693 0,
3694 0);
3695 }
3696 else
3697 {
3698 strcpy(lpStr, lpEmptyString);
3699 }
3700
3701 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3702 }
3703
3704 if (pcbBytesNeeded != NULL)
3705 *pcbBytesNeeded = dwRequiredSize;
3706
3707 Done:;
3708 if (lpImagePath != NULL)
3709 HeapFree(GetProcessHeap(), 0, lpImagePath);
3710
3711 if (lpServiceStartName != NULL)
3712 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3713
3714 if (hServiceKey != NULL)
3715 RegCloseKey(hServiceKey);
3716
3717 /* FIXME: Unlock the service database */
3718
3719 DPRINT("RQueryServiceConfigA() done\n");
3720
3721 return dwError;
3722 }
3723
3724
3725 /* Function 30 */
3726 DWORD RQueryServiceLockStatusA(
3727 SC_RPC_HANDLE hSCManager,
3728 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
3729 DWORD cbBufSize,
3730 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3731 {
3732 UNIMPLEMENTED;
3733 return ERROR_CALL_NOT_IMPLEMENTED;
3734 }
3735
3736
3737 /* Function 31 */
3738 DWORD RStartServiceA(
3739 SC_RPC_HANDLE hService,
3740 DWORD argc,
3741 LPSTRING_PTRSA argv)
3742 {
3743 DWORD dwError = ERROR_SUCCESS;
3744 PSERVICE_HANDLE hSvc;
3745 PSERVICE lpService = NULL;
3746
3747 DPRINT1("RStartServiceA() called\n");
3748
3749 if (ScmShutdown)
3750 return ERROR_SHUTDOWN_IN_PROGRESS;
3751
3752 hSvc = (PSERVICE_HANDLE)hService;
3753 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3754 {
3755 DPRINT1("Invalid handle tag!\n");
3756 return ERROR_INVALID_HANDLE;
3757 }
3758
3759 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3760 SERVICE_START))
3761 {
3762 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3763 return ERROR_ACCESS_DENIED;
3764 }
3765
3766 lpService = hSvc->ServiceEntry;
3767 if (lpService == NULL)
3768 {
3769 DPRINT1("lpService == NULL!\n");
3770 return ERROR_INVALID_HANDLE;
3771 }
3772
3773 if (lpService->dwStartType == SERVICE_DISABLED)
3774 return ERROR_SERVICE_DISABLED;
3775
3776 if (lpService->bDeleted)
3777 return ERROR_SERVICE_MARKED_FOR_DELETE;
3778
3779 /* FIXME: Convert argument vector to Unicode */
3780
3781 /* Start the service */
3782 dwError = ScmStartService(lpService, 0, NULL);
3783
3784 /* FIXME: Free argument vector */
3785
3786 return dwError;
3787 }
3788
3789
3790 /* Function 32 */
3791 DWORD RGetServiceDisplayNameA(
3792 SC_RPC_HANDLE hSCManager,
3793 LPCSTR lpServiceName,
3794 LPSTR lpDisplayName,
3795 LPBOUNDED_DWORD_4K lpcchBuffer)
3796 {
3797 // PMANAGER_HANDLE hManager;
3798 PSERVICE lpService = NULL;
3799 DWORD dwLength;
3800 DWORD dwError;
3801 LPWSTR lpServiceNameW;
3802
3803 DPRINT("RGetServiceDisplayNameA() called\n");
3804 DPRINT("hSCManager = %p\n", hSCManager);
3805 DPRINT("lpServiceName: %s\n", lpServiceName);
3806 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3807 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3808
3809 // hManager = (PMANAGER_HANDLE)hSCManager;
3810 // if (hManager->Handle.Tag != MANAGER_TAG)
3811 // {
3812 // DPRINT1("Invalid manager handle!\n");
3813 // return ERROR_INVALID_HANDLE;
3814 // }
3815
3816 if (lpServiceName != NULL)
3817 {
3818 dwLength = strlen(lpServiceName) + 1;
3819 lpServiceNameW = HeapAlloc(GetProcessHeap(),
3820 HEAP_ZERO_MEMORY,
3821 dwLength * sizeof(WCHAR));
3822 if (!lpServiceNameW)
3823 return ERROR_NOT_ENOUGH_MEMORY;
3824
3825 MultiByteToWideChar(CP_ACP,
3826 0,
3827 lpServiceName,
3828 -1,
3829 lpServiceNameW,
3830 dwLength);
3831
3832 lpService = ScmGetServiceEntryByName(lpServiceNameW);
3833
3834 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3835 }
3836
3837 if (lpService == NULL)
3838 {
3839 DPRINT1("Could not find a service!\n");
3840
3841 /* If the service could not be found and lpcchBuffer is 0, windows
3842 puts null in lpDisplayName and puts 1 in lpcchBuffer */
3843 if (*lpcchBuffer == 0)
3844 {
3845 *lpcchBuffer = 1;
3846 if (lpDisplayName != NULL)
3847 {
3848 *lpDisplayName = '\0';
3849 }
3850 }
3851 return ERROR_SERVICE_DOES_NOT_EXIST;
3852 }
3853
3854 if (!lpService->lpDisplayName)
3855 {
3856 dwLength = wcslen(lpService->lpServiceName);
3857 if (lpDisplayName != NULL &&
3858 *lpcchBuffer > dwLength)
3859 {
3860 WideCharToMultiByte(CP_ACP,
3861 0,
3862 lpService->lpServiceName,
3863 wcslen(lpService->lpServiceName),
3864 lpDisplayName,
3865 dwLength + 1,
3866 NULL,
3867 NULL);
3868 return ERROR_SUCCESS;
3869 }
3870 }
3871 else
3872 {
3873 dwLength = wcslen(lpService->lpDisplayName);
3874 if (lpDisplayName != NULL &&
3875 *lpcchBuffer > dwLength)
3876 {
3877 WideCharToMultiByte(CP_ACP,
3878 0,
3879 lpService->lpDisplayName,
3880 wcslen(lpService->lpDisplayName),
3881 lpDisplayName,
3882 dwLength + 1,
3883 NULL,
3884 NULL);
3885 return ERROR_SUCCESS;
3886 }
3887 }
3888
3889 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3890
3891 *lpcchBuffer = dwLength * 2;
3892
3893 return dwError;
3894 }
3895
3896
3897 /* Function 33 */
3898 DWORD RGetServiceKeyNameA(
3899 SC_RPC_HANDLE hSCManager,
3900 LPCSTR lpDisplayName,
3901 LPSTR lpServiceName,
3902 LPBOUNDED_DWORD_4K lpcchBuffer)
3903 {
3904 PSERVICE lpService;
3905 DWORD dwLength;
3906 DWORD dwError;
3907 LPWSTR lpDisplayNameW;
3908
3909 DPRINT("RGetServiceKeyNameA() called\n");
3910 DPRINT("hSCManager = %p\n", hSCManager);
3911 DPRINT("lpDisplayName: %s\n", lpDisplayName);
3912 DPRINT("lpServiceName: %p\n", lpServiceName);
3913 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3914
3915 dwLength = strlen(lpDisplayName) + 1;
3916 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3917 HEAP_ZERO_MEMORY,
3918 dwLength * sizeof(WCHAR));
3919 if (!lpDisplayNameW)
3920 return ERROR_NOT_ENOUGH_MEMORY;
3921
3922 MultiByteToWideChar(CP_ACP,
3923 0,
3924 lpDisplayName,
3925 -1,
3926 lpDisplayNameW,
3927 dwLength);
3928
3929 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
3930
3931 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3932
3933 if (lpService == NULL)
3934 {
3935 DPRINT1("Could not find the service!\n");
3936
3937 /* If the service could not be found and lpcchBuffer is 0,
3938 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
3939 if (*lpcchBuffer == 0)
3940 {
3941 *lpcchBuffer = 1;
3942 if (lpServiceName != NULL)
3943 {
3944 *lpServiceName = '\0';
3945 }
3946 }
3947
3948 return ERROR_SERVICE_DOES_NOT_EXIST;
3949 }
3950
3951 dwLength = wcslen(lpService->lpServiceName);
3952 if (lpServiceName != NULL &&
3953 *lpcchBuffer > dwLength)
3954 {
3955 WideCharToMultiByte(CP_ACP,
3956 0,
3957 lpService->lpServiceName,
3958 wcslen(lpService->lpServiceName),
3959 lpServiceName,
3960 dwLength + 1,
3961 NULL,
3962 NULL);
3963 return ERROR_SUCCESS;
3964 }
3965
3966 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3967
3968 *lpcchBuffer = dwLength * 2;
3969
3970 return dwError;
3971 }
3972
3973
3974 /* Function 34 */
3975 DWORD RI_ScGetCurrentGroupStateW(
3976 SC_RPC_HANDLE hSCManager,
3977 LPWSTR lpLoadOrderGroup,
3978 LPDWORD lpState)
3979 {
3980 UNIMPLEMENTED;
3981 return ERROR_CALL_NOT_IMPLEMENTED;
3982 }
3983
3984
3985 /* Function 35 */
3986 DWORD REnumServiceGroupW(
3987 SC_RPC_HANDLE hSCManager,
3988 DWORD dwServiceType,
3989 DWORD dwServiceState,
3990 LPBYTE lpBuffer,
3991 DWORD cbBufSize,
3992 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3993 LPBOUNDED_DWORD_256K lpServicesReturned,
3994 LPBOUNDED_DWORD_256K lpResumeIndex,
3995 LPCWSTR pszGroupName)
3996 {
3997 UNIMPLEMENTED;
3998 return ERROR_CALL_NOT_IMPLEMENTED;
3999 }
4000
4001
4002 //
4003 // WARNING: This function is untested
4004 //
4005 /* Function 36 */
4006 DWORD RChangeServiceConfig2A(
4007 SC_RPC_HANDLE hService,
4008 SC_RPC_CONFIG_INFOA Info)
4009 {
4010 SC_RPC_CONFIG_INFOW InfoW;
4011 DWORD dwRet, dwLength;
4012 PVOID ptr = NULL;
4013
4014 DPRINT("RChangeServiceConfig2A() called\n");
4015 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4016
4017 InfoW.dwInfoLevel = Info.dwInfoLevel;
4018
4019 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4020 {
4021 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4022 LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4023
4024 lpServiceDescriptonA = Info.psd;
4025
4026 ///if (lpServiceDescriptonA &&
4027 ///lpServiceDescriptonA->lpDescription)
4028 ///{
4029 dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
4030
4031 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4032 0,
4033 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4034 if (!lpServiceDescriptonW)
4035 {
4036 return ERROR_NOT_ENOUGH_MEMORY;
4037 }
4038
4039 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4040
4041 MultiByteToWideChar(CP_ACP,
4042 0,
4043 Info.lpDescription,
4044 -1,
4045 lpServiceDescriptonW->lpDescription,
4046 dwLength);
4047
4048 ptr = lpServiceDescriptonW;
4049 InfoW.psd = lpServiceDescriptonW;
4050 ///}
4051 }
4052 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4053 {
4054 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4055 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4056 DWORD dwRebootLen = 0;
4057 DWORD dwCommandLen = 0;
4058
4059 lpServiceFailureActionsA = Info.psfa;
4060
4061 if (lpServiceFailureActionsA)
4062 {
4063 if (lpServiceFailureActionsA->lpRebootMsg)
4064 {
4065 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4066 }
4067 if (lpServiceFailureActionsA->lpCommand)
4068 {
4069 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4070 }
4071 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4072
4073 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4074 0,
4075 dwLength);
4076 if (!lpServiceFailureActionsW)
4077 {
4078 return ERROR_NOT_ENOUGH_MEMORY;
4079 }
4080
4081 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4082 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4083 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4084
4085 if (lpServiceFailureActionsA->lpRebootMsg)
4086 {
4087 MultiByteToWideChar(CP_ACP,
4088 0,
4089 lpServiceFailureActionsA->lpRebootMsg,
4090 -1,
4091 lpServiceFailureActionsW->lpRebootMsg,
4092 dwRebootLen);
4093 }
4094
4095 if (lpServiceFailureActionsA->lpCommand)
4096 {
4097 MultiByteToWideChar(CP_ACP,
4098 0,
4099 lpServiceFailureActionsA->lpCommand,
4100 -1,
4101 lpServiceFailureActionsW->lpCommand,
4102 dwCommandLen);
4103 }
4104
4105 ptr = lpServiceFailureActionsW;
4106 }
4107 }
4108
4109 dwRet = RChangeServiceConfig2W(hService, InfoW);
4110
4111 HeapFree(GetProcessHeap(), 0, ptr);
4112
4113 return dwRet;
4114 }
4115
4116
4117 /* Function 37 */
4118 DWORD RChangeServiceConfig2W(
4119 SC_RPC_HANDLE hService,
4120 SC_RPC_CONFIG_INFOW Info)
4121 {
4122 DWORD dwError = ERROR_SUCCESS;
4123 PSERVICE_HANDLE hSvc;
4124 PSERVICE lpService = NULL;
4125 HKEY hServiceKey = NULL;
4126
4127 DPRINT("RChangeServiceConfig2W() called\n");
4128 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4129
4130 if (ScmShutdown)
4131 return ERROR_SHUTDOWN_IN_PROGRESS;
4132
4133 hSvc = (PSERVICE_HANDLE)hService;
4134 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4135 {
4136 DPRINT1("Invalid handle tag!\n");
4137 return ERROR_INVALID_HANDLE;
4138 }
4139
4140 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4141 SERVICE_CHANGE_CONFIG))
4142 {
4143 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4144 return ERROR_ACCESS_DENIED;
4145 }
4146
4147 lpService = hSvc->ServiceEntry;
4148 if (lpService == NULL)
4149 {
4150 DPRINT1("lpService == NULL!\n");
4151 return ERROR_INVALID_HANDLE;
4152 }
4153
4154 /* FIXME: Lock database exclusively */
4155
4156 if (lpService->bDeleted)
4157 {
4158 /* FIXME: Unlock database */
4159 DPRINT1("The service has already been marked for delete!\n");
4160 return ERROR_SERVICE_MARKED_FOR_DELETE;
4161 }
4162
4163 /* Open the service key */
4164 dwError = ScmOpenServiceKey(lpService->szServiceName,
4165 KEY_SET_VALUE,
4166 &hServiceKey);
4167 if (dwError != ERROR_SUCCESS)
4168 goto done;
4169
4170 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4171 {
4172 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4173
4174 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
4175 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
4176
4177 if (lpServiceDescription != NULL &&
4178 lpServiceDescription->lpDescription != NULL)
4179 {
4180 DPRINT1("Setting value %S\n", lpServiceDescription->lpDescription);
4181 RegSetValueExW(hServiceKey,
4182 L"Description",
4183 0,
4184 REG_SZ,
4185 (LPBYTE)lpServiceDescription->lpDescription,
4186 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4187
4188 if (dwError != ERROR_SUCCESS)
4189 goto done;
4190 }
4191 }
4192 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4193 {
4194 UNIMPLEMENTED;
4195 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4196 goto done;
4197 }
4198
4199 done:
4200 /* FIXME: Unlock database */
4201 if (hServiceKey != NULL)
4202 RegCloseKey(hServiceKey);
4203
4204 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4205
4206 return dwError;
4207 }
4208
4209
4210 /* Function 38 */
4211 DWORD RQueryServiceConfig2A(
4212 SC_RPC_HANDLE hService,
4213 DWORD dwInfoLevel,
4214 LPBYTE lpBuffer,
4215 DWORD cbBufSize,
4216 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4217 {
4218 DWORD dwError = ERROR_SUCCESS;
4219 PSERVICE_HANDLE hSvc;
4220 PSERVICE lpService = NULL;
4221 HKEY hServiceKey = NULL;
4222 LPWSTR lpDescriptionW = NULL;
4223 LPSTR lpDescription = NULL;
4224
4225 DPRINT1("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
4226
4227 if (!lpBuffer)
4228 return ERROR_INVALID_ADDRESS;
4229
4230 if (ScmShutdown)
4231 return ERROR_SHUTDOWN_IN_PROGRESS;
4232
4233 hSvc = (PSERVICE_HANDLE)hService;
4234 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4235 {
4236 DPRINT1("Invalid handle tag!\n");
4237 return ERROR_INVALID_HANDLE;
4238 }
4239
4240 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4241 SERVICE_QUERY_CONFIG))
4242 {
4243 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4244 return ERROR_ACCESS_DENIED;
4245 }
4246
4247 lpService = hSvc->ServiceEntry;
4248 if (lpService == NULL)
4249 {
4250 DPRINT1("lpService == NULL!\n");
4251 return ERROR_INVALID_HANDLE;
4252 }
4253
4254 /* FIXME: Lock the service database shared */
4255
4256 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4257 KEY_READ,
4258 &hServiceKey);
4259 if (dwError != ERROR_SUCCESS)
4260 goto done;
4261
4262 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4263 {
4264 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4265 LPSTR lpStr;
4266
4267 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4268
4269 dwError = ScmReadString(hServiceKey,
4270 L"Description",
4271 &lpDescriptionW);
4272 if (dwError == ERROR_SUCCESS)
4273 {
4274 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
4275 }
4276
4277 if (cbBufSize >= *pcbBytesNeeded)
4278 {
4279
4280 if (dwError == ERROR_SUCCESS)
4281 {
4282 lpStr = (LPSTR)(lpServiceDescription + 1);
4283
4284 WideCharToMultiByte(CP_ACP,
4285 0,
4286 lpDescriptionW,
4287 -1,
4288 lpStr,
4289 wcslen(lpDescriptionW),
4290 NULL,
4291 NULL);
4292 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4293 }
4294 else
4295 {
4296 lpServiceDescription->lpDescription = NULL;
4297 goto done;
4298 }
4299 }
4300 else
4301 {
4302 dwError = ERROR_INSUFFICIENT_BUFFER;
4303 goto done;
4304 }
4305 }
4306 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4307 {
4308 UNIMPLEMENTED;
4309 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4310 goto done;
4311 }
4312
4313 done:
4314 if (lpDescription != NULL)
4315 HeapFree(GetProcessHeap(), 0, lpDescription);
4316
4317 if (hServiceKey != NULL)
4318 RegCloseKey(hServiceKey);
4319
4320 /* FIXME: Unlock database */
4321
4322 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4323
4324 return dwError;
4325 }
4326
4327
4328 /* Function 39 */
4329 DWORD RQueryServiceConfig2W(
4330 SC_RPC_HANDLE hService,
4331 DWORD dwInfoLevel,
4332 LPBYTE lpBuffer,
4333 DWORD cbBufSize,
4334 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4335 {
4336 DWORD dwError = ERROR_SUCCESS;
4337 PSERVICE_HANDLE hSvc;
4338 PSERVICE lpService = NULL;
4339 HKEY hServiceKey = NULL;
4340 DWORD dwRequiredSize;
4341 LPWSTR lpDescription = NULL;
4342 LPWSTR lpFailureCommand = NULL;
4343 LPWSTR lpRebootMessage = NULL;
4344
4345 DPRINT("RQueryServiceConfig2W() called\n");
4346
4347 if (!lpBuffer)
4348 return ERROR_INVALID_ADDRESS;
4349
4350 if (ScmShutdown)
4351 return ERROR_SHUTDOWN_IN_PROGRESS;
4352
4353 hSvc = (PSERVICE_HANDLE)hService;
4354 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4355 {
4356 DPRINT1("Invalid handle tag!\n");
4357 return ERROR_INVALID_HANDLE;
4358 }
4359
4360 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4361 SERVICE_QUERY_CONFIG))
4362 {
4363 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4364 return ERROR_ACCESS_DENIED;
4365 }
4366
4367 lpService = hSvc->ServiceEntry;
4368 if (lpService == NULL)
4369 {
4370 DPRINT1("lpService == NULL!\n");
4371 return ERROR_INVALID_HANDLE;
4372 }
4373
4374 /* FIXME: Lock the service database shared */
4375
4376 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4377 KEY_READ,
4378 &hServiceKey);
4379 if (dwError != ERROR_SUCCESS)
4380 goto done;
4381
4382 if (dwInfoLevel & SERVICE_CONFIG_DESCRIPTION)
4383 {
4384 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4385 LPWSTR lpStr;
4386
4387 dwError = ScmReadString(hServiceKey,
4388 L"Description",
4389 &lpDescription);
4390 if (dwError != ERROR_SUCCESS)
4391 goto done;
4392
4393 dwRequiredSize = sizeof(SERVICE_DESCRIPTIONW) + ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4394
4395 if (cbBufSize < dwRequiredSize)
4396 {
4397 *pcbBytesNeeded = dwRequiredSize;
4398 dwError = ERROR_INSUFFICIENT_BUFFER;
4399 goto done;
4400 }
4401
4402 lpStr = (LPWSTR)(lpServiceDescription + 1);
4403 wcscpy(lpStr, lpDescription);
4404 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4405 }
4406 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4407 {
4408 LPWSTR lpStr;
4409 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
4410
4411 UNIMPLEMENTED;
4412
4413 dwError = ScmReadString(hServiceKey,
4414 L"FailureCommand",
4415 &lpFailureCommand);
4416
4417 dwError = ScmReadString(hServiceKey,
4418 L"RebootMessage",
4419 &lpRebootMessage);
4420
4421 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
4422
4423 if (lpFailureCommand)
4424 dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
4425
4426 if (lpRebootMessage)
4427 dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
4428
4429 if (cbBufSize < dwRequiredSize)
4430 {
4431 *pcbBytesNeeded = dwRequiredSize;
4432 dwError = ERROR_INSUFFICIENT_BUFFER;
4433 goto done;
4434 }
4435
4436 lpFailureActions->cActions = 0;
4437 lpFailureActions->dwResetPeriod = 0;
4438 lpFailureActions->lpCommand = NULL;
4439 lpFailureActions->lpRebootMsg = NULL;
4440 lpFailureActions->lpsaActions = NULL;
4441
4442 lpStr = (LPWSTR)(lpFailureActions + 1);
4443 if (lpRebootMessage)
4444 {
4445 wcscpy(lpStr, lpRebootMessage);
4446 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
4447 lpStr += wcslen(lpRebootMessage) + 1;
4448 }
4449
4450 if (lpFailureCommand)
4451 {
4452 wcscpy(lpStr, lpFailureCommand);
4453 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
4454 lpStr += wcslen(lpRebootMessage) + 1;
4455 }
4456 dwError = STATUS_SUCCESS;
4457 goto done;
4458 }
4459
4460 done:
4461 if (lpDescription != NULL)
4462 HeapFree(GetProcessHeap(), 0, lpDescription);
4463
4464 if (lpRebootMessage != NULL)
4465 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
4466
4467 if (lpFailureCommand != NULL)
4468 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
4469
4470 if (hServiceKey != NULL)
4471 RegCloseKey(hServiceKey);
4472
4473 /* FIXME: Unlock database */
4474
4475 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4476
4477 return dwError;
4478 }
4479
4480
4481 /* Function 40 */
4482 DWORD RQueryServiceStatusEx(
4483 SC_RPC_HANDLE hService,
4484 SC_STATUS_TYPE InfoLevel,
4485 LPBYTE lpBuffer,
4486 DWORD cbBufSize,
4487 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4488 {
4489 LPSERVICE_STATUS_PROCESS lpStatus;
4490 PSERVICE_HANDLE hSvc;
4491 PSERVICE lpService;
4492
4493 DPRINT("RQueryServiceStatusEx() called\n");
4494
4495 if (ScmShutdown)
4496 return ERROR_SHUTDOWN_IN_PROGRESS;
4497
4498 if (InfoLevel != SC_STATUS_PROCESS_INFO)
4499 return ERROR_INVALID_LEVEL;
4500
4501 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
4502
4503 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
4504 return ERROR_INSUFFICIENT_BUFFER;
4505
4506 hSvc = (PSERVICE_HANDLE)hService;
4507 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
4508 {
4509 DPRINT1("Invalid handle tag!\n");
4510 return ERROR_INVALID_HANDLE;
4511 }
4512
4513 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4514 SERVICE_QUERY_STATUS))
4515 {
4516 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4517 return ERROR_ACCESS_DENIED;
4518 }
4519
4520 lpService = hSvc->ServiceEntry;
4521 if (lpService == NULL)
4522 {
4523 DPRINT1("lpService == NULL!\n");
4524 return ERROR_INVALID_HANDLE;
4525 }
4526
4527 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
4528
4529 /* Return service status information */
4530 RtlCopyMemory(lpStatus,
4531 &lpService->Status,
4532 sizeof(SERVICE_STATUS));
4533
4534 lpStatus->dwProcessId = lpService->ProcessId; /* FIXME */
4535 lpStatus->dwServiceFlags = 0; /* FIXME */
4536
4537 return ERROR_SUCCESS;
4538 }
4539
4540
4541 /* Function 41 */
4542 DWORD REnumServicesStatusExA(
4543 SC_RPC_HANDLE hSCManager,
4544 SC_ENUM_TYPE InfoLevel,
4545 DWORD dwServiceType,
4546 DWORD dwServiceState,
4547 LPBYTE lpBuffer,
4548 DWORD cbBufSize,
4549 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4550 LPBOUNDED_DWORD_256K lpServicesReturned,
4551 LPBOUNDED_DWORD_256K lpResumeIndex,
4552 LPCSTR pszGroupName)
4553 {
4554 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
4555 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
4556 LPWSTR lpStringPtrW;
4557 LPSTR lpStringPtrA;
4558 LPWSTR pszGroupNameW = NULL;
4559 DWORD dwError;
4560 DWORD dwServiceCount;
4561
4562 DPRINT("REnumServicesStatusExA() called\n");
4563
4564 if (pszGroupName)
4565 {
4566 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
4567 if (!pszGroupNameW)
4568 {
4569 DPRINT1("Failed to allocate buffer!\n");
4570 return ERROR_NOT_ENOUGH_MEMORY;
4571 }
4572 MultiByteToWideChar(CP_ACP,
4573 0,
4574 pszGroupName,
4575 -1,
4576 pszGroupNameW,
4577 strlen(pszGroupName) + 1);
4578 }
4579
4580 if ((cbBufSize > 0) && (lpBuffer))
4581 {
4582 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
4583 if (!lpStatusPtrW)
4584 {
4585 DPRINT1("Failed to allocate buffer!\n");
4586 return ERROR_NOT_ENOUGH_MEMORY;
4587 }
4588 }
4589
4590 dwError = REnumServicesStatusExW(hSCManager,
4591 InfoLevel,
4592 dwServiceType,
4593 dwServiceState,
4594 (LPBYTE)lpStatusPtrW,
4595 cbBufSize,
4596 pcbBytesNeeded,
4597 lpServicesReturned,
4598 lpResumeIndex,
4599 pszGroupNameW);
4600
4601 /* if no services were returned then we are Done */
4602 if (*lpServicesReturned == 0) goto Done;
4603
4604 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
4605 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
4606 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
4607 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
4608 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4609
4610 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
4611 {
4612 /* Copy the service name */
4613 WideCharToMultiByte(CP_ACP,
4614 0,
4615 lpStringPtrW,
4616 -1,
4617 lpStringPtrA,
4618 wcslen(lpStringPtrW),
4619 0,
4620 0);
4621
4622 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4623 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4624 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4625
4626 /* Copy the display name */
4627 WideCharToMultiByte(CP_ACP,
4628 0,
4629 lpStringPtrW,
4630 -1,
4631 lpStringPtrA,
4632 wcslen(lpStringPtrW),
4633 0,
4634 0);
4635
4636 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4637 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4638 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4639
4640 /* Copy the status information */
4641 memcpy(&lpStatusPtrA->ServiceStatusProcess,
4642 &lpStatusPtrW->ServiceStatusProcess,
4643 sizeof(SERVICE_STATUS));
4644
4645 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
4646 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4647 lpStatusPtrA++;
4648 }
4649
4650 Done:;
4651 if (pszGroupNameW) HeapFree(GetProcessHeap(), 0, pszGroupNameW);
4652
4653 if (lpStatusPtrW) HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
4654
4655 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
4656
4657 return dwError;
4658 }
4659
4660
4661 /* Function 42 */
4662 DWORD REnumServicesStatusExW(
4663 SC_RPC_HANDLE hSCManager,
4664 SC_ENUM_TYPE InfoLevel,
4665 DWORD dwServiceType,
4666 DWORD dwServiceState,
4667 LPBYTE lpBuffer,
4668 DWORD cbBufSize,
4669 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4670 LPBOUNDED_DWORD_256K lpServicesReturned,
4671 LPBOUNDED_DWORD_256K lpResumeIndex,
4672 LPCWSTR pszGroupName)
4673 {
4674 PMANAGER_HANDLE hManager;
4675 PSERVICE lpService;
4676 DWORD dwError = ERROR_SUCCESS;
4677 PLIST_ENTRY ServiceEntry;
4678 PSERVICE CurrentService;
4679 DWORD dwState;
4680 DWORD dwRequiredSize;
4681 DWORD dwServiceCount;
4682 DWORD dwSize;
4683 DWORD dwLastResumeCount = 0;
4684 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
4685 LPWSTR lpStringPtr;
4686
4687 DPRINT("REnumServicesStatusExW() called\n");
4688
4689 if (ScmShutdown)
4690 return ERROR_SHUTDOWN_IN_PROGRESS;
4691
4692 if (InfoLevel != SC_ENUM_PROCESS_INFO)
4693 return ERROR_INVALID_LEVEL;
4694
4695 hManager = (PMANAGER_HANDLE)hSCManager;
4696 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
4697 {
4698 DPRINT1("Invalid manager handle!\n");
4699 return ERROR_INVALID_HANDLE;
4700 }
4701
4702 *pcbBytesNeeded = 0;
4703 *lpServicesReturned = 0;
4704
4705 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
4706 {
4707 DPRINT1("Not a valid Service Type!\n");
4708 return ERROR_INVALID_PARAMETER;
4709 }
4710
4711 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
4712 {
4713 DPRINT1("Not a valid Service State!\n");
4714 return ERROR_INVALID_PARAMETER;
4715 }
4716
4717 /* Check access rights */
4718 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
4719 SC_MANAGER_ENUMERATE_SERVICE))
4720 {
4721 DPRINT1("Insufficient access rights! 0x%lx\n",
4722 hManager->Handle.DesiredAccess);
4723 return ERROR_ACCESS_DENIED;
4724 }
4725
4726 if (lpResumeIndex) dwLastResumeCount = *lpResumeIndex;
4727
4728 /* Lock the service list shared */
4729
4730 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
4731 if (lpService == NULL)
4732 {
4733 dwError = ERROR_SUCCESS;
4734 goto Done;
4735 }
4736
4737 dwRequiredSize = 0;
4738 dwServiceCount = 0;
4739
4740 for (ServiceEntry = &lpService->ServiceListEntry;
4741 ServiceEntry != &ServiceListHead;
4742 ServiceEntry = ServiceEntry->Flink)
4743 {
4744 CurrentService = CONTAINING_RECORD(ServiceEntry,
4745 SERVICE,
4746 ServiceListEntry);
4747
4748 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4749 continue;
4750
4751 dwState = SERVICE_ACTIVE;
4752 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4753 dwState = SERVICE_INACTIVE;
4754
4755 if ((dwState & dwServiceState) == 0)
4756 continue;
4757
4758 if (pszGroupName)
4759 {
4760 if (*pszGroupName == 0)
4761 {
4762 if (CurrentService->lpGroup != NULL)
4763 continue;
4764 }
4765 else
4766 {
4767 if ((CurrentService->lpGroup == NULL) ||
4768 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4769 continue;
4770 }
4771 }
4772
4773 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4774 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4775 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4776
4777 if (dwRequiredSize + dwSize <= cbBufSize)
4778 {
4779 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
4780 dwRequiredSize += dwSize;
4781 dwServiceCount++;
4782 dwLastResumeCount = CurrentService->dwResumeCount;
4783 }
4784 else
4785 {
4786 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
4787 break;
4788 }
4789
4790 }
4791
4792 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
4793 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
4794
4795 for (;
4796 ServiceEntry != &ServiceListHead;
4797 ServiceEntry = ServiceEntry->Flink)
4798 {
4799 CurrentService = CONTAINING_RECORD(ServiceEntry,
4800 SERVICE,
4801 ServiceListEntry);
4802
4803 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4804 continue;
4805
4806 dwState = SERVICE_ACTIVE;
4807 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4808 dwState = SERVICE_INACTIVE;
4809
4810 if ((dwState & dwServiceState) == 0)
4811 continue;
4812
4813 if (pszGroupName)
4814 {
4815 if (*pszGroupName == 0)
4816 {
4817 if (CurrentService->lpGroup != NULL)
4818 continue;
4819 }
4820 else
4821 {
4822 if ((CurrentService->lpGroup == NULL) ||
4823 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4824 continue;
4825 }
4826 }
4827
4828 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4829 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4830 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
4831
4832 dwError = ERROR_MORE_DATA;
4833 }
4834
4835 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
4836
4837 if (lpResumeIndex) *lpResumeIndex = dwLastResumeCount;
4838 *lpServicesReturned = dwServiceCount;
4839 *pcbBytesNeeded = dwRequiredSize;
4840
4841 /* If there was no services that matched */
4842 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
4843 {
4844 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
4845 goto Done;
4846 }
4847
4848 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
4849 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
4850 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4851
4852 dwRequiredSize = 0;
4853 for (ServiceEntry = &lpService->ServiceListEntry;
4854 ServiceEntry != &ServiceListHead;
4855 ServiceEntry = ServiceEntry->Flink)
4856 {
4857 CurrentService = CONTAINING_RECORD(ServiceEntry,
4858 SERVICE,
4859 ServiceListEntry);
4860
4861 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
4862 continue;
4863
4864 dwState = SERVICE_ACTIVE;
4865 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
4866 dwState = SERVICE_INACTIVE;
4867
4868 if ((dwState & dwServiceState) == 0)
4869 continue;
4870
4871 if (pszGroupName)
4872 {
4873 if (*pszGroupName == 0)
4874 {
4875 if (CurrentService->lpGroup != NULL)
4876 continue;
4877 }
4878 else
4879 {
4880 if ((CurrentService->lpGroup == NULL) ||
4881 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
4882 continue;
4883 }
4884 }
4885
4886 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
4887 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
4888 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
4889
4890 if (dwRequiredSize + dwSize <= cbBufSize)
4891 {
4892 /* Copy the service name */
4893 wcscpy(lpStringPtr,
4894 CurrentService->lpServiceName);
4895 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4896 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
4897
4898 /* Copy the display name */
4899 wcscpy(lpStringPtr,
4900 CurrentService->lpDisplayName);
4901 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
4902 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
4903
4904 /* Copy the status information */
4905 memcpy(&lpStatusPtr->ServiceStatusProcess,
4906 &CurrentService->Status,
4907 sizeof(SERVICE_STATUS));
4908 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
4909 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
4910
4911 lpStatusPtr++;
4912 dwRequiredSize += dwSize;
4913 }
4914 else
4915 {
4916 break;
4917 }
4918 }
4919
4920 if (dwError == 0)
4921 {
4922 *pcbBytesNeeded = 0;
4923 if (lpResumeIndex) *lpResumeIndex = 0;
4924 }
4925
4926 Done:;
4927 /* Unlock the service list */
4928
4929 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
4930
4931 return dwError;
4932 }
4933
4934
4935 /* Function 43 */
4936 DWORD RSendTSMessage(
4937 handle_t BindingHandle) /* FIXME */
4938 {
4939 UNIMPLEMENTED;
4940 return ERROR_CALL_NOT_IMPLEMENTED;
4941 }
4942
4943
4944 /* Function 44 */
4945 DWORD RCreateServiceWOW64A(
4946 handle_t BindingHandle,
4947 LPSTR lpServiceName,
4948 LPSTR lpDisplayName,
4949 DWORD dwDesiredAccess,
4950 DWORD dwServiceType,
4951 DWORD dwStartType,
4952 DWORD dwErrorControl,
4953 LPSTR lpBinaryPathName,
4954 LPSTR lpLoadOrderGroup,
4955 LPDWORD lpdwTagId,
4956 LPBYTE lpDependencies,
4957 DWORD dwDependSize,
4958 LPSTR lpServiceStartName,
4959 LPBYTE lpPassword,
4960 DWORD dwPwSize,
4961 LPSC_RPC_HANDLE lpServiceHandle)
4962 {
4963 UNIMPLEMENTED;
4964 return ERROR_CALL_NOT_IMPLEMENTED;
4965 }
4966
4967
4968 /* Function 45 */
4969 DWORD RCreateServiceWOW64W(
4970 handle_t BindingHandle,
4971 LPWSTR lpServiceName,
4972 LPWSTR lpDisplayName,
4973 DWORD dwDesiredAccess,
4974 DWORD dwServiceType,
4975 DWORD dwStartType,
4976 DWORD dwErrorControl,
4977 LPWSTR lpBinaryPathName,
4978 LPWSTR lpLoadOrderGroup,
4979 LPDWORD lpdwTagId,
4980 LPBYTE lpDependencies,
4981 DWORD dwDependSize,
4982 LPWSTR lpServiceStartName,
4983 LPBYTE lpPassword,
4984 DWORD dwPwSize,
4985 LPSC_RPC_HANDLE lpServiceHandle)
4986 {
4987 UNIMPLEMENTED;
4988 return ERROR_CALL_NOT_IMPLEMENTED;
4989 }
4990
4991
4992 /* Function 46 */
4993 DWORD RQueryServiceTagInfo(
4994 handle_t BindingHandle) /* FIXME */
4995 {
4996 UNIMPLEMENTED;
4997 return ERROR_CALL_NOT_IMPLEMENTED;
4998 }
4999
5000
5001 /* Function 47 */
5002 DWORD RNotifyServiceStatusChange(
5003 SC_RPC_HANDLE hService,
5004 SC_RPC_NOTIFY_PARAMS NotifyParams,
5005 GUID *pClientProcessGuid,
5006 GUID *pSCMProcessGuid,
5007 PBOOL pfCreateRemoteQueue,
5008 LPSC_NOTIFY_RPC_HANDLE phNotify)
5009 {
5010 UNIMPLEMENTED;
5011 return ERROR_CALL_NOT_IMPLEMENTED;
5012 }
5013
5014
5015 /* Function 48 */
5016 DWORD RGetNotifyResults(
5017 SC_NOTIFY_RPC_HANDLE hNotify,
5018 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5019 {
5020 UNIMPLEMENTED;
5021 return ERROR_CALL_NOT_IMPLEMENTED;
5022 }
5023
5024
5025 /* Function 49 */
5026 DWORD RCloseNotifyHandle(
5027 LPSC_NOTIFY_RPC_HANDLE phNotify,
5028 PBOOL pfApcFired)
5029 {
5030 UNIMPLEMENTED;
5031 return ERROR_CALL_NOT_IMPLEMENTED;
5032 }
5033
5034
5035 /* Function 50 */
5036 DWORD RControlServiceExA(
5037 SC_RPC_HANDLE hService,
5038 DWORD dwControl,
5039 DWORD dwInfoLevel)
5040 {
5041 UNIMPLEMENTED;
5042 return ERROR_CALL_NOT_IMPLEMENTED;
5043 }
5044
5045
5046 /* Function 51 */
5047 DWORD RControlServiceExW(
5048 SC_RPC_HANDLE hService,
5049 DWORD dwControl,
5050 DWORD dwInfoLevel)
5051 {
5052 UNIMPLEMENTED;
5053 return ERROR_CALL_NOT_IMPLEMENTED;
5054 }
5055
5056
5057 /* Function 52 */
5058 DWORD RSendPnPMessage(
5059 handle_t BindingHandle) /* FIXME */
5060 {
5061 UNIMPLEMENTED;
5062 return ERROR_CALL_NOT_IMPLEMENTED;
5063 }
5064
5065
5066 /* Function 53 */
5067 DWORD RValidatePnPService(
5068 handle_t BindingHandle) /* FIXME */
5069 {
5070 UNIMPLEMENTED;
5071 return ERROR_CALL_NOT_IMPLEMENTED;
5072 }
5073
5074
5075 /* Function 54 */
5076 DWORD ROpenServiceStatusHandle(
5077 handle_t BindingHandle) /* FIXME */
5078 {
5079 UNIMPLEMENTED;
5080 return ERROR_CALL_NOT_IMPLEMENTED;
5081 }
5082
5083
5084 /* Function 55 */
5085 DWORD RFunction55(
5086 handle_t BindingHandle) /* FIXME */
5087 {
5088 UNIMPLEMENTED;
5089 return ERROR_CALL_NOT_IMPLEMENTED;
5090 }
5091
5092
5093 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
5094 {
5095 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5096 }
5097
5098
5099 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5100 {
5101 HeapFree(GetProcessHeap(), 0, ptr);
5102 }
5103
5104
5105 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5106 {
5107 }
5108
5109
5110 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5111 {
5112 }
5113
5114
5115 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5116 {
5117 }
5118
5119 /* EOF */