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