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