3061ad463defaff1506d0ffd4cc3106029a18eb3
[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
12 /* INCLUDES ****************************************************************/
13
14 #include "services.h"
15 #include "svcctl_s.h"
16
17 #define NDEBUG
18 #include <debug.h>
19
20 /* GLOBALS *****************************************************************/
21
22 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
23 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
24
25 typedef struct _SCMGR_HANDLE
26 {
27 DWORD Tag;
28 DWORD RefCount;
29 DWORD DesiredAccess;
30 } SCMGR_HANDLE;
31
32
33 typedef struct _MANAGER_HANDLE
34 {
35 SCMGR_HANDLE Handle;
36
37 /* FIXME: Insert more data here */
38
39 WCHAR DatabaseName[1];
40 } MANAGER_HANDLE, *PMANAGER_HANDLE;
41
42
43 typedef struct _SERVICE_HANDLE
44 {
45 SCMGR_HANDLE Handle;
46
47 DWORD DesiredAccess;
48 PSERVICE ServiceEntry;
49
50 /* FIXME: Insert more data here */
51
52 } SERVICE_HANDLE, *PSERVICE_HANDLE;
53
54
55 #define SC_MANAGER_READ \
56 (STANDARD_RIGHTS_READ | \
57 SC_MANAGER_QUERY_LOCK_STATUS | \
58 SC_MANAGER_ENUMERATE_SERVICE)
59
60 #define SC_MANAGER_WRITE \
61 (STANDARD_RIGHTS_WRITE | \
62 SC_MANAGER_MODIFY_BOOT_CONFIG | \
63 SC_MANAGER_CREATE_SERVICE)
64
65 #define SC_MANAGER_EXECUTE \
66 (STANDARD_RIGHTS_EXECUTE | \
67 SC_MANAGER_LOCK | \
68 SC_MANAGER_ENUMERATE_SERVICE | \
69 SC_MANAGER_CONNECT | \
70 SC_MANAGER_CREATE_SERVICE)
71
72
73 #define SERVICE_READ \
74 (STANDARD_RIGHTS_READ | \
75 SERVICE_INTERROGATE | \
76 SERVICE_ENUMERATE_DEPENDENTS | \
77 SERVICE_QUERY_STATUS | \
78 SERVICE_QUERY_CONFIG)
79
80 #define SERVICE_WRITE \
81 (STANDARD_RIGHTS_WRITE | \
82 SERVICE_CHANGE_CONFIG)
83
84 #define SERVICE_EXECUTE \
85 (STANDARD_RIGHTS_EXECUTE | \
86 SERVICE_USER_DEFINED_CONTROL | \
87 SERVICE_PAUSE_CONTINUE | \
88 SERVICE_STOP | \
89 SERVICE_START)
90
91
92 /* VARIABLES ***************************************************************/
93
94 static GENERIC_MAPPING
95 ScmManagerMapping = {SC_MANAGER_READ,
96 SC_MANAGER_WRITE,
97 SC_MANAGER_EXECUTE,
98 SC_MANAGER_ALL_ACCESS};
99
100 static GENERIC_MAPPING
101 ScmServiceMapping = {SERVICE_READ,
102 SERVICE_WRITE,
103 SERVICE_EXECUTE,
104 SC_MANAGER_ALL_ACCESS};
105
106
107 /* FUNCTIONS ***************************************************************/
108
109 VOID
110 ScmStartRpcServer(VOID)
111 {
112 RPC_STATUS Status;
113
114 DPRINT("ScmStartRpcServer() called\n");
115
116 Status = RpcServerUseProtseqEpW(L"ncacn_np",
117 10,
118 L"\\pipe\\ntsvcs",
119 NULL);
120 if (Status != RPC_S_OK)
121 {
122 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
123 return;
124 }
125
126 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
127 NULL,
128 NULL);
129 if (Status != RPC_S_OK)
130 {
131 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
132 return;
133 }
134
135 Status = RpcServerListen(1, 20, TRUE);
136 if (Status != RPC_S_OK)
137 {
138 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
139 return;
140 }
141
142 DPRINT("ScmStartRpcServer() done\n");
143 }
144
145
146 static DWORD
147 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
148 SC_HANDLE *Handle)
149 {
150 PMANAGER_HANDLE Ptr;
151
152 if (lpDatabaseName == NULL)
153 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
154
155 if (wcsicmp(lpDatabaseName,SERVICES_FAILED_DATABASEW)==0)
156 {
157 DPRINT1("Database %S, does not exist\n",lpDatabaseName);
158 return ERROR_DATABASE_DOES_NOT_EXIST;
159 }
160 else if (wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
161 {
162 DPRINT1("Invalid Database name %S.\n",lpDatabaseName);
163 return ERROR_INVALID_NAME;
164 }
165
166 Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
167 HEAP_ZERO_MEMORY,
168 sizeof(MANAGER_HANDLE) + wcslen(lpDatabaseName) * sizeof(WCHAR));
169 if (Ptr == NULL)
170 return ERROR_NOT_ENOUGH_MEMORY;
171
172 Ptr->Handle.Tag = MANAGER_TAG;
173 Ptr->Handle.RefCount = 1;
174
175 /* FIXME: initialize more data here */
176
177 wcscpy(Ptr->DatabaseName, lpDatabaseName);
178
179 *Handle = (SC_HANDLE)Ptr;
180
181 return ERROR_SUCCESS;
182 }
183
184
185 static DWORD
186 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
187 SC_HANDLE *Handle)
188 {
189 PSERVICE_HANDLE Ptr;
190
191 Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
192 HEAP_ZERO_MEMORY,
193 sizeof(SERVICE_HANDLE));
194 if (Ptr == NULL)
195 return ERROR_NOT_ENOUGH_MEMORY;
196
197 Ptr->Handle.Tag = SERVICE_TAG;
198 Ptr->Handle.RefCount = 1;
199
200 /* FIXME: initialize more data here */
201 Ptr->ServiceEntry = lpServiceEntry;
202
203 *Handle = (SC_HANDLE)Ptr;
204
205 return ERROR_SUCCESS;
206 }
207
208
209 static DWORD
210 ScmCheckAccess(SC_HANDLE Handle,
211 DWORD dwDesiredAccess)
212 {
213 PMANAGER_HANDLE hMgr;
214
215 hMgr = (PMANAGER_HANDLE)Handle;
216 if (hMgr->Handle.Tag == MANAGER_TAG)
217 {
218 RtlMapGenericMask(&dwDesiredAccess,
219 &ScmManagerMapping);
220
221 hMgr->Handle.DesiredAccess = dwDesiredAccess;
222
223 return ERROR_SUCCESS;
224 }
225 else if (hMgr->Handle.Tag == SERVICE_TAG)
226 {
227 RtlMapGenericMask(&dwDesiredAccess,
228 &ScmServiceMapping);
229
230 hMgr->Handle.DesiredAccess = dwDesiredAccess;
231
232 return ERROR_SUCCESS;
233 }
234
235 return ERROR_INVALID_HANDLE;
236 }
237
238
239 DWORD
240 ScmAssignNewTag(PSERVICE lpService)
241 {
242 /* FIXME */
243 DPRINT("Assigning new tag to service %S\n", lpService->lpServiceName);
244 lpService->dwTag = 0;
245 return ERROR_SUCCESS;
246 }
247
248
249 /* Internal recursive function */
250 /* Need to search for every dependency on every service */
251 static DWORD
252 Int_EnumDependentServicesW(HKEY hServicesKey,
253 PSERVICE lpService,
254 DWORD dwServiceState,
255 PSERVICE *lpServices,
256 LPDWORD pcbBytesNeeded,
257 LPDWORD lpServicesReturned)
258 {
259 DWORD dwError = ERROR_SUCCESS;
260 WCHAR szNameBuf[MAX_PATH];
261 WCHAR szValueBuf[MAX_PATH];
262 WCHAR *lpszNameBuf = szNameBuf;
263 WCHAR *lpszValueBuf = szValueBuf;
264 DWORD dwSize;
265 DWORD dwNumSubKeys;
266 DWORD dwIteration;
267 PSERVICE lpCurrentService;
268 HKEY hServiceEnumKey;
269 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
270 DWORD dwDependServiceStrPtr = 0;
271 DWORD dwRequiredSize = 0;
272
273 /* Get the number of service keys */
274 dwError = RegQueryInfoKeyW(hServicesKey,
275 NULL,
276 NULL,
277 NULL,
278 &dwNumSubKeys,
279 NULL,
280 NULL,
281 NULL,
282 NULL,
283 NULL,
284 NULL,
285 NULL);
286 if (dwError != ERROR_SUCCESS)
287 {
288 DPRINT1("ERROR! Unable to get number of services keys.\n");
289 return dwError;
290 }
291
292 /* Iterate the service keys to see if another service depends on the this service */
293 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
294 {
295 dwSize = MAX_PATH;
296 dwError = RegEnumKeyExW(hServicesKey,
297 dwIteration,
298 lpszNameBuf,
299 &dwSize,
300 NULL,
301 NULL,
302 NULL,
303 NULL);
304 if (dwError != ERROR_SUCCESS)
305 return dwError;
306
307 /* Open the Service key */
308 dwError = RegOpenKeyExW(hServicesKey,
309 lpszNameBuf,
310 0,
311 KEY_READ,
312 &hServiceEnumKey);
313 if (dwError != ERROR_SUCCESS)
314 return dwError;
315
316 dwSize = MAX_PATH;
317
318 /* Check for the DependOnService Value */
319 dwError = RegQueryValueExW(hServiceEnumKey,
320 L"DependOnService",
321 NULL,
322 NULL,
323 (LPBYTE)lpszValueBuf,
324 &dwSize);
325
326 /* FIXME: Handle load order. */
327
328 /* If the service found has a DependOnService value */
329 if (dwError == ERROR_SUCCESS)
330 {
331 dwDependServiceStrPtr = 0;
332
333 /* Can be more than one Dependencies in the DependOnService string */
334 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
335 {
336 if (wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
337 {
338 /* Get the current enumed service pointer */
339 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
340
341 /* Check for valid Service */
342 if (!lpCurrentService)
343 {
344 /* This should never happen! */
345 DPRINT1("This should not happen at this point, report to Developer\n");
346 return ERROR_NOT_FOUND;
347 }
348
349 /* Determine state the service is in */
350 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
351 dwCurrentServiceState = SERVICE_INACTIVE;
352
353 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
354 if ((dwCurrentServiceState == dwServiceState) ||
355 (dwServiceState == SERVICE_STATE_ALL))
356 {
357 /* Calculate the required size */
358 dwRequiredSize += sizeof(SERVICE_STATUS);
359 dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
360 dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
361
362 /* Add the size for service name and display name pointers */
363 dwRequiredSize += (2 * sizeof(PVOID));
364
365 /* increase the BytesNeeded size */
366 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
367
368 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
369 comes first */
370
371 /* Recursive call to check for its dependencies */
372 Int_EnumDependentServicesW(hServicesKey,
373 lpCurrentService,
374 dwServiceState,
375 lpServices,
376 pcbBytesNeeded,
377 lpServicesReturned);
378
379 /* If the lpServices is valid set the service pointer */
380 if (lpServices)
381 lpServices[*lpServicesReturned] = lpCurrentService;
382
383 *lpServicesReturned = *lpServicesReturned + 1;
384 }
385 }
386
387 dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
388 }
389 }
390 else if (*pcbBytesNeeded)
391 {
392 dwError = ERROR_SUCCESS;
393 }
394
395 RegCloseKey(hServiceEnumKey);
396 }
397
398 return dwError;
399 }
400
401
402 /* Function 0 */
403 DWORD RCloseServiceHandle(
404 handle_t BindingHandle,
405 LPSC_RPC_HANDLE hSCObject)
406 {
407 PMANAGER_HANDLE hManager;
408
409 DPRINT("RCloseServiceHandle() called\n");
410
411 DPRINT("hSCObject = %p\n", *hSCObject);
412
413 if (*hSCObject == 0)
414 return ERROR_INVALID_HANDLE;
415
416 hManager = (PMANAGER_HANDLE)*hSCObject;
417 if (hManager->Handle.Tag == MANAGER_TAG)
418 {
419 DPRINT("Found manager handle\n");
420
421 hManager->Handle.RefCount--;
422 if (hManager->Handle.RefCount == 0)
423 {
424 /* FIXME: add cleanup code */
425
426 HeapFree(GetProcessHeap(), 0, hManager);
427 }
428
429 DPRINT("RCloseServiceHandle() done\n");
430 return ERROR_SUCCESS;
431 }
432 else if (hManager->Handle.Tag == SERVICE_TAG)
433 {
434 DPRINT("Found service handle\n");
435
436 hManager->Handle.RefCount--;
437 if (hManager->Handle.RefCount == 0)
438 {
439 /* FIXME: add cleanup code */
440
441 HeapFree(GetProcessHeap(), 0, hManager);
442 }
443
444 DPRINT("RCloseServiceHandle() done\n");
445 return ERROR_SUCCESS;
446 }
447
448 DPRINT1("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
449
450 return ERROR_INVALID_HANDLE;
451 }
452
453
454 /* Function 1 */
455 DWORD RControlService(
456 handle_t BindingHandle,
457 SC_RPC_HANDLE hService,
458 DWORD dwControl,
459 LPSERVICE_STATUS lpServiceStatus)
460 {
461 PSERVICE_HANDLE hSvc;
462 PSERVICE lpService;
463 ACCESS_MASK DesiredAccess;
464 DWORD dwError = ERROR_SUCCESS;
465
466 DPRINT("RControlService() called\n");
467
468 if (ScmShutdown)
469 return ERROR_SHUTDOWN_IN_PROGRESS;
470
471 /* Check the service handle */
472 hSvc = (PSERVICE_HANDLE)hService;
473 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
474 {
475 DPRINT1("Invalid handle tag!\n");
476 return ERROR_INVALID_HANDLE;
477 }
478
479 /* Check access rights */
480 switch (dwControl)
481 {
482 case SERVICE_CONTROL_STOP:
483 DesiredAccess = SERVICE_STOP;
484 break;
485
486 case SERVICE_CONTROL_PAUSE:
487 case SERVICE_CONTROL_CONTINUE:
488 DesiredAccess = SERVICE_PAUSE_CONTINUE;
489 break;
490
491 case SERVICE_INTERROGATE:
492 DesiredAccess = SERVICE_INTERROGATE;
493 break;
494
495 default:
496 if (dwControl >= 128 && dwControl <= 255)
497 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
498 else
499 DesiredAccess = SERVICE_QUERY_CONFIG |
500 SERVICE_CHANGE_CONFIG |
501 SERVICE_QUERY_STATUS |
502 SERVICE_START |
503 SERVICE_PAUSE_CONTINUE;
504 break;
505 }
506
507 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
508 DesiredAccess))
509 return ERROR_ACCESS_DENIED;
510
511 /* Check the service entry point */
512 lpService = hSvc->ServiceEntry;
513 if (lpService == NULL)
514 {
515 DPRINT1("lpService == NULL!\n");
516 return ERROR_INVALID_HANDLE;
517 }
518
519 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
520 {
521 /* Send control code to the driver */
522 dwError = ScmControlDriver(lpService,
523 dwControl,
524 lpServiceStatus);
525 }
526 else
527 {
528 /* Send control code to the service */
529 dwError = ScmControlService(lpService,
530 dwControl,
531 lpServiceStatus);
532 }
533
534 /* Return service status information */
535 RtlCopyMemory(lpServiceStatus,
536 &lpService->Status,
537 sizeof(SERVICE_STATUS));
538
539 return dwError;
540 }
541
542
543 /* Function 2 */
544 DWORD RDeleteService(
545 handle_t BindingHandle,
546 SC_RPC_HANDLE hService)
547 {
548 PSERVICE_HANDLE hSvc;
549 PSERVICE lpService;
550 DWORD dwError;
551
552 DPRINT("RDeleteService() called\n");
553
554 if (ScmShutdown)
555 return ERROR_SHUTDOWN_IN_PROGRESS;
556
557 hSvc = (PSERVICE_HANDLE)hService;
558 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
559 return ERROR_INVALID_HANDLE;
560
561 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
562 DELETE))
563 return ERROR_ACCESS_DENIED;
564
565 lpService = hSvc->ServiceEntry;
566 if (lpService == NULL)
567 {
568 DPRINT1("lpService == NULL!\n");
569 return ERROR_INVALID_HANDLE;
570 }
571
572 /* FIXME: Acquire service database lock exclusively */
573
574 if (lpService->bDeleted)
575 {
576 DPRINT1("The service has already been marked for delete!\n");
577 return ERROR_SERVICE_MARKED_FOR_DELETE;
578 }
579
580 /* Mark service for delete */
581 lpService->bDeleted = TRUE;
582
583 dwError = ScmMarkServiceForDelete(lpService);
584
585 /* FIXME: Release service database lock */
586
587 DPRINT("RDeleteService() done\n");
588
589 return dwError;
590 }
591
592
593 /* Function 3 */
594 DWORD RLockServiceDatabase(
595 handle_t BindingHandle,
596 SC_RPC_HANDLE hSCManager,
597 LPSC_RPC_LOCK lpLock)
598 {
599 PMANAGER_HANDLE hMgr;
600
601 DPRINT("RLockServiceDatabase() called\n");
602
603 *lpLock = 0;
604
605 hMgr = (PMANAGER_HANDLE)hSCManager;
606 if (!hMgr || hMgr->Handle.Tag != MANAGER_TAG)
607 return ERROR_INVALID_HANDLE;
608
609 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
610 SC_MANAGER_LOCK))
611 return ERROR_ACCESS_DENIED;
612
613 // return ScmLockDatabase(0, hMgr->0xC, hLock);
614
615 /* FIXME: Lock the database */
616 *lpLock = (void *)0x12345678; /* Dummy! */
617
618 return ERROR_SUCCESS;
619 }
620
621
622 /* Function 4 */
623 DWORD RQueryServiceObjectSecurity(
624 handle_t BindingHandle,
625 SC_RPC_HANDLE hService,
626 SECURITY_INFORMATION dwSecurityInformation,
627 LPBYTE lpSecurityDescriptor,
628 DWORD cbBufSize,
629 LPBOUNDED_DWORD_256K pcbBytesNeeded)
630 {
631 #if 0
632 PSERVICE_HANDLE hSvc;
633 PSERVICE lpService;
634 ULONG DesiredAccess = 0;
635 NTSTATUS Status;
636 DWORD dwBytesNeeded;
637 DWORD dwError;
638
639 DPRINT("RQueryServiceObjectSecurity() called\n");
640
641 hSvc = (PSERVICE_HANDLE)hService;
642 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
643 {
644 DPRINT1("Invalid handle tag!\n");
645 return ERROR_INVALID_HANDLE;
646 }
647
648 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION ||
649 GROUP_SECURITY_INFORMATION ||
650 OWNER_SECURITY_INFORMATION))
651 DesiredAccess |= READ_CONTROL;
652
653 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
654 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
655
656 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
657 DesiredAccess))
658 {
659 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
660 return ERROR_ACCESS_DENIED;
661 }
662
663 lpService = hSvc->ServiceEntry;
664 if (lpService == NULL)
665 {
666 DPRINT1("lpService == NULL!\n");
667 return ERROR_INVALID_HANDLE;
668 }
669
670 /* FIXME: Lock the service list */
671
672 Status = RtlQuerySecurityObject(lpService->lpSecurityDescriptor,
673 dwSecurityInformation,
674 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
675 dwSecuityDescriptorSize,
676 &dwBytesNeeded);
677
678 /* FIXME: Unlock the service list */
679
680 if (NT_SUCCESS(Status))
681 {
682 *pcbBytesNeeded = dwBytesNeeded;
683 dwError = STATUS_SUCCESS;
684 }
685 else if (Status == STATUS_BUFFER_TOO_SMALL)
686 {
687 *pcbBytesNeeded = dwBytesNeeded;
688 dwError = ERROR_INSUFFICIENT_BUFFER;
689 }
690 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
691 {
692 dwError = ERROR_GEN_FAILURE;
693 }
694 else
695 {
696 dwError = RtlNtStatusToDosError(Status);
697 }
698
699 return dwError;
700 #endif
701 UNIMPLEMENTED;
702 return ERROR_CALL_NOT_IMPLEMENTED;
703 }
704
705
706 /* Function 5 */
707 DWORD RSetServiceObjectSecurity(
708 handle_t BindingHandle,
709 SC_RPC_HANDLE hService,
710 DWORD dwSecurityInformation,
711 LPBYTE lpSecurityDescriptor,
712 DWORD dwSecuityDescriptorSize)
713 {
714 PSERVICE_HANDLE hSvc;
715 PSERVICE lpService;
716 ULONG DesiredAccess = 0;
717 HANDLE hToken = NULL;
718 HKEY hServiceKey;
719 NTSTATUS Status;
720 DWORD dwError;
721
722 DPRINT1("RSetServiceObjectSecurity() called\n");
723
724 hSvc = (PSERVICE_HANDLE)hService;
725 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
726 {
727 DPRINT1("Invalid handle tag!\n");
728 return ERROR_INVALID_HANDLE;
729 }
730
731 if (dwSecurityInformation == 0 ||
732 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
733 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
734 return ERROR_INVALID_PARAMETER;
735
736 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
737 return ERROR_INVALID_PARAMETER;
738
739 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
740 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
741
742 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
743 DesiredAccess |= WRITE_DAC;
744
745 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
746 DesiredAccess |= WRITE_OWNER;
747
748 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
749 (((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
750 return ERROR_INVALID_PARAMETER;
751
752 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
753 (((PSECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
754 return ERROR_INVALID_PARAMETER;
755
756 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
757 DesiredAccess))
758 {
759 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
760 return ERROR_ACCESS_DENIED;
761 }
762
763 lpService = hSvc->ServiceEntry;
764 if (lpService == NULL)
765 {
766 DPRINT1("lpService == NULL!\n");
767 return ERROR_INVALID_HANDLE;
768 }
769
770 if (lpService->bDeleted)
771 return ERROR_SERVICE_MARKED_FOR_DELETE;
772
773 RpcImpersonateClient(NULL);
774
775 Status = NtOpenThreadToken(NtCurrentThread(),
776 8,
777 TRUE,
778 &hToken);
779 if (!NT_SUCCESS(Status))
780 return RtlNtStatusToDosError(Status);
781
782 RpcRevertToSelf();
783
784 /* FIXME: Lock service database */
785
786 #if 0
787 Status = RtlSetSecurityObject(dwSecurityInformation,
788 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
789 &lpService->lpSecurityDescriptor,
790 &ScmServiceMapping,
791 hToken);
792 if (!NT_SUCCESS(Status))
793 {
794 dwError = RtlNtStatusToDosError(Status);
795 goto Done;
796 }
797 #endif
798
799 dwError = ScmOpenServiceKey(lpService->lpServiceName,
800 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
801 &hServiceKey);
802 if (dwError != ERROR_SUCCESS)
803 goto Done;
804
805 UNIMPLEMENTED;
806 dwError = ERROR_SUCCESS;
807 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
808 // lpService->lpSecurityDescriptor);
809
810 RegFlushKey(hServiceKey);
811 RegCloseKey(hServiceKey);
812
813 Done:
814
815 if (hToken != NULL)
816 NtClose(hToken);
817
818 /* FIXME: Unlock service database */
819
820 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
821
822 return dwError;
823 }
824
825
826 /* Function 6 */
827 DWORD RQueryServiceStatus(
828 handle_t BindingHandle,
829 SC_RPC_HANDLE hService,
830 LPSERVICE_STATUS lpServiceStatus)
831 {
832 PSERVICE_HANDLE hSvc;
833 PSERVICE lpService;
834
835 DPRINT("RQueryServiceStatus() called\n");
836
837 if (ScmShutdown)
838 return ERROR_SHUTDOWN_IN_PROGRESS;
839
840 hSvc = (PSERVICE_HANDLE)hService;
841 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
842 {
843 DPRINT1("Invalid handle tag!\n");
844 return ERROR_INVALID_HANDLE;
845 }
846
847 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
848 SERVICE_QUERY_STATUS))
849 {
850 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
851 return ERROR_ACCESS_DENIED;
852 }
853
854 lpService = hSvc->ServiceEntry;
855 if (lpService == NULL)
856 {
857 DPRINT1("lpService == NULL!\n");
858 return ERROR_INVALID_HANDLE;
859 }
860
861 /* Return service status information */
862 RtlCopyMemory(lpServiceStatus,
863 &lpService->Status,
864 sizeof(SERVICE_STATUS));
865
866 return ERROR_SUCCESS;
867 }
868
869
870 /* Function 7 */
871 DWORD RSetServiceStatus(
872 handle_t BindingHandle,
873 SC_RPC_HANDLE hServiceStatus,
874 LPSERVICE_STATUS lpServiceStatus)
875 {
876 PSERVICE lpService;
877
878 DPRINT("RSetServiceStatus() called\n");
879
880 if (ScmShutdown)
881 return ERROR_SHUTDOWN_IN_PROGRESS;
882
883 lpService = ScmGetServiceEntryByClientHandle((ULONG)hServiceStatus);
884 if (lpService == NULL)
885 {
886 DPRINT1("lpService == NULL!\n");
887 return ERROR_INVALID_HANDLE;
888 }
889
890 RtlCopyMemory(&lpService->Status,
891 lpServiceStatus,
892 sizeof(SERVICE_STATUS));
893
894 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
895 DPRINT("RSetServiceStatus() done\n");
896
897 return ERROR_SUCCESS;
898 }
899
900
901 /* Function 8 */
902 DWORD RUnlockServiceDatabase(
903 handle_t BindingHandle,
904 LPSC_RPC_LOCK Lock)
905 {
906 UNIMPLEMENTED;
907 return ERROR_SUCCESS;
908 }
909
910
911 /* Function 9 */
912 DWORD RNotifyBootConfigStatus(
913 handle_t BindingHandle,
914 SVCCTL_HANDLEW lpMachineName,
915 DWORD BootAcceptable)
916 {
917 UNIMPLEMENTED;
918 return ERROR_CALL_NOT_IMPLEMENTED;
919 }
920
921
922 /* Function 10 */
923 DWORD RSetServiceBitsW(
924 handle_t BindingHandle,
925 SC_RPC_HANDLE hServiceStatus,
926 DWORD dwServiceBits,
927 int bSetBitsOn,
928 int bUpdateImmediately,
929 wchar_t *lpString)
930 {
931 UNIMPLEMENTED;
932 return ERROR_CALL_NOT_IMPLEMENTED;
933 }
934
935
936 /* Function 11 */
937 DWORD RChangeServiceConfigW(
938 handle_t BindingHandle,
939 SC_RPC_HANDLE hService,
940 DWORD dwServiceType,
941 DWORD dwStartType,
942 DWORD dwErrorControl,
943 LPWSTR lpBinaryPathName,
944 LPWSTR lpLoadOrderGroup,
945 LPDWORD lpdwTagId,
946 LPBYTE lpDependencies,
947 DWORD dwDependSize,
948 LPWSTR lpServiceStartName,
949 LPBYTE lpPassword,
950 DWORD dwPwSize,
951 LPWSTR lpDisplayName)
952 {
953 DWORD dwError = ERROR_SUCCESS;
954 PSERVICE_HANDLE hSvc;
955 PSERVICE lpService = NULL;
956 HKEY hServiceKey = NULL;
957 LPWSTR lpDisplayNameW = NULL;
958
959 DPRINT("RChangeServiceConfigW() called\n");
960 DPRINT("dwServiceType = %lu\n", dwServiceType);
961 DPRINT("dwStartType = %lu\n", dwStartType);
962 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
963 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
964 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
965 DPRINT("lpDisplayName = %S\n", lpDisplayName);
966
967 if (ScmShutdown)
968 return ERROR_SHUTDOWN_IN_PROGRESS;
969
970 hSvc = (PSERVICE_HANDLE)hService;
971 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
972 {
973 DPRINT1("Invalid handle tag!\n");
974 return ERROR_INVALID_HANDLE;
975 }
976
977 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
978 SERVICE_CHANGE_CONFIG))
979 {
980 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
981 return ERROR_ACCESS_DENIED;
982 }
983
984 lpService = hSvc->ServiceEntry;
985 if (lpService == NULL)
986 {
987 DPRINT1("lpService == NULL!\n");
988 return ERROR_INVALID_HANDLE;
989 }
990
991 /* FIXME: Lock database exclusively */
992
993 if (lpService->bDeleted)
994 {
995 /* FIXME: Unlock database */
996 DPRINT1("The service has already been marked for delete!\n");
997 return ERROR_SERVICE_MARKED_FOR_DELETE;
998 }
999
1000 /* Open the service key */
1001 dwError = ScmOpenServiceKey(lpService->szServiceName,
1002 KEY_SET_VALUE,
1003 &hServiceKey);
1004 if (dwError != ERROR_SUCCESS)
1005 goto done;
1006
1007 /* Write service data to the registry */
1008 /* Set the display name */
1009 if (lpDisplayName != NULL && *lpDisplayName != 0)
1010 {
1011 RegSetValueExW(hServiceKey,
1012 L"DisplayName",
1013 0,
1014 REG_SZ,
1015 (LPBYTE)lpDisplayName,
1016 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1017
1018 /* Update the display name */
1019 lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
1020 0,
1021 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1022 if (lpDisplayNameW == NULL)
1023 {
1024 dwError = ERROR_NOT_ENOUGH_MEMORY;
1025 goto done;
1026 }
1027
1028 if (lpService->lpDisplayName != lpService->lpServiceName)
1029 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1030
1031 lpService->lpDisplayName = lpDisplayNameW;
1032 }
1033
1034 if (dwServiceType != SERVICE_NO_CHANGE)
1035 {
1036 /* Set the service type */
1037 dwError = RegSetValueExW(hServiceKey,
1038 L"Type",
1039 0,
1040 REG_DWORD,
1041 (LPBYTE)&dwServiceType,
1042 sizeof(DWORD));
1043 if (dwError != ERROR_SUCCESS)
1044 goto done;
1045
1046 lpService->Status.dwServiceType = dwServiceType;
1047 }
1048
1049 if (dwStartType != SERVICE_NO_CHANGE)
1050 {
1051 /* Set the start value */
1052 dwError = RegSetValueExW(hServiceKey,
1053 L"Start",
1054 0,
1055 REG_DWORD,
1056 (LPBYTE)&dwStartType,
1057 sizeof(DWORD));
1058 if (dwError != ERROR_SUCCESS)
1059 goto done;
1060
1061 lpService->dwStartType = dwStartType;
1062 }
1063
1064 if (dwErrorControl != SERVICE_NO_CHANGE)
1065 {
1066 /* Set the error control value */
1067 dwError = RegSetValueExW(hServiceKey,
1068 L"ErrorControl",
1069 0,
1070 REG_DWORD,
1071 (LPBYTE)&dwErrorControl,
1072 sizeof(DWORD));
1073 if (dwError != ERROR_SUCCESS)
1074 goto done;
1075
1076 lpService->dwErrorControl = dwErrorControl;
1077 }
1078
1079 #if 0
1080 /* FIXME: set the new ImagePath value */
1081
1082 /* Set the image path */
1083 if (dwServiceType & SERVICE_WIN32)
1084 {
1085 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1086 {
1087 dwError = RegSetValueExW(hServiceKey,
1088 L"ImagePath",
1089 0,
1090 REG_EXPAND_SZ,
1091 (LPBYTE)lpBinaryPathName,
1092 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1093 if (dwError != ERROR_SUCCESS)
1094 goto done;
1095 }
1096 }
1097 else if (dwServiceType & SERVICE_DRIVER)
1098 {
1099 if (lpImagePath != NULL && *lpImagePath != 0)
1100 {
1101 dwError = RegSetValueExW(hServiceKey,
1102 L"ImagePath",
1103 0,
1104 REG_EXPAND_SZ,
1105 (LPBYTE)lpImagePath,
1106 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
1107 if (dwError != ERROR_SUCCESS)
1108 goto done;
1109 }
1110 }
1111 #endif
1112
1113 /* Set the group name */
1114 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1115 {
1116 dwError = RegSetValueExW(hServiceKey,
1117 L"Group",
1118 0,
1119 REG_SZ,
1120 (LPBYTE)lpLoadOrderGroup,
1121 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1122 if (dwError != ERROR_SUCCESS)
1123 goto done;
1124 /* FIXME: update lpService->lpServiceGroup */
1125 }
1126
1127 if (lpdwTagId != NULL)
1128 {
1129 dwError = ScmAssignNewTag(lpService);
1130 if (dwError != ERROR_SUCCESS)
1131 goto done;
1132
1133 dwError = RegSetValueExW(hServiceKey,
1134 L"Tag",
1135 0,
1136 REG_DWORD,
1137 (LPBYTE)&lpService->dwTag,
1138 sizeof(DWORD));
1139 if (dwError != ERROR_SUCCESS)
1140 goto done;
1141
1142 *lpdwTagId = lpService->dwTag;
1143 }
1144
1145 /* Write dependencies */
1146 if (lpDependencies != NULL && *lpDependencies != 0)
1147 {
1148 dwError = ScmWriteDependencies(hServiceKey,
1149 (LPWSTR)lpDependencies,
1150 dwDependSize);
1151 if (dwError != ERROR_SUCCESS)
1152 goto done;
1153 }
1154
1155 if (lpPassword != NULL)
1156 {
1157 /* FIXME: Write password */
1158 }
1159
1160 /* FIXME: Unlock database */
1161
1162 done:
1163 if (hServiceKey != NULL)
1164 RegCloseKey(hServiceKey);
1165
1166 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1167
1168 return dwError;
1169 }
1170
1171 /* Create a path suitable for the bootloader out of the full path */
1172 DWORD
1173 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1174 {
1175 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1176 WCHAR Dest;
1177 WCHAR *Expanded;
1178 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1179 OBJECT_ATTRIBUTES ObjectAttributes;
1180 NTSTATUS Status;
1181 HANDLE SymbolicLinkHandle;
1182
1183 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1184
1185 ServiceNameLen = wcslen(CanonName);
1186 /* First check, if it's already good */
1187 if (ServiceNameLen > 12 &&
1188 !wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1189 {
1190 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1191
1192 if (*RelativeName == NULL)
1193 {
1194 DPRINT1("Error allocating memory for boot driver name!\n");
1195 return ERROR_NOT_ENOUGH_MEMORY;
1196 }
1197
1198 /* Copy it */
1199 wcscpy(*RelativeName, CanonName);
1200
1201 DPRINT1("Bootdriver name %S\n", *RelativeName);
1202 return ERROR_SUCCESS;
1203 }
1204
1205 /* If it has %SystemRoot% prefix, substitute it to \System*/
1206 if (ServiceNameLen > 13 &&
1207 !wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1208 {
1209 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1210 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1211
1212 if (*RelativeName == NULL)
1213 {
1214 DPRINT1("Error allocating memory for boot driver name!\n");
1215 return ERROR_NOT_ENOUGH_MEMORY;
1216 }
1217
1218 /* Copy it */
1219 wcscpy(*RelativeName, L"\\SystemRoot\\");
1220 wcscat(*RelativeName, CanonName + 13);
1221
1222 DPRINT1("Bootdriver name %S\n", *RelativeName);
1223 return ERROR_SUCCESS;
1224 }
1225
1226 /* Get buffer size needed for expanding env strings */
1227 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1228
1229 if (BufferSize <= 1)
1230 {
1231 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1232 return ERROR_INVALID_ENVIRONMENT;
1233 }
1234
1235 /* Allocate memory, since the size is known now */
1236 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1237 if (!Expanded)
1238 {
1239 DPRINT1("Error allocating memory for boot driver name!\n");
1240 return ERROR_NOT_ENOUGH_MEMORY;
1241 }
1242
1243 /* Expand it */
1244 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1245 BufferSize)
1246 {
1247 DPRINT1("Error during a call to ExpandEnvironmentStringsW()\n");
1248 LocalFree(Expanded);
1249 return ERROR_NOT_ENOUGH_MEMORY;
1250 }
1251
1252 /* Convert to NY-style path */
1253 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1254 {
1255 DPRINT1("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1256 return ERROR_INVALID_ENVIRONMENT;
1257 }
1258
1259 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1260
1261 /* No need to keep the dos-path anymore */
1262 LocalFree(Expanded);
1263
1264 /* Copy it to the allocated place */
1265 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1266 if (!Expanded)
1267 {
1268 DPRINT1("Error allocating memory for boot driver name!\n");
1269 return ERROR_NOT_ENOUGH_MEMORY;
1270 }
1271
1272 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1273 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1274 Expanded[ExpandedLen] = 0;
1275
1276 if (ServiceNameLen > ExpandedLen &&
1277 !wcsnicmp(Expanded, CanonName, ExpandedLen))
1278 {
1279 /* Only \SystemRoot\ is missing */
1280 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1281 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1282
1283 if (*RelativeName == NULL)
1284 {
1285 DPRINT1("Error allocating memory for boot driver name!\n");
1286 LocalFree(Expanded);
1287 return ERROR_NOT_ENOUGH_MEMORY;
1288 }
1289
1290 wcscpy(*RelativeName, L"\\SystemRoot\\");
1291 wcscat(*RelativeName, CanonName + ExpandedLen);
1292
1293 RtlFreeUnicodeString(&NtPathName);
1294 return ERROR_SUCCESS;
1295 }
1296
1297 /* The most complex case starts here */
1298 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1299 InitializeObjectAttributes(&ObjectAttributes,
1300 &SystemRoot,
1301 OBJ_CASE_INSENSITIVE,
1302 NULL,
1303 NULL);
1304
1305 /* Open this symlink */
1306 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1307
1308 if (NT_SUCCESS(Status))
1309 {
1310 LinkTarget.Length = 0;
1311 LinkTarget.MaximumLength = 0;
1312
1313 DPRINT("Opened symbolic link object\n");
1314
1315 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1316 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1317 {
1318 /* Check if required buffer size is sane */
1319 if (BufferSize > 0xFFFD)
1320 {
1321 DPRINT1("Too large buffer required\n");
1322 *RelativeName = 0;
1323
1324 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1325 LocalFree(Expanded);
1326 return ERROR_NOT_ENOUGH_MEMORY;
1327 }
1328
1329 /* Alloc the string */
1330 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1331 if (!LinkTarget.Buffer)
1332 {
1333 DPRINT1("Unable to alloc buffer\n");
1334 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1335 LocalFree(Expanded);
1336 return ERROR_NOT_ENOUGH_MEMORY;
1337 }
1338
1339 /* Do a real query now */
1340 LinkTarget.Length = BufferSize;
1341 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1342
1343 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1344 if (NT_SUCCESS(Status))
1345 {
1346 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1347
1348 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1349 if ((ServiceNameLen > ExpandedLen) &&
1350 !wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1351 {
1352 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1353 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1354
1355 if (*RelativeName == NULL)
1356 {
1357 DPRINT1("Unable to alloc buffer\n");
1358 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1359 LocalFree(Expanded);
1360 RtlFreeUnicodeString(&NtPathName);
1361 return ERROR_NOT_ENOUGH_MEMORY;
1362 }
1363
1364 /* Copy it over, substituting the first part
1365 with SystemRoot */
1366 wcscpy(*RelativeName, L"\\SystemRoot\\");
1367 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1368
1369 /* Cleanup */
1370 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1371 LocalFree(Expanded);
1372 RtlFreeUnicodeString(&NtPathName);
1373
1374 /* Return success */
1375 return ERROR_SUCCESS;
1376 }
1377 else
1378 {
1379 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1380 LocalFree(Expanded);
1381 RtlFreeUnicodeString(&NtPathName);
1382 return ERROR_INVALID_PARAMETER;
1383 }
1384 }
1385 else
1386 {
1387 DPRINT1("Error, Status = %08X\n", Status);
1388 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1389 LocalFree(Expanded);
1390 RtlFreeUnicodeString(&NtPathName);
1391 return ERROR_INVALID_PARAMETER;
1392 }
1393 }
1394 else
1395 {
1396 DPRINT1("Error, Status = %08X\n", Status);
1397 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1398 LocalFree(Expanded);
1399 RtlFreeUnicodeString(&NtPathName);
1400 return ERROR_INVALID_PARAMETER;
1401 }
1402 }
1403 else
1404 {
1405 DPRINT1("Error, Status = %08X\n", Status);
1406 LocalFree(Expanded);
1407 return ERROR_INVALID_PARAMETER;
1408 }
1409
1410 /* Failure */
1411 *RelativeName = NULL;
1412 return ERROR_INVALID_PARAMETER;
1413 }
1414
1415 DWORD
1416 ScmCanonDriverImagePath(DWORD dwStartType,
1417 wchar_t *lpServiceName,
1418 wchar_t **lpCanonName)
1419 {
1420 DWORD ServiceNameLen, Result;
1421 UNICODE_STRING NtServiceName;
1422 WCHAR *RelativeName;
1423 WCHAR *SourceName = lpServiceName;
1424
1425 /* Calculate the length of the service's name */
1426 ServiceNameLen = wcslen(lpServiceName);
1427
1428 /* 12 is wcslen(L"\\SystemRoot\\") */
1429 if (ServiceNameLen > 12 &&
1430 !wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1431 {
1432 /* SystemRoot prefix is already included */
1433
1434 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1435
1436 if (*lpCanonName == NULL)
1437 {
1438 DPRINT1("Error allocating memory for canonized service name!\n");
1439 return ERROR_NOT_ENOUGH_MEMORY;
1440 }
1441
1442 /* If it's a boot-time driver, it must be systemroot relative */
1443 if (dwStartType == SERVICE_BOOT_START)
1444 SourceName += 12;
1445
1446 /* Copy it */
1447 wcscpy(*lpCanonName, SourceName);
1448
1449 DPRINT("Canonicalized name %S\n", *lpCanonName);
1450 return NO_ERROR;
1451 }
1452
1453 /* Check if it has %SystemRoot% (len=13) */
1454 if (ServiceNameLen > 13 &&
1455 !wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1456 {
1457 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1458 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1459
1460 if (*lpCanonName == NULL)
1461 {
1462 DPRINT1("Error allocating memory for canonized service name!\n");
1463 return ERROR_NOT_ENOUGH_MEMORY;
1464 }
1465
1466 /* If it's a boot-time driver, it must be systemroot relative */
1467 if (dwStartType == SERVICE_BOOT_START)
1468 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1469
1470 wcscat(*lpCanonName, lpServiceName + 13);
1471
1472 DPRINT("Canonicalized name %S\n", *lpCanonName);
1473 return NO_ERROR;
1474 }
1475
1476 /* Check if it's a relative path name */
1477 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1478 {
1479 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1480
1481 if (*lpCanonName == NULL)
1482 {
1483 DPRINT1("Error allocating memory for canonized service name!\n");
1484 return ERROR_NOT_ENOUGH_MEMORY;
1485 }
1486
1487 /* Just copy it over without changing */
1488 wcscpy(*lpCanonName, lpServiceName);
1489
1490 return NO_ERROR;
1491 }
1492
1493 /* It seems to be a DOS path, convert it */
1494 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1495 {
1496 DPRINT1("RtlDosPathNameToNtPathName_U() failed!\n");
1497 return ERROR_INVALID_PARAMETER;
1498 }
1499
1500 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1501
1502 if (*lpCanonName == NULL)
1503 {
1504 DPRINT1("Error allocating memory for canonized service name!\n");
1505 RtlFreeUnicodeString(&NtServiceName);
1506 return ERROR_NOT_ENOUGH_MEMORY;
1507 }
1508
1509 /* Copy the string */
1510 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1511
1512 /* The unicode string is not needed anymore */
1513 RtlFreeUnicodeString(&NtServiceName);
1514
1515 if (dwStartType != SERVICE_BOOT_START)
1516 {
1517 DPRINT("Canonicalized name %S\n", *lpCanonName);
1518 return NO_ERROR;
1519 }
1520
1521 /* The service is boot-started, so must be relative */
1522 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1523 if (Result)
1524 {
1525 /* There is a problem, free name and return */
1526 LocalFree(*lpCanonName);
1527 DPRINT1("Error converting named!\n");
1528 return Result;
1529 }
1530
1531 ASSERT(RelativeName);
1532
1533 /* Copy that string */
1534 wcscpy(*lpCanonName, RelativeName + 12);
1535
1536 /* Free the allocated buffer */
1537 LocalFree(RelativeName);
1538
1539 DPRINT("Canonicalized name %S\n", *lpCanonName);
1540
1541 /* Success */
1542 return NO_ERROR;
1543 }
1544
1545
1546 /* Function 12 */
1547 DWORD RCreateServiceW(
1548 handle_t BindingHandle,
1549 SC_RPC_HANDLE hSCManager,
1550 LPWSTR lpServiceName,
1551 LPWSTR lpDisplayName,
1552 DWORD dwDesiredAccess,
1553 DWORD dwServiceType,
1554 DWORD dwStartType,
1555 DWORD dwErrorControl,
1556 LPWSTR lpBinaryPathName,
1557 LPWSTR lpLoadOrderGroup,
1558 LPDWORD lpdwTagId,
1559 LPBYTE lpDependencies,
1560 DWORD dwDependSize,
1561 LPWSTR lpServiceStartName,
1562 LPBYTE lpPassword,
1563 DWORD dwPwSize,
1564 LPSC_RPC_HANDLE lpServiceHandle)
1565 {
1566 PMANAGER_HANDLE hManager;
1567 DWORD dwError = ERROR_SUCCESS;
1568 PSERVICE lpService = NULL;
1569 SC_HANDLE hServiceHandle = NULL;
1570 LPWSTR lpImagePath = NULL;
1571 HKEY hServiceKey = NULL;
1572
1573 DPRINT("RCreateServiceW() called\n");
1574 DPRINT("lpServiceName = %S\n", lpServiceName);
1575 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1576 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1577 DPRINT("dwServiceType = %lu\n", dwServiceType);
1578 DPRINT("dwStartType = %lu\n", dwStartType);
1579 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1580 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1581 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1582
1583 if (ScmShutdown)
1584 return ERROR_SHUTDOWN_IN_PROGRESS;
1585
1586 hManager = (PMANAGER_HANDLE)hSCManager;
1587 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1588 {
1589 DPRINT1("Invalid manager handle!\n");
1590 return ERROR_INVALID_HANDLE;
1591 }
1592
1593 /* Check access rights */
1594 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1595 SC_MANAGER_CREATE_SERVICE))
1596 {
1597 DPRINT1("Insufficient access rights! 0x%lx\n",
1598 hManager->Handle.DesiredAccess);
1599 return ERROR_ACCESS_DENIED;
1600 }
1601
1602 /* Fail if the service already exists! */
1603 if (ScmGetServiceEntryByName(lpServiceName) != NULL)
1604 return ERROR_SERVICE_EXISTS;
1605
1606 if (dwServiceType & SERVICE_DRIVER)
1607 {
1608 dwError = ScmCanonDriverImagePath(dwStartType,
1609 lpBinaryPathName,
1610 &lpImagePath);
1611
1612 if (dwError != ERROR_SUCCESS)
1613 goto done;
1614 }
1615
1616 /* Allocate a new service entry */
1617 dwError = ScmCreateNewServiceRecord(lpServiceName,
1618 &lpService);
1619 if (dwError != ERROR_SUCCESS)
1620 goto done;
1621
1622 /* Fill the new service entry */
1623 lpService->Status.dwServiceType = dwServiceType;
1624 lpService->dwStartType = dwStartType;
1625 lpService->dwErrorControl = dwErrorControl;
1626
1627 /* Fill the display name */
1628 if (lpDisplayName != NULL &&
1629 *lpDisplayName != 0 &&
1630 wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1631 {
1632 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1633 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1634 if (lpService->lpDisplayName == NULL)
1635 {
1636 dwError = ERROR_NOT_ENOUGH_MEMORY;
1637 goto done;
1638 }
1639 wcscpy(lpService->lpDisplayName, lpDisplayName);
1640 }
1641
1642 /* Assign the service to a group */
1643 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1644 {
1645 dwError = ScmSetServiceGroup(lpService,
1646 lpLoadOrderGroup);
1647 if (dwError != ERROR_SUCCESS)
1648 goto done;
1649 }
1650
1651 /* Assign a new tag */
1652 if (lpdwTagId != NULL)
1653 {
1654 dwError = ScmAssignNewTag(lpService);
1655 if (dwError != ERROR_SUCCESS)
1656 goto done;
1657 }
1658
1659 /* Write service data to the registry */
1660 /* Create the service key */
1661 dwError = ScmCreateServiceKey(lpServiceName,
1662 KEY_WRITE,
1663 &hServiceKey);
1664 if (dwError != ERROR_SUCCESS)
1665 goto done;
1666
1667 /* Set the display name */
1668 if (lpDisplayName != NULL && *lpDisplayName != 0)
1669 {
1670 RegSetValueExW(hServiceKey,
1671 L"DisplayName",
1672 0,
1673 REG_SZ,
1674 (LPBYTE)lpDisplayName,
1675 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1676 }
1677
1678 /* Set the service type */
1679 dwError = RegSetValueExW(hServiceKey,
1680 L"Type",
1681 0,
1682 REG_DWORD,
1683 (LPBYTE)&dwServiceType,
1684 sizeof(DWORD));
1685 if (dwError != ERROR_SUCCESS)
1686 goto done;
1687
1688 /* Set the start value */
1689 dwError = RegSetValueExW(hServiceKey,
1690 L"Start",
1691 0,
1692 REG_DWORD,
1693 (LPBYTE)&dwStartType,
1694 sizeof(DWORD));
1695 if (dwError != ERROR_SUCCESS)
1696 goto done;
1697
1698 /* Set the error control value */
1699 dwError = RegSetValueExW(hServiceKey,
1700 L"ErrorControl",
1701 0,
1702 REG_DWORD,
1703 (LPBYTE)&dwErrorControl,
1704 sizeof(DWORD));
1705 if (dwError != ERROR_SUCCESS)
1706 goto done;
1707
1708 /* Set the image path */
1709 if (dwServiceType & SERVICE_WIN32)
1710 {
1711 dwError = RegSetValueExW(hServiceKey,
1712 L"ImagePath",
1713 0,
1714 REG_EXPAND_SZ,
1715 (LPBYTE)lpBinaryPathName,
1716 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1717 if (dwError != ERROR_SUCCESS)
1718 goto done;
1719 }
1720 else if (dwServiceType & SERVICE_DRIVER)
1721 {
1722 dwError = RegSetValueExW(hServiceKey,
1723 L"ImagePath",
1724 0,
1725 REG_EXPAND_SZ,
1726 (LPBYTE)lpImagePath,
1727 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
1728 if (dwError != ERROR_SUCCESS)
1729 goto done;
1730 }
1731
1732 /* Set the group name */
1733 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1734 {
1735 dwError = RegSetValueExW(hServiceKey,
1736 L"Group",
1737 0,
1738 REG_SZ,
1739 (LPBYTE)lpLoadOrderGroup,
1740 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1741 if (dwError != ERROR_SUCCESS)
1742 goto done;
1743 }
1744
1745 if (lpdwTagId != NULL)
1746 {
1747 dwError = RegSetValueExW(hServiceKey,
1748 L"Tag",
1749 0,
1750 REG_DWORD,
1751 (LPBYTE)&lpService->dwTag,
1752 sizeof(DWORD));
1753 if (dwError != ERROR_SUCCESS)
1754 goto done;
1755 }
1756
1757 /* Write dependencies */
1758 if (lpDependencies != NULL && *lpDependencies != 0)
1759 {
1760 dwError = ScmWriteDependencies(hServiceKey,
1761 (LPWSTR)lpDependencies,
1762 dwDependSize);
1763 if (dwError != ERROR_SUCCESS)
1764 goto done;
1765 }
1766
1767 if (lpPassword != NULL)
1768 {
1769 /* FIXME: Write password */
1770 }
1771
1772 dwError = ScmCreateServiceHandle(lpService,
1773 &hServiceHandle);
1774 if (dwError != ERROR_SUCCESS)
1775 goto done;
1776
1777 dwError = ScmCheckAccess(hServiceHandle,
1778 dwDesiredAccess);
1779 if (dwError != ERROR_SUCCESS)
1780 goto done;
1781
1782 done:;
1783 if (hServiceKey != NULL)
1784 RegCloseKey(hServiceKey);
1785
1786 if (dwError == ERROR_SUCCESS)
1787 {
1788 DPRINT("hService %p\n", hServiceHandle);
1789 *lpServiceHandle = (unsigned long)hServiceHandle; /* FIXME: 64 bit portability */
1790
1791 if (lpdwTagId != NULL)
1792 *lpdwTagId = lpService->dwTag;
1793 }
1794 else
1795 {
1796 /* Release the display name buffer */
1797 if (lpService->lpServiceName != NULL)
1798 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1799
1800 if (hServiceHandle)
1801 {
1802 /* Remove the service handle */
1803 HeapFree(GetProcessHeap(), 0, hServiceHandle);
1804 }
1805
1806 if (lpService != NULL)
1807 {
1808 /* FIXME: remove the service entry */
1809 }
1810 }
1811
1812 if (lpImagePath != NULL)
1813 HeapFree(GetProcessHeap(), 0, lpImagePath);
1814
1815 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
1816
1817 return dwError;
1818 }
1819
1820
1821 /* Function 13 */
1822 DWORD REnumDependentServicesW(
1823 handle_t BindingHandle,
1824 SC_RPC_HANDLE hService,
1825 DWORD dwServiceState,
1826 LPBYTE lpServices,
1827 DWORD cbBufSize,
1828 LPBOUNDED_DWORD_256K pcbBytesNeeded,
1829 LPBOUNDED_DWORD_256K lpServicesReturned)
1830 {
1831 DWORD dwError = ERROR_SUCCESS;
1832 DWORD dwServicesReturned = 0;
1833 DWORD dwServiceCount;
1834 HKEY hServicesKey = NULL;
1835 LPSC_RPC_HANDLE hSCObject;
1836 PSERVICE_HANDLE hSvc;
1837 PSERVICE lpService = NULL;
1838 PSERVICE *lpServicesArray = NULL;
1839 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
1840 LPWSTR lpStr;
1841
1842 *pcbBytesNeeded = 0;
1843 *lpServicesReturned = 0;
1844
1845 DPRINT("REnumDependentServicesW() called\n");
1846
1847 hSCObject = &hService;
1848 hSvc = (PSERVICE_HANDLE) *hSCObject;
1849 lpService = hSvc->ServiceEntry;
1850
1851 /* Check access rights */
1852 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1853 SC_MANAGER_ENUMERATE_SERVICE))
1854 {
1855 DPRINT1("Insufficient access rights! 0x%lx\n",
1856 hSvc->Handle.DesiredAccess);
1857 return ERROR_ACCESS_DENIED;
1858 }
1859
1860 /* Open the Services Reg key */
1861 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1862 L"System\\CurrentControlSet\\Services",
1863 0,
1864 KEY_READ,
1865 &hServicesKey);
1866 if (dwError != ERROR_SUCCESS)
1867 return dwError;
1868
1869 /* First determine the bytes needed and get the number of dependent services */
1870 dwError = Int_EnumDependentServicesW(hServicesKey,
1871 lpService,
1872 dwServiceState,
1873 NULL,
1874 pcbBytesNeeded,
1875 &dwServicesReturned);
1876 if (dwError != ERROR_SUCCESS)
1877 goto Done;
1878
1879 /* If buffer size is less than the bytes needed or pointer is null */
1880 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
1881 {
1882 dwError = ERROR_MORE_DATA;
1883 goto Done;
1884 }
1885
1886 /* Allocate memory for array of service pointers */
1887 lpServicesArray = HeapAlloc(GetProcessHeap(),
1888 0,
1889 (dwServicesReturned + 1) * sizeof(PSERVICE));
1890 if (!lpServicesArray)
1891 {
1892 DPRINT1("Could not allocate a buffer!!\n");
1893 dwError = ERROR_NOT_ENOUGH_MEMORY;
1894 goto Done;
1895 }
1896
1897 dwServicesReturned = 0;
1898 *pcbBytesNeeded = 0;
1899
1900 dwError = Int_EnumDependentServicesW(hServicesKey,
1901 lpService,
1902 dwServiceState,
1903 lpServicesArray,
1904 pcbBytesNeeded,
1905 &dwServicesReturned);
1906 if (dwError != ERROR_SUCCESS)
1907 {
1908 goto Done;
1909 }
1910
1911 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
1912 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
1913
1914 /* Copy EnumDepenedentService to Buffer */
1915 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
1916 {
1917 lpService = lpServicesArray[dwServiceCount];
1918
1919 /* Copy status info */
1920 memcpy(&lpServicesPtr->ServiceStatus,
1921 &lpService->Status,
1922 sizeof(SERVICE_STATUS));
1923
1924 /* Copy display name */
1925 wcscpy(lpStr, lpService->lpDisplayName);
1926 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
1927 lpStr += (wcslen(lpService->lpDisplayName) + 1);
1928
1929 /* Copy service name */
1930 wcscpy(lpStr, lpService->lpServiceName);
1931 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
1932 lpStr += (wcslen(lpService->lpServiceName) + 1);
1933
1934 lpServicesPtr ++;
1935 }
1936
1937 *lpServicesReturned = dwServicesReturned;
1938
1939 Done:
1940 if (lpServicesArray != NULL)
1941 HeapFree(GetProcessHeap(), 0, lpServicesArray);
1942
1943 RegCloseKey(hServicesKey);
1944
1945 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
1946
1947 return dwError;
1948 }
1949
1950
1951 /* Function 14 */
1952 DWORD REnumServicesStatusW(
1953 handle_t BindingHandle,
1954 SC_RPC_HANDLE hSCManager,
1955 DWORD dwServiceType,
1956 DWORD dwServiceState,
1957 LPBYTE lpBuffer,
1958 DWORD dwBufSize,
1959 LPBOUNDED_DWORD_256K pcbBytesNeeded,
1960 LPBOUNDED_DWORD_256K lpServicesReturned,
1961 LPBOUNDED_DWORD_256K lpResumeHandle)
1962 {
1963 PMANAGER_HANDLE hManager;
1964 PSERVICE lpService;
1965 DWORD dwError = ERROR_SUCCESS;
1966 PLIST_ENTRY ServiceEntry;
1967 PSERVICE CurrentService;
1968 DWORD dwState;
1969 DWORD dwRequiredSize;
1970 DWORD dwServiceCount;
1971 DWORD dwSize;
1972 DWORD dwLastResumeCount;
1973 LPENUM_SERVICE_STATUSW lpStatusPtr;
1974 LPWSTR lpStringPtr;
1975
1976 DPRINT("REnumServicesStatusW() called\n");
1977
1978 if (ScmShutdown)
1979 return ERROR_SHUTDOWN_IN_PROGRESS;
1980
1981 hManager = (PMANAGER_HANDLE)hSCManager;
1982 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1983 {
1984 DPRINT1("Invalid manager handle!\n");
1985 return ERROR_INVALID_HANDLE;
1986 }
1987
1988 /* Check access rights */
1989 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1990 SC_MANAGER_ENUMERATE_SERVICE))
1991 {
1992 DPRINT1("Insufficient access rights! 0x%lx\n",
1993 hManager->Handle.DesiredAccess);
1994 return ERROR_ACCESS_DENIED;
1995 }
1996
1997 *pcbBytesNeeded = 0;
1998 *lpServicesReturned = 0;
1999
2000 dwLastResumeCount = *lpResumeHandle;
2001
2002 /* FIXME: Lock the service list shared */
2003
2004 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2005 if (lpService == NULL)
2006 {
2007 dwError = ERROR_SUCCESS;
2008 goto Done;
2009 }
2010
2011 dwRequiredSize = 0;
2012 dwServiceCount = 0;
2013
2014 for (ServiceEntry = &lpService->ServiceListEntry;
2015 ServiceEntry != &ServiceListHead;
2016 ServiceEntry = ServiceEntry->Flink)
2017 {
2018 CurrentService = CONTAINING_RECORD(ServiceEntry,
2019 SERVICE,
2020 ServiceListEntry);
2021
2022 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2023 continue;
2024
2025 dwState = SERVICE_ACTIVE;
2026 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2027 dwState = SERVICE_INACTIVE;
2028
2029 if ((dwState & dwServiceState) == 0)
2030 continue;
2031
2032 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2033 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2034 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2035
2036 if (dwRequiredSize + dwSize <= dwBufSize)
2037 {
2038 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2039 dwRequiredSize += dwSize;
2040 dwServiceCount++;
2041 dwLastResumeCount = CurrentService->dwResumeCount;
2042 }
2043 else
2044 {
2045 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2046 break;
2047 }
2048
2049 }
2050
2051 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2052 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2053
2054 for (;
2055 ServiceEntry != &ServiceListHead;
2056 ServiceEntry = ServiceEntry->Flink)
2057 {
2058 CurrentService = CONTAINING_RECORD(ServiceEntry,
2059 SERVICE,
2060 ServiceListEntry);
2061
2062 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2063 continue;
2064
2065 dwState = SERVICE_ACTIVE;
2066 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2067 dwState = SERVICE_INACTIVE;
2068
2069 if ((dwState & dwServiceState) == 0)
2070 continue;
2071
2072 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2073 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2074 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2075
2076 dwError = ERROR_MORE_DATA;
2077 }
2078
2079 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2080
2081 *lpResumeHandle = dwLastResumeCount;
2082 *lpServicesReturned = dwServiceCount;
2083 *pcbBytesNeeded = dwRequiredSize;
2084
2085 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2086 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2087 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2088
2089 dwRequiredSize = 0;
2090 for (ServiceEntry = &lpService->ServiceListEntry;
2091 ServiceEntry != &ServiceListHead;
2092 ServiceEntry = ServiceEntry->Flink)
2093 {
2094 CurrentService = CONTAINING_RECORD(ServiceEntry,
2095 SERVICE,
2096 ServiceListEntry);
2097
2098 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2099 continue;
2100
2101 dwState = SERVICE_ACTIVE;
2102 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2103 dwState = SERVICE_INACTIVE;
2104
2105 if ((dwState & dwServiceState) == 0)
2106 continue;
2107
2108 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2109 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2110 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2111
2112 if (dwRequiredSize + dwSize <= dwBufSize)
2113 {
2114 /* Copy the service name */
2115 wcscpy(lpStringPtr,
2116 CurrentService->lpServiceName);
2117 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2118 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2119
2120 /* Copy the display name */
2121 wcscpy(lpStringPtr,
2122 CurrentService->lpDisplayName);
2123 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2124 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2125
2126 /* Copy the status information */
2127 memcpy(&lpStatusPtr->ServiceStatus,
2128 &CurrentService->Status,
2129 sizeof(SERVICE_STATUS));
2130
2131 lpStatusPtr++;
2132 dwRequiredSize += dwSize;
2133 }
2134 else
2135 {
2136 break;
2137 }
2138
2139 }
2140
2141 Done:;
2142 /* FIXME: Unlock the service list */
2143
2144 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2145
2146 return dwError;
2147 }
2148
2149
2150 /* Function 15 */
2151 DWORD ROpenSCManagerW(
2152 handle_t BindingHandle,
2153 LPWSTR lpMachineName,
2154 LPWSTR lpDatabaseName,
2155 DWORD dwDesiredAccess,
2156 LPSC_RPC_HANDLE lpScHandle)
2157 {
2158 DWORD dwError;
2159 SC_HANDLE hHandle;
2160
2161 DPRINT("ROpenSCManagerW() called\n");
2162 DPRINT("lpMachineName = %p\n", lpMachineName);
2163 DPRINT("lpMachineName: %S\n", lpMachineName);
2164 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2165 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2166 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2167
2168 if (ScmShutdown)
2169 return ERROR_SHUTDOWN_IN_PROGRESS;
2170
2171 if (!lpScHandle)
2172 return ERROR_INVALID_PARAMETER;
2173
2174 dwError = ScmCreateManagerHandle(lpDatabaseName,
2175 &hHandle);
2176 if (dwError != ERROR_SUCCESS)
2177 {
2178 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2179 return dwError;
2180 }
2181
2182 /* Check the desired access */
2183 dwError = ScmCheckAccess(hHandle,
2184 dwDesiredAccess | SC_MANAGER_CONNECT);
2185 if (dwError != ERROR_SUCCESS)
2186 {
2187 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2188 HeapFree(GetProcessHeap(), 0, hHandle);
2189 return dwError;
2190 }
2191
2192 *lpScHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
2193 DPRINT("*hScm = %p\n", *lpScHandle);
2194
2195 DPRINT("ROpenSCManagerW() done\n");
2196
2197 return ERROR_SUCCESS;
2198 }
2199
2200
2201 /* Function 16 */
2202 DWORD ROpenServiceW(
2203 handle_t BindingHandle,
2204 SC_RPC_HANDLE hSCManager,
2205 LPWSTR lpServiceName,
2206 DWORD dwDesiredAccess,
2207 LPSC_RPC_HANDLE lpServiceHandle)
2208 {
2209 PSERVICE lpService;
2210 PMANAGER_HANDLE hManager;
2211 SC_HANDLE hHandle;
2212 DWORD dwError;
2213
2214 DPRINT("ROpenServiceW() called\n");
2215 DPRINT("hSCManager = %p\n", hSCManager);
2216 DPRINT("lpServiceName = %p\n", lpServiceName);
2217 DPRINT("lpServiceName: %S\n", lpServiceName);
2218 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2219
2220 if (ScmShutdown)
2221 return ERROR_SHUTDOWN_IN_PROGRESS;
2222
2223 if (!lpServiceHandle)
2224 return ERROR_INVALID_PARAMETER;
2225
2226 if (!lpServiceName)
2227 return ERROR_INVALID_ADDRESS;
2228
2229 hManager = (PMANAGER_HANDLE)hSCManager;
2230 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2231 {
2232 DPRINT1("Invalid manager handle!\n");
2233 return ERROR_INVALID_HANDLE;
2234 }
2235
2236 /* FIXME: Lock the service list */
2237
2238 /* Get service database entry */
2239 lpService = ScmGetServiceEntryByName(lpServiceName);
2240 if (lpService == NULL)
2241 {
2242 DPRINT("Could not find a service!\n");
2243 return ERROR_SERVICE_DOES_NOT_EXIST;
2244 }
2245
2246 /* Create a service handle */
2247 dwError = ScmCreateServiceHandle(lpService,
2248 &hHandle);
2249 if (dwError != ERROR_SUCCESS)
2250 {
2251 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2252 return dwError;
2253 }
2254
2255 /* Check the desired access */
2256 dwError = ScmCheckAccess(hHandle,
2257 dwDesiredAccess);
2258 if (dwError != ERROR_SUCCESS)
2259 {
2260 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2261 HeapFree(GetProcessHeap(), 0, hHandle);
2262 return dwError;
2263 }
2264
2265 *lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
2266 DPRINT("*hService = %p\n", *lpServiceHandle);
2267
2268 DPRINT("ROpenServiceW() done\n");
2269
2270 return ERROR_SUCCESS;
2271 }
2272
2273
2274 /* Function 17 */
2275 DWORD RQueryServiceConfigW(
2276 handle_t BindingHandle,
2277 SC_RPC_HANDLE hService,
2278 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2279 DWORD cbBufSize,
2280 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2281 {
2282 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2283 DWORD dwError = ERROR_SUCCESS;
2284 PSERVICE_HANDLE hSvc;
2285 PSERVICE lpService = NULL;
2286 HKEY hServiceKey = NULL;
2287 LPWSTR lpImagePath = NULL;
2288 LPWSTR lpServiceStartName = NULL;
2289 DWORD dwRequiredSize;
2290 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2291 WCHAR lpEmptyString[] = {0,0};
2292 LPWSTR lpStr;
2293
2294 DPRINT("RQueryServiceConfigW() called\n");
2295
2296 if (ScmShutdown)
2297 return ERROR_SHUTDOWN_IN_PROGRESS;
2298
2299 hSvc = (PSERVICE_HANDLE)hService;
2300 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2301 {
2302 DPRINT1("Invalid handle tag!\n");
2303 return ERROR_INVALID_HANDLE;
2304 }
2305
2306 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2307 SERVICE_QUERY_CONFIG))
2308 {
2309 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2310 return ERROR_ACCESS_DENIED;
2311 }
2312
2313 lpService = hSvc->ServiceEntry;
2314 if (lpService == NULL)
2315 {
2316 DPRINT1("lpService == NULL!\n");
2317 return ERROR_INVALID_HANDLE;
2318 }
2319
2320 /* FIXME: Lock the service database shared */
2321
2322 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2323 KEY_READ,
2324 &hServiceKey);
2325 if (dwError != ERROR_SUCCESS)
2326 goto Done;
2327
2328 dwError = ScmReadString(hServiceKey,
2329 L"ImagePath",
2330 &lpImagePath);
2331 if (dwError != ERROR_SUCCESS)
2332 goto Done;
2333
2334 ScmReadString(hServiceKey,
2335 L"ObjectName",
2336 &lpServiceStartName);
2337
2338 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2339
2340 if (lpImagePath != NULL)
2341 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2342 else
2343 dwRequiredSize += 2 * sizeof(WCHAR);
2344
2345 if (lpService->lpGroup != NULL)
2346 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2347 else
2348 dwRequiredSize += 2 * sizeof(WCHAR);
2349
2350 /* FIXME: Add Dependencies length*/
2351
2352 if (lpServiceStartName != NULL)
2353 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2354 else
2355 dwRequiredSize += 2 * sizeof(WCHAR);
2356
2357 if (lpService->lpDisplayName != NULL)
2358 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2359 else
2360 dwRequiredSize += 2 * sizeof(WCHAR);
2361
2362 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2363 {
2364 dwError = ERROR_INSUFFICIENT_BUFFER;
2365 }
2366 else
2367 {
2368 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2369 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2370 lpConfig->dwStartType = lpService->dwStartType;
2371 lpConfig->dwErrorControl = lpService->dwErrorControl;
2372 lpConfig->dwTagId = lpService->dwTag;
2373
2374 lpStr = (LPWSTR)(lpConfig + 1);
2375
2376 if (lpImagePath != NULL)
2377 {
2378 wcscpy(lpStr, lpImagePath);
2379 }
2380 else
2381 {
2382 wcscpy(lpStr, lpEmptyString);
2383 }
2384
2385 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2386 lpStr += (wcslen(lpStr) + 1);
2387
2388 if (lpService->lpGroup != NULL)
2389 {
2390 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2391 }
2392 else
2393 {
2394 wcscpy(lpStr, lpEmptyString);
2395 }
2396
2397 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2398 lpStr += (wcslen(lpStr) + 1);
2399
2400 /* FIXME: Append Dependencies */
2401 wcscpy(lpStr, lpEmptyString);
2402
2403 lpStr += (wcslen(lpStr) + 1);
2404 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2405
2406 if (lpServiceStartName != NULL)
2407 {
2408 wcscpy(lpStr, lpServiceStartName);
2409 }
2410 else
2411 {
2412 wcscpy(lpStr, lpEmptyString);
2413 }
2414
2415 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2416 lpStr += (wcslen(lpStr) + 1);
2417
2418 if (lpService->lpDisplayName != NULL)
2419 {
2420 wcscpy(lpStr, lpService->lpDisplayName);
2421 }
2422 else
2423 {
2424 wcscpy(lpStr, lpEmptyString);
2425 }
2426
2427 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2428 }
2429
2430 if (pcbBytesNeeded != NULL)
2431 *pcbBytesNeeded = dwRequiredSize;
2432
2433 Done:;
2434 if (lpImagePath != NULL)
2435 HeapFree(GetProcessHeap(), 0, lpImagePath);
2436
2437 if (lpServiceStartName != NULL)
2438 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2439
2440 if (hServiceKey != NULL)
2441 RegCloseKey(hServiceKey);
2442
2443 /* FIXME: Unlock the service database */
2444
2445 DPRINT("RQueryServiceConfigW() done\n");
2446
2447 return dwError;
2448 }
2449
2450
2451 /* Function 18 */
2452 DWORD RQueryServiceLockStatusW(
2453 handle_t BindingHandle,
2454 SC_RPC_HANDLE hSCManager,
2455 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2456 DWORD cbBufSize,
2457 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2458 {
2459 UNIMPLEMENTED;
2460 return ERROR_CALL_NOT_IMPLEMENTED;
2461 }
2462
2463
2464 /* Function 19 */
2465 DWORD RStartServiceW(
2466 handle_t BindingHandle,
2467 SC_RPC_HANDLE hService,
2468 DWORD argc,
2469 LPSTRING_PTRSW argv)
2470 {
2471 DWORD dwError = ERROR_SUCCESS;
2472 PSERVICE_HANDLE hSvc;
2473 PSERVICE lpService = NULL;
2474
2475 DPRINT("RStartServiceW() called\n");
2476
2477 if (ScmShutdown)
2478 return ERROR_SHUTDOWN_IN_PROGRESS;
2479
2480 hSvc = (PSERVICE_HANDLE)hService;
2481 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2482 {
2483 DPRINT1("Invalid handle tag!\n");
2484 return ERROR_INVALID_HANDLE;
2485 }
2486
2487 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2488 SERVICE_START))
2489 {
2490 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2491 return ERROR_ACCESS_DENIED;
2492 }
2493
2494 lpService = hSvc->ServiceEntry;
2495 if (lpService == NULL)
2496 {
2497 DPRINT1("lpService == NULL!\n");
2498 return ERROR_INVALID_HANDLE;
2499 }
2500
2501 if (lpService->dwStartType == SERVICE_DISABLED)
2502 return ERROR_SERVICE_DISABLED;
2503
2504 if (lpService->bDeleted)
2505 return ERROR_SERVICE_MARKED_FOR_DELETE;
2506
2507 if (argv) {
2508 UNIMPLEMENTED;
2509 argv = NULL;
2510 }
2511
2512 /* Start the service */
2513 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2514
2515 return dwError;
2516 }
2517
2518
2519 /* Function 20 */
2520 DWORD RGetServiceDisplayNameW(
2521 handle_t BindingHandle,
2522 SC_RPC_HANDLE hSCManager,
2523 LPWSTR lpServiceName,
2524 LPWSTR lpDisplayName,
2525 DWORD *lpcchBuffer)
2526 {
2527 // PMANAGER_HANDLE hManager;
2528 PSERVICE lpService;
2529 DWORD dwLength;
2530 DWORD dwError;
2531
2532 DPRINT("RGetServiceDisplayNameW() called\n");
2533 DPRINT("hSCManager = %p\n", hSCManager);
2534 DPRINT("lpServiceName: %S\n", lpServiceName);
2535 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2536 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2537
2538 // hManager = (PMANAGER_HANDLE)hSCManager;
2539 // if (hManager->Handle.Tag != MANAGER_TAG)
2540 // {
2541 // DPRINT1("Invalid manager handle!\n");
2542 // return ERROR_INVALID_HANDLE;
2543 // }
2544
2545 /* Get service database entry */
2546 lpService = ScmGetServiceEntryByName(lpServiceName);
2547 if (lpService == NULL)
2548 {
2549 DPRINT1("Could not find a service!\n");
2550
2551 /* If the service could not be found and lpcchBuffer is 0, windows
2552 puts null in lpDisplayName and puts 1 in lpcchBuffer */
2553 if (*lpcchBuffer == 0)
2554 {
2555 *lpcchBuffer = 1;
2556 *lpDisplayName = '\0';
2557 }
2558
2559 return ERROR_SERVICE_DOES_NOT_EXIST;
2560 }
2561
2562 if (!lpService->lpDisplayName)
2563 {
2564 dwLength = wcslen(lpService->lpServiceName);
2565
2566 if (lpServiceName != NULL &&
2567 *lpcchBuffer > dwLength)
2568 {
2569 wcscpy(lpDisplayName, lpService->lpServiceName);
2570 }
2571 }
2572 else
2573 {
2574 dwLength = wcslen(lpService->lpDisplayName);
2575
2576 if (lpDisplayName != NULL &&
2577 *lpcchBuffer > dwLength)
2578 {
2579 wcscpy(lpDisplayName, lpService->lpDisplayName);
2580 }
2581 }
2582
2583 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2584
2585 *lpcchBuffer = dwLength;
2586
2587 return dwError;
2588 }
2589
2590
2591 /* Function 21 */
2592 DWORD RGetServiceKeyNameW(
2593 handle_t BindingHandle,
2594 SC_RPC_HANDLE hSCManager,
2595 LPWSTR lpDisplayName,
2596 LPWSTR lpServiceName,
2597 DWORD *lpcchBuffer)
2598 {
2599 // PMANAGER_HANDLE hManager;
2600 PSERVICE lpService;
2601 DWORD dwLength;
2602 DWORD dwError;
2603
2604 DPRINT("RGetServiceKeyNameW() called\n");
2605 DPRINT("hSCManager = %p\n", hSCManager);
2606 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2607 DPRINT("lpServiceName: %p\n", lpServiceName);
2608 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2609
2610 // hManager = (PMANAGER_HANDLE)hSCManager;
2611 // if (hManager->Handle.Tag != MANAGER_TAG)
2612 // {
2613 // DPRINT1("Invalid manager handle!\n");
2614 // return ERROR_INVALID_HANDLE;
2615 // }
2616
2617 /* Get service database entry */
2618 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2619 if (lpService == NULL)
2620 {
2621 DPRINT1("Could not find a service!\n");
2622
2623 /* If the service could not be found and lpcchBuffer is 0, windows
2624 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2625 if (*lpcchBuffer == 0)
2626 {
2627 *lpcchBuffer = 2;
2628 *lpServiceName = '\0';
2629 }
2630
2631 return ERROR_SERVICE_DOES_NOT_EXIST;
2632 }
2633
2634 dwLength = wcslen(lpService->lpServiceName);
2635
2636 if (lpServiceName != NULL &&
2637 *lpcchBuffer > dwLength)
2638 {
2639 wcscpy(lpServiceName, lpService->lpServiceName);
2640 *lpcchBuffer = dwLength;
2641 return ERROR_SUCCESS;
2642 }
2643
2644 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2645
2646 *lpcchBuffer = dwLength * 2;
2647
2648 return dwError;
2649 }
2650
2651
2652 /* Function 22 */
2653 DWORD RSetServiceBitsA(
2654 handle_t BindingHandle,
2655 SC_RPC_HANDLE hServiceStatus,
2656 DWORD dwServiceBits,
2657 int bSetBitsOn,
2658 int bUpdateImmediately,
2659 char *lpString)
2660 {
2661 UNIMPLEMENTED;
2662 return ERROR_CALL_NOT_IMPLEMENTED;
2663 }
2664
2665
2666 /* Function 23 */
2667 DWORD RChangeServiceConfigA(
2668 handle_t BindingHandle,
2669 SC_RPC_HANDLE hService,
2670 DWORD dwServiceType,
2671 DWORD dwStartType,
2672 DWORD dwErrorControl,
2673 LPSTR lpBinaryPathName,
2674 LPSTR lpLoadOrderGroup,
2675 LPDWORD lpdwTagId,
2676 LPSTR lpDependencies,
2677 DWORD dwDependSize,
2678 LPSTR lpServiceStartName,
2679 LPBYTE lpPassword,
2680 DWORD dwPwSize,
2681 LPSTR lpDisplayName)
2682 {
2683 DWORD dwError = ERROR_SUCCESS;
2684 PSERVICE_HANDLE hSvc;
2685 PSERVICE lpService = NULL;
2686 HKEY hServiceKey = NULL;
2687 LPWSTR lpDisplayNameW = NULL;
2688 // LPWSTR lpBinaryPathNameW = NULL;
2689 LPWSTR lpLoadOrderGroupW = NULL;
2690 LPWSTR lpDependenciesW = NULL;
2691 // LPWSTR lpPasswordW = NULL;
2692
2693 DPRINT("RChangeServiceConfigA() called\n");
2694 DPRINT("dwServiceType = %lu\n", dwServiceType);
2695 DPRINT("dwStartType = %lu\n", dwStartType);
2696 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2697 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2698 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2699 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2700
2701 if (ScmShutdown)
2702 return ERROR_SHUTDOWN_IN_PROGRESS;
2703
2704 hSvc = (PSERVICE_HANDLE)hService;
2705 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2706 {
2707 DPRINT1("Invalid handle tag!\n");
2708 return ERROR_INVALID_HANDLE;
2709 }
2710
2711 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2712 SERVICE_CHANGE_CONFIG))
2713 {
2714 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2715 return ERROR_ACCESS_DENIED;
2716 }
2717
2718 lpService = hSvc->ServiceEntry;
2719 if (lpService == NULL)
2720 {
2721 DPRINT1("lpService == NULL!\n");
2722 return ERROR_INVALID_HANDLE;
2723 }
2724
2725 /* FIXME: Lock database exclusively */
2726
2727 if (lpService->bDeleted)
2728 {
2729 /* FIXME: Unlock database */
2730 DPRINT1("The service has already been marked for delete!\n");
2731 return ERROR_SERVICE_MARKED_FOR_DELETE;
2732 }
2733
2734 /* Open the service key */
2735 dwError = ScmOpenServiceKey(lpService->szServiceName,
2736 KEY_SET_VALUE,
2737 &hServiceKey);
2738 if (dwError != ERROR_SUCCESS)
2739 goto done;
2740
2741 /* Write service data to the registry */
2742
2743 if (lpDisplayName != NULL && *lpDisplayName != 0)
2744 {
2745 /* Set the display name */
2746 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2747 0,
2748 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
2749 if (lpDisplayNameW == NULL)
2750 {
2751 dwError = ERROR_NOT_ENOUGH_MEMORY;
2752 goto done;
2753 }
2754
2755 MultiByteToWideChar(CP_ACP,
2756 0,
2757 lpDisplayName,
2758 -1,
2759 lpDisplayNameW,
2760 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2761
2762 RegSetValueExW(hServiceKey,
2763 L"DisplayName",
2764 0,
2765 REG_SZ,
2766 (LPBYTE)lpDisplayNameW,
2767 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2768
2769 /* Update lpService->lpDisplayName */
2770 if (lpService->lpDisplayName)
2771 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2772
2773 lpService->lpDisplayName = lpDisplayNameW;
2774 }
2775
2776 if (dwServiceType != SERVICE_NO_CHANGE)
2777 {
2778 /* Set the service type */
2779 dwError = RegSetValueExW(hServiceKey,
2780 L"Type",
2781 0,
2782 REG_DWORD,
2783 (LPBYTE)&dwServiceType,
2784 sizeof(DWORD));
2785 if (dwError != ERROR_SUCCESS)
2786 goto done;
2787
2788 lpService->Status.dwServiceType = dwServiceType;
2789 }
2790
2791 if (dwStartType != SERVICE_NO_CHANGE)
2792 {
2793 /* Set the start value */
2794 dwError = RegSetValueExW(hServiceKey,
2795 L"Start",
2796 0,
2797 REG_DWORD,
2798 (LPBYTE)&dwStartType,
2799 sizeof(DWORD));
2800 if (dwError != ERROR_SUCCESS)
2801 goto done;
2802
2803 lpService->dwStartType = dwStartType;
2804 }
2805
2806 if (dwErrorControl != SERVICE_NO_CHANGE)
2807 {
2808 /* Set the error control value */
2809 dwError = RegSetValueExW(hServiceKey,
2810 L"ErrorControl",
2811 0,
2812 REG_DWORD,
2813 (LPBYTE)&dwErrorControl,
2814 sizeof(DWORD));
2815 if (dwError != ERROR_SUCCESS)
2816 goto done;
2817
2818 lpService->dwErrorControl = dwErrorControl;
2819 }
2820
2821 #if 0
2822 /* FIXME: set the new ImagePath value */
2823
2824 /* Set the image path */
2825 if (dwServiceType & SERVICE_WIN32)
2826 {
2827 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2828 {
2829 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
2830 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, (wcslen(lpBinaryPathNameW)+1) * sizeof(WCHAR));
2831 dwError = RegSetValueExW(hServiceKey,
2832 L"ImagePath",
2833 0,
2834 REG_EXPAND_SZ,
2835 (LPBYTE)lpBinaryPathNameW,
2836 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
2837 if (dwError != ERROR_SUCCESS)
2838 goto done;
2839 }
2840 }
2841 else if (dwServiceType & SERVICE_DRIVER)
2842 {
2843 if (lpImagePath != NULL && *lpImagePath != 0)
2844 {
2845 dwError = RegSetValueExW(hServiceKey,
2846 L"ImagePath",
2847 0,
2848 REG_EXPAND_SZ,
2849 (LPBYTE)lpImagePath,
2850 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
2851 if (dwError != ERROR_SUCCESS)
2852 goto done;
2853 }
2854 }
2855 #endif
2856
2857 /* Set the group name */
2858 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2859 {
2860 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
2861 0,
2862 (strlen(lpLoadOrderGroup)+1) * sizeof(WCHAR));
2863 if (lpLoadOrderGroupW == NULL)
2864 {
2865 dwError = ERROR_NOT_ENOUGH_MEMORY;
2866 goto done;
2867 }
2868
2869 MultiByteToWideChar(CP_ACP,
2870 0,
2871 lpLoadOrderGroup,
2872 -1,
2873 lpLoadOrderGroupW,
2874 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
2875
2876 dwError = RegSetValueExW(hServiceKey,
2877 L"Group",
2878 0,
2879 REG_SZ,
2880 (LPBYTE)lpLoadOrderGroupW,
2881 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
2882 if (dwError != ERROR_SUCCESS)
2883 goto done;
2884
2885 /* FIXME: Update lpService->lpServiceGroup */
2886
2887 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
2888 }
2889
2890 if (lpdwTagId != NULL)
2891 {
2892 dwError = ScmAssignNewTag(lpService);
2893 if (dwError != ERROR_SUCCESS)
2894 goto done;
2895
2896 dwError = RegSetValueExW(hServiceKey,
2897 L"Tag",
2898 0,
2899 REG_DWORD,
2900 (LPBYTE)&lpService->dwTag,
2901 sizeof(DWORD));
2902 if (dwError != ERROR_SUCCESS)
2903 goto done;
2904
2905 *lpdwTagId = lpService->dwTag;
2906 }
2907
2908 /* Write dependencies */
2909 if (lpDependencies != NULL && *lpDependencies != 0)
2910 {
2911 lpDependenciesW = HeapAlloc(GetProcessHeap(),
2912 0,
2913 (strlen(lpDependencies)+1) * sizeof(WCHAR));
2914 if (lpDependenciesW == NULL)
2915 {
2916 dwError = ERROR_NOT_ENOUGH_MEMORY;
2917 goto done;
2918 }
2919
2920 MultiByteToWideChar(CP_ACP,
2921 0,
2922 lpDependencies,
2923 dwDependSize,
2924 lpDependenciesW,
2925 (wcslen(lpDependenciesW)+1) * sizeof(WCHAR));
2926
2927 dwError = ScmWriteDependencies(hServiceKey,
2928 (LPWSTR)lpDependenciesW,
2929 dwDependSize);
2930
2931 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
2932 }
2933
2934 if (lpPassword != NULL)
2935 {
2936 /* FIXME: Write password */
2937 }
2938
2939 /* FIXME: Unlock database */
2940
2941 done:
2942 if (hServiceKey != NULL)
2943 RegCloseKey(hServiceKey);
2944
2945 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
2946
2947 return dwError;
2948 }
2949
2950
2951 /* Function 24 */
2952 DWORD RCreateServiceA(
2953 handle_t BindingHandle,
2954 SC_RPC_HANDLE hSCManager,
2955 LPSTR lpServiceName,
2956 LPSTR lpDisplayName,
2957 DWORD dwDesiredAccess,
2958 DWORD dwServiceType,
2959 DWORD dwStartType,
2960 DWORD dwErrorControl,
2961 LPSTR lpBinaryPathName,
2962 LPSTR lpLoadOrderGroup,
2963 LPDWORD lpdwTagId,
2964 LPBYTE lpDependencies,
2965 DWORD dwDependSize,
2966 LPSTR lpServiceStartName,
2967 LPBYTE lpPassword,
2968 DWORD dwPwSize,
2969 LPSC_RPC_HANDLE lpServiceHandle)
2970 {
2971 UNIMPLEMENTED;
2972 return ERROR_CALL_NOT_IMPLEMENTED;
2973 }
2974
2975
2976 /* Function 25 */
2977 DWORD REnumDependentServicesA(
2978 handle_t BindingHandle,
2979 SC_RPC_HANDLE hService,
2980 DWORD dwServiceState,
2981 LPBYTE lpServices,
2982 DWORD cbBufSize,
2983 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2984 LPBOUNDED_DWORD_256K lpServicesReturned)
2985 {
2986 DWORD dwError = ERROR_SUCCESS;
2987 DWORD dwServicesReturned = 0;
2988 DWORD dwServiceCount;
2989 HKEY hServicesKey = NULL;
2990 LPSC_RPC_HANDLE hSCObject;
2991 PSERVICE_HANDLE hSvc;
2992 PSERVICE lpService = NULL;
2993 PSERVICE *lpServicesArray = NULL;
2994 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
2995 LPSTR lpStr;
2996
2997 *pcbBytesNeeded = 0;
2998 *lpServicesReturned = 0;
2999
3000 DPRINT("REnumDependentServicesA() called\n");
3001
3002 hSCObject = &hService;
3003 hSvc = (PSERVICE_HANDLE) *hSCObject;
3004 lpService = hSvc->ServiceEntry;
3005
3006 /* Check access rights */
3007 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3008 SC_MANAGER_ENUMERATE_SERVICE))
3009 {
3010 DPRINT1("Insufficient access rights! 0x%lx\n",
3011 hSvc->Handle.DesiredAccess);
3012 return ERROR_ACCESS_DENIED;
3013 }
3014
3015 /* Open the Services Reg key */
3016 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3017 L"System\\CurrentControlSet\\Services",
3018 0,
3019 KEY_READ,
3020 &hServicesKey);
3021
3022 if (dwError != ERROR_SUCCESS) return dwError;
3023
3024 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3025 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3026 are the same for both. Verified in WINXP. */
3027
3028 /* First determine the bytes needed and get the number of dependent services*/
3029 dwError = Int_EnumDependentServicesW(hServicesKey,
3030 lpService,
3031 dwServiceState,
3032 NULL,
3033 pcbBytesNeeded,
3034 &dwServicesReturned);
3035 if (dwError != ERROR_SUCCESS)
3036 goto Done;
3037
3038 /* If buffer size is less than the bytes needed or pointer is null*/
3039 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3040 {
3041 dwError = ERROR_MORE_DATA;
3042 goto Done;
3043 }
3044
3045 /* Allocate memory for array of service pointers */
3046 lpServicesArray = HeapAlloc(GetProcessHeap(),
3047 0,
3048 (dwServicesReturned + 1) * sizeof(PSERVICE));
3049 if (!lpServicesArray)
3050 {
3051 DPRINT1("Could not allocate a buffer!!\n");
3052 dwError = ERROR_NOT_ENOUGH_MEMORY;
3053 goto Done;
3054 }
3055
3056 dwServicesReturned = 0;
3057 *pcbBytesNeeded = 0;
3058
3059 dwError = Int_EnumDependentServicesW(hServicesKey,
3060 lpService,
3061 dwServiceState,
3062 lpServicesArray,
3063 pcbBytesNeeded,
3064 &dwServicesReturned);
3065 if (dwError != ERROR_SUCCESS)
3066 {
3067 goto Done;
3068 }
3069
3070 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3071 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3072
3073 /* Copy EnumDepenedentService to Buffer */
3074 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3075 {
3076 lpService = lpServicesArray[dwServiceCount];
3077
3078 /* Copy the status info */
3079 memcpy(&lpServicesPtr->ServiceStatus,
3080 &lpService->Status,
3081 sizeof(SERVICE_STATUS));
3082
3083 /* Copy display name */
3084 WideCharToMultiByte(CP_ACP,
3085 0,
3086 lpService->lpDisplayName,
3087 -1,
3088 lpStr,
3089 wcslen(lpService->lpDisplayName),
3090 0,
3091 0);
3092 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3093 lpStr += strlen(lpStr) + 1;
3094
3095 /* Copy service name */
3096 WideCharToMultiByte(CP_ACP,
3097 0,
3098 lpService->lpServiceName,
3099 -1,
3100 lpStr,
3101 wcslen(lpService->lpServiceName),
3102 0,
3103 0);
3104 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3105 lpStr += strlen(lpStr) + 1;
3106
3107 lpServicesPtr ++;
3108 }
3109
3110 *lpServicesReturned = dwServicesReturned;
3111
3112 Done:
3113 if (lpServicesArray)
3114 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3115
3116 RegCloseKey(hServicesKey);
3117
3118 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3119
3120 return dwError;
3121 }
3122
3123
3124 /* Function 26 */
3125 DWORD REnumServicesStatusA(
3126 handle_t BindingHandle,
3127 SC_RPC_HANDLE hSCManager,
3128 DWORD dwServiceType,
3129 DWORD dwServiceState,
3130 LPBYTE lpBuffer,
3131 DWORD dwBufSize,
3132 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3133 LPBOUNDED_DWORD_256K lpServicesReturned,
3134 LPBOUNDED_DWORD_256K lpResumeHandle)
3135 {
3136 UNIMPLEMENTED;
3137 return ERROR_CALL_NOT_IMPLEMENTED;
3138 }
3139
3140
3141 /* Function 27 */
3142 DWORD ROpenSCManagerA(
3143 handle_t BindingHandle,
3144 LPSTR lpMachineName,
3145 LPSTR lpDatabaseName,
3146 DWORD dwDesiredAccess,
3147 LPSC_RPC_HANDLE lpScHandle)
3148 {
3149 UNICODE_STRING MachineName;
3150 UNICODE_STRING DatabaseName;
3151 DWORD dwError;
3152
3153 DPRINT("ROpenSCManagerA() called\n");
3154
3155 if (lpMachineName)
3156 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3157 lpMachineName);
3158
3159 if (lpDatabaseName)
3160 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3161 lpDatabaseName);
3162
3163 dwError = ROpenSCManagerW(BindingHandle,
3164 lpMachineName ? MachineName.Buffer : NULL,
3165 lpDatabaseName ? DatabaseName.Buffer : NULL,
3166 dwDesiredAccess,
3167 lpScHandle);
3168
3169 if (lpMachineName)
3170 RtlFreeUnicodeString(&MachineName);
3171
3172 if (lpDatabaseName)
3173 RtlFreeUnicodeString(&DatabaseName);
3174
3175 return dwError;
3176 }
3177
3178
3179 /* Function 28 */
3180 DWORD ROpenServiceA(
3181 handle_t BindingHandle,
3182 SC_RPC_HANDLE hSCManager,
3183 LPSTR lpServiceName,
3184 DWORD dwDesiredAccess,
3185 LPSC_RPC_HANDLE lpServiceHandle)
3186 {
3187 UNICODE_STRING ServiceName;
3188 DWORD dwError;
3189
3190 DPRINT("ROpenServiceA() called\n");
3191
3192 if (lpServiceName)
3193 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3194 lpServiceName);
3195
3196 dwError = ROpenServiceW(BindingHandle,
3197 hSCManager,
3198 ServiceName.Buffer,
3199 dwDesiredAccess,
3200 lpServiceHandle);
3201
3202 if (lpServiceName)
3203 RtlFreeUnicodeString(&ServiceName);
3204
3205 return dwError;
3206 }
3207
3208
3209 /* Function 29 */
3210 DWORD RQueryServiceConfigA(
3211 handle_t BindingHandle,
3212 SC_RPC_HANDLE hService,
3213 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3214 DWORD cbBufSize,
3215 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3216 {
3217 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3218 DWORD dwError = ERROR_SUCCESS;
3219 PSERVICE_HANDLE hSvc;
3220 PSERVICE lpService = NULL;
3221 HKEY hServiceKey = NULL;
3222 LPWSTR lpImagePath = NULL;
3223 LPWSTR lpServiceStartName = NULL;
3224 DWORD dwRequiredSize;
3225 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3226 CHAR lpEmptyString[]={0,0};
3227 LPSTR lpStr;
3228
3229 DPRINT("RQueryServiceConfigA() called\n");
3230
3231 if (ScmShutdown)
3232 return ERROR_SHUTDOWN_IN_PROGRESS;
3233
3234 hSvc = (PSERVICE_HANDLE)hService;
3235 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
3236 {
3237 DPRINT1("Invalid handle tag!\n");
3238 return ERROR_INVALID_HANDLE;
3239 }
3240
3241 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3242 SERVICE_QUERY_CONFIG))
3243 {
3244 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3245 return ERROR_ACCESS_DENIED;
3246 }
3247
3248 lpService = hSvc->ServiceEntry;
3249 if (lpService == NULL)
3250 {
3251 DPRINT1("lpService == NULL!\n");
3252 return ERROR_INVALID_HANDLE;
3253 }
3254
3255 /* FIXME: Lock the service database shared */
3256
3257 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3258 KEY_READ,
3259 &hServiceKey);
3260 if (dwError != ERROR_SUCCESS)
3261 goto Done;
3262
3263 dwError = ScmReadString(hServiceKey,
3264 L"ImagePath",
3265 &lpImagePath);
3266 if (dwError != ERROR_SUCCESS)
3267 goto Done;
3268
3269 ScmReadString(hServiceKey,
3270 L"ObjectName",
3271 &lpServiceStartName);
3272
3273 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3274
3275 if (lpImagePath != NULL)
3276 dwRequiredSize += wcslen(lpImagePath) + 1;
3277 else
3278 dwRequiredSize += 2;