- RCreateServiceW:
[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 if (wcslen(lpServiceName) == 0)
1603 {
1604 return ERROR_INVALID_NAME;
1605 }
1606
1607 if (wcslen(lpBinaryPathName) == 0)
1608 {
1609 return ERROR_INVALID_PARAMETER;
1610 }
1611
1612 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1613 (lpServiceStartName))
1614 {
1615 return ERROR_INVALID_PARAMETER;
1616 }
1617
1618 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
1619 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1620 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
1621 {
1622 return ERROR_INVALID_PARAMETER;
1623 }
1624
1625 if (dwStartType > SERVICE_DISABLED)
1626 {
1627 return ERROR_INVALID_PARAMETER;
1628 }
1629
1630 lpService = ScmGetServiceEntryByName(lpServiceName);
1631 if (lpService)
1632 {
1633 /* check if it is marked for deletion */
1634 if (lpService->bDeleted)
1635 return ERROR_SERVICE_MARKED_FOR_DELETE;
1636 /* Return Error exist */
1637 return ERROR_SERVICE_EXISTS;
1638 }
1639
1640 if (lpDisplayName != NULL &&
1641 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
1642 return ERROR_DUPLICATE_SERVICE_NAME;
1643
1644 if (dwServiceType & SERVICE_DRIVER)
1645 {
1646 dwError = ScmCanonDriverImagePath(dwStartType,
1647 lpBinaryPathName,
1648 &lpImagePath);
1649
1650 if (dwError != ERROR_SUCCESS)
1651 goto done;
1652 }
1653 else
1654 {
1655 if (dwStartType == SERVICE_BOOT_START ||
1656 dwStartType == SERVICE_SYSTEM_START)
1657 {
1658 return ERROR_INVALID_PARAMETER;
1659 }
1660 }
1661
1662 /* Allocate a new service entry */
1663 dwError = ScmCreateNewServiceRecord(lpServiceName,
1664 &lpService);
1665 if (dwError != ERROR_SUCCESS)
1666 goto done;
1667
1668 /* Fill the new service entry */
1669 lpService->Status.dwServiceType = dwServiceType;
1670 lpService->dwStartType = dwStartType;
1671 lpService->dwErrorControl = dwErrorControl;
1672
1673 /* Fill the display name */
1674 if (lpDisplayName != NULL &&
1675 *lpDisplayName != 0 &&
1676 wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1677 {
1678 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1679 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1680 if (lpService->lpDisplayName == NULL)
1681 {
1682 dwError = ERROR_NOT_ENOUGH_MEMORY;
1683 goto done;
1684 }
1685 wcscpy(lpService->lpDisplayName, lpDisplayName);
1686 }
1687
1688 /* Assign the service to a group */
1689 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1690 {
1691 dwError = ScmSetServiceGroup(lpService,
1692 lpLoadOrderGroup);
1693 if (dwError != ERROR_SUCCESS)
1694 goto done;
1695 }
1696
1697 /* Assign a new tag */
1698 if (lpdwTagId != NULL)
1699 {
1700 dwError = ScmAssignNewTag(lpService);
1701 if (dwError != ERROR_SUCCESS)
1702 goto done;
1703 }
1704
1705 /* Write service data to the registry */
1706 /* Create the service key */
1707 dwError = ScmCreateServiceKey(lpServiceName,
1708 KEY_WRITE,
1709 &hServiceKey);
1710 if (dwError != ERROR_SUCCESS)
1711 goto done;
1712
1713 /* Set the display name */
1714 if (lpDisplayName != NULL && *lpDisplayName != 0)
1715 {
1716 RegSetValueExW(hServiceKey,
1717 L"DisplayName",
1718 0,
1719 REG_SZ,
1720 (LPBYTE)lpDisplayName,
1721 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1722 }
1723
1724 /* Set the service type */
1725 dwError = RegSetValueExW(hServiceKey,
1726 L"Type",
1727 0,
1728 REG_DWORD,
1729 (LPBYTE)&dwServiceType,
1730 sizeof(DWORD));
1731 if (dwError != ERROR_SUCCESS)
1732 goto done;
1733
1734 /* Set the start value */
1735 dwError = RegSetValueExW(hServiceKey,
1736 L"Start",
1737 0,
1738 REG_DWORD,
1739 (LPBYTE)&dwStartType,
1740 sizeof(DWORD));
1741 if (dwError != ERROR_SUCCESS)
1742 goto done;
1743
1744 /* Set the error control value */
1745 dwError = RegSetValueExW(hServiceKey,
1746 L"ErrorControl",
1747 0,
1748 REG_DWORD,
1749 (LPBYTE)&dwErrorControl,
1750 sizeof(DWORD));
1751 if (dwError != ERROR_SUCCESS)
1752 goto done;
1753
1754 /* Set the image path */
1755 if (dwServiceType & SERVICE_WIN32)
1756 {
1757 dwError = RegSetValueExW(hServiceKey,
1758 L"ImagePath",
1759 0,
1760 REG_EXPAND_SZ,
1761 (LPBYTE)lpBinaryPathName,
1762 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1763 if (dwError != ERROR_SUCCESS)
1764 goto done;
1765 }
1766 else if (dwServiceType & SERVICE_DRIVER)
1767 {
1768 dwError = RegSetValueExW(hServiceKey,
1769 L"ImagePath",
1770 0,
1771 REG_EXPAND_SZ,
1772 (LPBYTE)lpImagePath,
1773 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
1774 if (dwError != ERROR_SUCCESS)
1775 goto done;
1776 }
1777
1778 /* Set the group name */
1779 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1780 {
1781 dwError = RegSetValueExW(hServiceKey,
1782 L"Group",
1783 0,
1784 REG_SZ,
1785 (LPBYTE)lpLoadOrderGroup,
1786 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1787 if (dwError != ERROR_SUCCESS)
1788 goto done;
1789 }
1790
1791 if (lpdwTagId != NULL)
1792 {
1793 dwError = RegSetValueExW(hServiceKey,
1794 L"Tag",
1795 0,
1796 REG_DWORD,
1797 (LPBYTE)&lpService->dwTag,
1798 sizeof(DWORD));
1799 if (dwError != ERROR_SUCCESS)
1800 goto done;
1801 }
1802
1803 /* Write dependencies */
1804 if (lpDependencies != NULL && *lpDependencies != 0)
1805 {
1806 dwError = ScmWriteDependencies(hServiceKey,
1807 (LPWSTR)lpDependencies,
1808 dwDependSize);
1809 if (dwError != ERROR_SUCCESS)
1810 goto done;
1811 }
1812
1813 /* If a non driver and NULL for lpServiceName, write ObjectName as LocalSystem */
1814 if ((dwServiceType & SERVICE_WIN32) && (!lpServiceName))
1815 {
1816 dwError = RegSetValueExW(hServiceKey,
1817 L"ObjectName",
1818 0,
1819 REG_SZ,
1820 (LPBYTE)L"LocalSystem",
1821 24);
1822 if (dwError != ERROR_SUCCESS)
1823 goto done;
1824 }
1825
1826 if (lpPassword != NULL)
1827 {
1828 /* FIXME: Write password */
1829 }
1830
1831 dwError = ScmCreateServiceHandle(lpService,
1832 &hServiceHandle);
1833 if (dwError != ERROR_SUCCESS)
1834 goto done;
1835
1836 dwError = ScmCheckAccess(hServiceHandle,
1837 dwDesiredAccess);
1838 if (dwError != ERROR_SUCCESS)
1839 goto done;
1840
1841 done:;
1842 if (hServiceKey != NULL)
1843 RegCloseKey(hServiceKey);
1844
1845 if (dwError == ERROR_SUCCESS)
1846 {
1847 DPRINT("hService %p\n", hServiceHandle);
1848 *lpServiceHandle = (unsigned long)hServiceHandle; /* FIXME: 64 bit portability */
1849
1850 if (lpdwTagId != NULL)
1851 *lpdwTagId = lpService->dwTag;
1852 }
1853 else
1854 {
1855 /* Release the display name buffer */
1856 if (lpService->lpServiceName != NULL)
1857 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1858
1859 if (hServiceHandle)
1860 {
1861 /* Remove the service handle */
1862 HeapFree(GetProcessHeap(), 0, hServiceHandle);
1863 }
1864
1865 if (lpService != NULL)
1866 {
1867 /* FIXME: remove the service entry */
1868 }
1869 }
1870
1871 if (lpImagePath != NULL)
1872 HeapFree(GetProcessHeap(), 0, lpImagePath);
1873
1874 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
1875
1876 return dwError;
1877 }
1878
1879
1880 /* Function 13 */
1881 DWORD REnumDependentServicesW(
1882 handle_t BindingHandle,
1883 SC_RPC_HANDLE hService,
1884 DWORD dwServiceState,
1885 LPBYTE lpServices,
1886 DWORD cbBufSize,
1887 LPBOUNDED_DWORD_256K pcbBytesNeeded,
1888 LPBOUNDED_DWORD_256K lpServicesReturned)
1889 {
1890 DWORD dwError = ERROR_SUCCESS;
1891 DWORD dwServicesReturned = 0;
1892 DWORD dwServiceCount;
1893 HKEY hServicesKey = NULL;
1894 LPSC_RPC_HANDLE hSCObject;
1895 PSERVICE_HANDLE hSvc;
1896 PSERVICE lpService = NULL;
1897 PSERVICE *lpServicesArray = NULL;
1898 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
1899 LPWSTR lpStr;
1900
1901 *pcbBytesNeeded = 0;
1902 *lpServicesReturned = 0;
1903
1904 DPRINT("REnumDependentServicesW() called\n");
1905
1906 hSCObject = &hService;
1907 hSvc = (PSERVICE_HANDLE) *hSCObject;
1908 lpService = hSvc->ServiceEntry;
1909
1910 /* Check access rights */
1911 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1912 SC_MANAGER_ENUMERATE_SERVICE))
1913 {
1914 DPRINT1("Insufficient access rights! 0x%lx\n",
1915 hSvc->Handle.DesiredAccess);
1916 return ERROR_ACCESS_DENIED;
1917 }
1918
1919 /* Open the Services Reg key */
1920 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1921 L"System\\CurrentControlSet\\Services",
1922 0,
1923 KEY_READ,
1924 &hServicesKey);
1925 if (dwError != ERROR_SUCCESS)
1926 return dwError;
1927
1928 /* First determine the bytes needed and get the number of dependent services */
1929 dwError = Int_EnumDependentServicesW(hServicesKey,
1930 lpService,
1931 dwServiceState,
1932 NULL,
1933 pcbBytesNeeded,
1934 &dwServicesReturned);
1935 if (dwError != ERROR_SUCCESS)
1936 goto Done;
1937
1938 /* If buffer size is less than the bytes needed or pointer is null */
1939 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
1940 {
1941 dwError = ERROR_MORE_DATA;
1942 goto Done;
1943 }
1944
1945 /* Allocate memory for array of service pointers */
1946 lpServicesArray = HeapAlloc(GetProcessHeap(),
1947 0,
1948 (dwServicesReturned + 1) * sizeof(PSERVICE));
1949 if (!lpServicesArray)
1950 {
1951 DPRINT1("Could not allocate a buffer!!\n");
1952 dwError = ERROR_NOT_ENOUGH_MEMORY;
1953 goto Done;
1954 }
1955
1956 dwServicesReturned = 0;
1957 *pcbBytesNeeded = 0;
1958
1959 dwError = Int_EnumDependentServicesW(hServicesKey,
1960 lpService,
1961 dwServiceState,
1962 lpServicesArray,
1963 pcbBytesNeeded,
1964 &dwServicesReturned);
1965 if (dwError != ERROR_SUCCESS)
1966 {
1967 goto Done;
1968 }
1969
1970 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
1971 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
1972
1973 /* Copy EnumDepenedentService to Buffer */
1974 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
1975 {
1976 lpService = lpServicesArray[dwServiceCount];
1977
1978 /* Copy status info */
1979 memcpy(&lpServicesPtr->ServiceStatus,
1980 &lpService->Status,
1981 sizeof(SERVICE_STATUS));
1982
1983 /* Copy display name */
1984 wcscpy(lpStr, lpService->lpDisplayName);
1985 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
1986 lpStr += (wcslen(lpService->lpDisplayName) + 1);
1987
1988 /* Copy service name */
1989 wcscpy(lpStr, lpService->lpServiceName);
1990 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
1991 lpStr += (wcslen(lpService->lpServiceName) + 1);
1992
1993 lpServicesPtr ++;
1994 }
1995
1996 *lpServicesReturned = dwServicesReturned;
1997
1998 Done:
1999 if (lpServicesArray != NULL)
2000 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2001
2002 RegCloseKey(hServicesKey);
2003
2004 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2005
2006 return dwError;
2007 }
2008
2009
2010 /* Function 14 */
2011 DWORD REnumServicesStatusW(
2012 handle_t BindingHandle,
2013 SC_RPC_HANDLE hSCManager,
2014 DWORD dwServiceType,
2015 DWORD dwServiceState,
2016 LPBYTE lpBuffer,
2017 DWORD dwBufSize,
2018 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2019 LPBOUNDED_DWORD_256K lpServicesReturned,
2020 LPBOUNDED_DWORD_256K lpResumeHandle)
2021 {
2022 PMANAGER_HANDLE hManager;
2023 PSERVICE lpService;
2024 DWORD dwError = ERROR_SUCCESS;
2025 PLIST_ENTRY ServiceEntry;
2026 PSERVICE CurrentService;
2027 DWORD dwState;
2028 DWORD dwRequiredSize;
2029 DWORD dwServiceCount;
2030 DWORD dwSize;
2031 DWORD dwLastResumeCount;
2032 LPENUM_SERVICE_STATUSW lpStatusPtr;
2033 LPWSTR lpStringPtr;
2034
2035 DPRINT("REnumServicesStatusW() called\n");
2036
2037 if (ScmShutdown)
2038 return ERROR_SHUTDOWN_IN_PROGRESS;
2039
2040 hManager = (PMANAGER_HANDLE)hSCManager;
2041 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2042 {
2043 DPRINT1("Invalid manager handle!\n");
2044 return ERROR_INVALID_HANDLE;
2045 }
2046
2047 /* Check access rights */
2048 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2049 SC_MANAGER_ENUMERATE_SERVICE))
2050 {
2051 DPRINT1("Insufficient access rights! 0x%lx\n",
2052 hManager->Handle.DesiredAccess);
2053 return ERROR_ACCESS_DENIED;
2054 }
2055
2056 *pcbBytesNeeded = 0;
2057 *lpServicesReturned = 0;
2058
2059 dwLastResumeCount = *lpResumeHandle;
2060
2061 /* FIXME: Lock the service list shared */
2062
2063 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2064 if (lpService == NULL)
2065 {
2066 dwError = ERROR_SUCCESS;
2067 goto Done;
2068 }
2069
2070 dwRequiredSize = 0;
2071 dwServiceCount = 0;
2072
2073 for (ServiceEntry = &lpService->ServiceListEntry;
2074 ServiceEntry != &ServiceListHead;
2075 ServiceEntry = ServiceEntry->Flink)
2076 {
2077 CurrentService = CONTAINING_RECORD(ServiceEntry,
2078 SERVICE,
2079 ServiceListEntry);
2080
2081 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2082 continue;
2083
2084 dwState = SERVICE_ACTIVE;
2085 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2086 dwState = SERVICE_INACTIVE;
2087
2088 if ((dwState & dwServiceState) == 0)
2089 continue;
2090
2091 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2092 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2093 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2094
2095 if (dwRequiredSize + dwSize > dwBufSize)
2096 {
2097 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2098 break;
2099 }
2100
2101 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2102 dwRequiredSize += dwSize;
2103 dwServiceCount++;
2104 dwLastResumeCount = CurrentService->dwResumeCount;
2105 }
2106
2107 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2108 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2109
2110 for (;
2111 ServiceEntry != &ServiceListHead;
2112 ServiceEntry = ServiceEntry->Flink)
2113 {
2114 CurrentService = CONTAINING_RECORD(ServiceEntry,
2115 SERVICE,
2116 ServiceListEntry);
2117
2118 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2119 continue;
2120
2121 dwState = SERVICE_ACTIVE;
2122 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2123 dwState = SERVICE_INACTIVE;
2124
2125 if ((dwState & dwServiceState) == 0)
2126 continue;
2127
2128 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2129 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2130 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2131
2132 dwError = ERROR_MORE_DATA;
2133 }
2134
2135 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2136
2137 *lpResumeHandle = dwLastResumeCount;
2138 *lpServicesReturned = dwServiceCount;
2139 *pcbBytesNeeded = dwRequiredSize;
2140
2141 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2142 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2143 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2144
2145 dwRequiredSize = 0;
2146 for (ServiceEntry = &lpService->ServiceListEntry;
2147 ServiceEntry != &ServiceListHead;
2148 ServiceEntry = ServiceEntry->Flink)
2149 {
2150 CurrentService = CONTAINING_RECORD(ServiceEntry,
2151 SERVICE,
2152 ServiceListEntry);
2153
2154 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2155 continue;
2156
2157 dwState = SERVICE_ACTIVE;
2158 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2159 dwState = SERVICE_INACTIVE;
2160
2161 if ((dwState & dwServiceState) == 0)
2162 continue;
2163
2164 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2165 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2166 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2167
2168 if (dwRequiredSize + dwSize > dwBufSize)
2169 break;
2170
2171 /* Copy the service name */
2172 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2173 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2174 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2175
2176 /* Copy the display name */
2177 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2178 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2179 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2180
2181 /* Copy the status information */
2182 memcpy(&lpStatusPtr->ServiceStatus,
2183 &CurrentService->Status,
2184 sizeof(SERVICE_STATUS));
2185
2186 lpStatusPtr++;
2187 dwRequiredSize += dwSize;
2188 }
2189
2190 Done:;
2191 /* FIXME: Unlock the service list */
2192
2193 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2194
2195 return dwError;
2196 }
2197
2198
2199 /* Function 15 */
2200 DWORD ROpenSCManagerW(
2201 handle_t BindingHandle,
2202 LPWSTR lpMachineName,
2203 LPWSTR lpDatabaseName,
2204 DWORD dwDesiredAccess,
2205 LPSC_RPC_HANDLE lpScHandle)
2206 {
2207 DWORD dwError;
2208 SC_HANDLE hHandle;
2209
2210 DPRINT("ROpenSCManagerW() called\n");
2211 DPRINT("lpMachineName = %p\n", lpMachineName);
2212 DPRINT("lpMachineName: %S\n", lpMachineName);
2213 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2214 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2215 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2216
2217 if (ScmShutdown)
2218 return ERROR_SHUTDOWN_IN_PROGRESS;
2219
2220 if (!lpScHandle)
2221 return ERROR_INVALID_PARAMETER;
2222
2223 dwError = ScmCreateManagerHandle(lpDatabaseName,
2224 &hHandle);
2225 if (dwError != ERROR_SUCCESS)
2226 {
2227 DPRINT1("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2228 return dwError;
2229 }
2230
2231 /* Check the desired access */
2232 dwError = ScmCheckAccess(hHandle,
2233 dwDesiredAccess | SC_MANAGER_CONNECT);
2234 if (dwError != ERROR_SUCCESS)
2235 {
2236 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2237 HeapFree(GetProcessHeap(), 0, hHandle);
2238 return dwError;
2239 }
2240
2241 *lpScHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
2242 DPRINT("*hScm = %p\n", *lpScHandle);
2243
2244 DPRINT("ROpenSCManagerW() done\n");
2245
2246 return ERROR_SUCCESS;
2247 }
2248
2249
2250 /* Function 16 */
2251 DWORD ROpenServiceW(
2252 handle_t BindingHandle,
2253 SC_RPC_HANDLE hSCManager,
2254 LPWSTR lpServiceName,
2255 DWORD dwDesiredAccess,
2256 LPSC_RPC_HANDLE lpServiceHandle)
2257 {
2258 PSERVICE lpService;
2259 PMANAGER_HANDLE hManager;
2260 SC_HANDLE hHandle;
2261 DWORD dwError;
2262
2263 DPRINT("ROpenServiceW() called\n");
2264 DPRINT("hSCManager = %p\n", hSCManager);
2265 DPRINT("lpServiceName = %p\n", lpServiceName);
2266 DPRINT("lpServiceName: %S\n", lpServiceName);
2267 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2268
2269 if (ScmShutdown)
2270 return ERROR_SHUTDOWN_IN_PROGRESS;
2271
2272 if (!lpServiceHandle)
2273 return ERROR_INVALID_PARAMETER;
2274
2275 if (!lpServiceName)
2276 return ERROR_INVALID_ADDRESS;
2277
2278 hManager = (PMANAGER_HANDLE)hSCManager;
2279 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2280 {
2281 DPRINT1("Invalid manager handle!\n");
2282 return ERROR_INVALID_HANDLE;
2283 }
2284
2285 /* FIXME: Lock the service list */
2286
2287 /* Get service database entry */
2288 lpService = ScmGetServiceEntryByName(lpServiceName);
2289 if (lpService == NULL)
2290 {
2291 DPRINT("Could not find a service!\n");
2292 return ERROR_SERVICE_DOES_NOT_EXIST;
2293 }
2294
2295 /* Create a service handle */
2296 dwError = ScmCreateServiceHandle(lpService,
2297 &hHandle);
2298 if (dwError != ERROR_SUCCESS)
2299 {
2300 DPRINT1("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2301 return dwError;
2302 }
2303
2304 /* Check the desired access */
2305 dwError = ScmCheckAccess(hHandle,
2306 dwDesiredAccess);
2307 if (dwError != ERROR_SUCCESS)
2308 {
2309 DPRINT1("ScmCheckAccess() failed (Error %lu)\n", dwError);
2310 HeapFree(GetProcessHeap(), 0, hHandle);
2311 return dwError;
2312 }
2313
2314 *lpServiceHandle = (unsigned long)hHandle; /* FIXME: 64 bit portability */
2315 DPRINT("*hService = %p\n", *lpServiceHandle);
2316
2317 DPRINT("ROpenServiceW() done\n");
2318
2319 return ERROR_SUCCESS;
2320 }
2321
2322
2323 /* Function 17 */
2324 DWORD RQueryServiceConfigW(
2325 handle_t BindingHandle,
2326 SC_RPC_HANDLE hService,
2327 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2328 DWORD cbBufSize,
2329 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2330 {
2331 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2332 DWORD dwError = ERROR_SUCCESS;
2333 PSERVICE_HANDLE hSvc;
2334 PSERVICE lpService = NULL;
2335 HKEY hServiceKey = NULL;
2336 LPWSTR lpImagePath = NULL;
2337 LPWSTR lpServiceStartName = NULL;
2338 DWORD dwRequiredSize;
2339 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2340 WCHAR lpEmptyString[] = {0,0};
2341 LPWSTR lpStr;
2342
2343 DPRINT("RQueryServiceConfigW() called\n");
2344
2345 if (ScmShutdown)
2346 return ERROR_SHUTDOWN_IN_PROGRESS;
2347
2348 hSvc = (PSERVICE_HANDLE)hService;
2349 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2350 {
2351 DPRINT1("Invalid handle tag!\n");
2352 return ERROR_INVALID_HANDLE;
2353 }
2354
2355 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2356 SERVICE_QUERY_CONFIG))
2357 {
2358 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2359 return ERROR_ACCESS_DENIED;
2360 }
2361
2362 lpService = hSvc->ServiceEntry;
2363 if (lpService == NULL)
2364 {
2365 DPRINT1("lpService == NULL!\n");
2366 return ERROR_INVALID_HANDLE;
2367 }
2368
2369 /* FIXME: Lock the service database shared */
2370
2371 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2372 KEY_READ,
2373 &hServiceKey);
2374 if (dwError != ERROR_SUCCESS)
2375 goto Done;
2376
2377 dwError = ScmReadString(hServiceKey,
2378 L"ImagePath",
2379 &lpImagePath);
2380 if (dwError != ERROR_SUCCESS)
2381 goto Done;
2382
2383 ScmReadString(hServiceKey,
2384 L"ObjectName",
2385 &lpServiceStartName);
2386
2387 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2388
2389 if (lpImagePath != NULL)
2390 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2391 else
2392 dwRequiredSize += 2 * sizeof(WCHAR);
2393
2394 if (lpService->lpGroup != NULL)
2395 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2396 else
2397 dwRequiredSize += 2 * sizeof(WCHAR);
2398
2399 /* FIXME: Add Dependencies length*/
2400
2401 if (lpServiceStartName != NULL)
2402 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2403 else
2404 dwRequiredSize += 2 * sizeof(WCHAR);
2405
2406 if (lpService->lpDisplayName != NULL)
2407 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2408 else
2409 dwRequiredSize += 2 * sizeof(WCHAR);
2410
2411 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2412 {
2413 dwError = ERROR_INSUFFICIENT_BUFFER;
2414 }
2415 else
2416 {
2417 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2418 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2419 lpConfig->dwStartType = lpService->dwStartType;
2420 lpConfig->dwErrorControl = lpService->dwErrorControl;
2421 lpConfig->dwTagId = lpService->dwTag;
2422
2423 lpStr = (LPWSTR)(lpConfig + 1);
2424
2425 if (lpImagePath != NULL)
2426 {
2427 wcscpy(lpStr, lpImagePath);
2428 }
2429 else
2430 {
2431 wcscpy(lpStr, lpEmptyString);
2432 }
2433
2434 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2435 lpStr += (wcslen(lpStr) + 1);
2436
2437 if (lpService->lpGroup != NULL)
2438 {
2439 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2440 }
2441 else
2442 {
2443 wcscpy(lpStr, lpEmptyString);
2444 }
2445
2446 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2447 lpStr += (wcslen(lpStr) + 1);
2448
2449 /* FIXME: Append Dependencies */
2450 wcscpy(lpStr, lpEmptyString);
2451
2452 lpStr += (wcslen(lpStr) + 1);
2453 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2454
2455 if (lpServiceStartName != NULL)
2456 {
2457 wcscpy(lpStr, lpServiceStartName);
2458 }
2459 else
2460 {
2461 wcscpy(lpStr, lpEmptyString);
2462 }
2463
2464 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2465 lpStr += (wcslen(lpStr) + 1);
2466
2467 if (lpService->lpDisplayName != NULL)
2468 {
2469 wcscpy(lpStr, lpService->lpDisplayName);
2470 }
2471 else
2472 {
2473 wcscpy(lpStr, lpEmptyString);
2474 }
2475
2476 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2477 }
2478
2479 if (pcbBytesNeeded != NULL)
2480 *pcbBytesNeeded = dwRequiredSize;
2481
2482 Done:;
2483 if (lpImagePath != NULL)
2484 HeapFree(GetProcessHeap(), 0, lpImagePath);
2485
2486 if (lpServiceStartName != NULL)
2487 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2488
2489 if (hServiceKey != NULL)
2490 RegCloseKey(hServiceKey);
2491
2492 /* FIXME: Unlock the service database */
2493
2494 DPRINT("RQueryServiceConfigW() done\n");
2495
2496 return dwError;
2497 }
2498
2499
2500 /* Function 18 */
2501 DWORD RQueryServiceLockStatusW(
2502 handle_t BindingHandle,
2503 SC_RPC_HANDLE hSCManager,
2504 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2505 DWORD cbBufSize,
2506 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2507 {
2508 UNIMPLEMENTED;
2509 return ERROR_CALL_NOT_IMPLEMENTED;
2510 }
2511
2512
2513 /* Function 19 */
2514 DWORD RStartServiceW(
2515 handle_t BindingHandle,
2516 SC_RPC_HANDLE hService,
2517 DWORD argc,
2518 LPSTRING_PTRSW argv)
2519 {
2520 DWORD dwError = ERROR_SUCCESS;
2521 PSERVICE_HANDLE hSvc;
2522 PSERVICE lpService = NULL;
2523
2524 DPRINT("RStartServiceW() called\n");
2525
2526 if (ScmShutdown)
2527 return ERROR_SHUTDOWN_IN_PROGRESS;
2528
2529 hSvc = (PSERVICE_HANDLE)hService;
2530 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2531 {
2532 DPRINT1("Invalid handle tag!\n");
2533 return ERROR_INVALID_HANDLE;
2534 }
2535
2536 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2537 SERVICE_START))
2538 {
2539 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2540 return ERROR_ACCESS_DENIED;
2541 }
2542
2543 lpService = hSvc->ServiceEntry;
2544 if (lpService == NULL)
2545 {
2546 DPRINT1("lpService == NULL!\n");
2547 return ERROR_INVALID_HANDLE;
2548 }
2549
2550 if (lpService->dwStartType == SERVICE_DISABLED)
2551 return ERROR_SERVICE_DISABLED;
2552
2553 if (lpService->bDeleted)
2554 return ERROR_SERVICE_MARKED_FOR_DELETE;
2555
2556 if (argv) {
2557 UNIMPLEMENTED;
2558 argv = NULL;
2559 }
2560
2561 /* Start the service */
2562 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2563
2564 return dwError;
2565 }
2566
2567
2568 /* Function 20 */
2569 DWORD RGetServiceDisplayNameW(
2570 handle_t BindingHandle,
2571 SC_RPC_HANDLE hSCManager,
2572 LPWSTR lpServiceName,
2573 LPWSTR lpDisplayName,
2574 DWORD *lpcchBuffer)
2575 {
2576 // PMANAGER_HANDLE hManager;
2577 PSERVICE lpService;
2578 DWORD dwLength;
2579 DWORD dwError;
2580
2581 DPRINT("RGetServiceDisplayNameW() called\n");
2582 DPRINT("hSCManager = %p\n", hSCManager);
2583 DPRINT("lpServiceName: %S\n", lpServiceName);
2584 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2585 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2586
2587 // hManager = (PMANAGER_HANDLE)hSCManager;
2588 // if (hManager->Handle.Tag != MANAGER_TAG)
2589 // {
2590 // DPRINT1("Invalid manager handle!\n");
2591 // return ERROR_INVALID_HANDLE;
2592 // }
2593
2594 /* Get service database entry */
2595 lpService = ScmGetServiceEntryByName(lpServiceName);
2596 if (lpService == NULL)
2597 {
2598 DPRINT1("Could not find a service!\n");
2599
2600 /* If the service could not be found and lpcchBuffer is 0, windows
2601 puts null in lpDisplayName and puts 1 in lpcchBuffer */
2602 if (*lpcchBuffer == 0)
2603 {
2604 *lpcchBuffer = 1;
2605 *lpDisplayName = '\0';
2606 }
2607
2608 return ERROR_SERVICE_DOES_NOT_EXIST;
2609 }
2610
2611 if (!lpService->lpDisplayName)
2612 {
2613 dwLength = wcslen(lpService->lpServiceName);
2614
2615 if (lpServiceName != NULL &&
2616 *lpcchBuffer > dwLength)
2617 {
2618 wcscpy(lpDisplayName, lpService->lpServiceName);
2619 }
2620 }
2621 else
2622 {
2623 dwLength = wcslen(lpService->lpDisplayName);
2624
2625 if (lpDisplayName != NULL &&
2626 *lpcchBuffer > dwLength)
2627 {
2628 wcscpy(lpDisplayName, lpService->lpDisplayName);
2629 }
2630 }
2631
2632 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2633
2634 *lpcchBuffer = dwLength;
2635
2636 return dwError;
2637 }
2638
2639
2640 /* Function 21 */
2641 DWORD RGetServiceKeyNameW(
2642 handle_t BindingHandle,
2643 SC_RPC_HANDLE hSCManager,
2644 LPWSTR lpDisplayName,
2645 LPWSTR lpServiceName,
2646 DWORD *lpcchBuffer)
2647 {
2648 // PMANAGER_HANDLE hManager;
2649 PSERVICE lpService;
2650 DWORD dwLength;
2651 DWORD dwError;
2652
2653 DPRINT("RGetServiceKeyNameW() called\n");
2654 DPRINT("hSCManager = %p\n", hSCManager);
2655 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2656 DPRINT("lpServiceName: %p\n", lpServiceName);
2657 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2658
2659 // hManager = (PMANAGER_HANDLE)hSCManager;
2660 // if (hManager->Handle.Tag != MANAGER_TAG)
2661 // {
2662 // DPRINT1("Invalid manager handle!\n");
2663 // return ERROR_INVALID_HANDLE;
2664 // }
2665
2666 /* Get service database entry */
2667 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2668 if (lpService == NULL)
2669 {
2670 DPRINT1("Could not find a service!\n");
2671
2672 /* If the service could not be found and lpcchBuffer is 0, windows
2673 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2674 if (*lpcchBuffer == 0)
2675 {
2676 *lpcchBuffer = 2;
2677 *lpServiceName = '\0';
2678 }
2679
2680 return ERROR_SERVICE_DOES_NOT_EXIST;
2681 }
2682
2683 dwLength = wcslen(lpService->lpServiceName);
2684
2685 if (lpServiceName != NULL &&
2686 *lpcchBuffer > dwLength)
2687 {
2688 wcscpy(lpServiceName, lpService->lpServiceName);
2689 *lpcchBuffer = dwLength;
2690 return ERROR_SUCCESS;
2691 }
2692
2693 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2694
2695 *lpcchBuffer = dwLength * 2;
2696
2697 return dwError;
2698 }
2699
2700
2701 /* Function 22 */
2702 DWORD RSetServiceBitsA(
2703 handle_t BindingHandle,
2704 SC_RPC_HANDLE hServiceStatus,
2705 DWORD dwServiceBits,
2706 int bSetBitsOn,
2707 int bUpdateImmediately,
2708 char *lpString)
2709 {
2710 UNIMPLEMENTED;
2711 return ERROR_CALL_NOT_IMPLEMENTED;
2712 }
2713
2714
2715 /* Function 23 */
2716 DWORD RChangeServiceConfigA(
2717 handle_t BindingHandle,
2718 SC_RPC_HANDLE hService,
2719 DWORD dwServiceType,
2720 DWORD dwStartType,
2721 DWORD dwErrorControl,
2722 LPSTR lpBinaryPathName,
2723 LPSTR lpLoadOrderGroup,
2724 LPDWORD lpdwTagId,
2725 LPSTR lpDependencies,
2726 DWORD dwDependSize,
2727 LPSTR lpServiceStartName,
2728 LPBYTE lpPassword,
2729 DWORD dwPwSize,
2730 LPSTR lpDisplayName)
2731 {
2732 DWORD dwError = ERROR_SUCCESS;
2733 PSERVICE_HANDLE hSvc;
2734 PSERVICE lpService = NULL;
2735 HKEY hServiceKey = NULL;
2736 LPWSTR lpDisplayNameW = NULL;
2737 // LPWSTR lpBinaryPathNameW = NULL;
2738 LPWSTR lpLoadOrderGroupW = NULL;
2739 LPWSTR lpDependenciesW = NULL;
2740 // LPWSTR lpPasswordW = NULL;
2741
2742 DPRINT("RChangeServiceConfigA() called\n");
2743 DPRINT("dwServiceType = %lu\n", dwServiceType);
2744 DPRINT("dwStartType = %lu\n", dwStartType);
2745 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2746 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2747 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2748 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2749
2750 if (ScmShutdown)
2751 return ERROR_SHUTDOWN_IN_PROGRESS;
2752
2753 hSvc = (PSERVICE_HANDLE)hService;
2754 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2755 {
2756 DPRINT1("Invalid handle tag!\n");
2757 return ERROR_INVALID_HANDLE;
2758 }
2759
2760 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2761 SERVICE_CHANGE_CONFIG))
2762 {
2763 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2764 return ERROR_ACCESS_DENIED;
2765 }
2766
2767 lpService = hSvc->ServiceEntry;
2768 if (lpService == NULL)
2769 {
2770 DPRINT1("lpService == NULL!\n");
2771 return ERROR_INVALID_HANDLE;
2772 }
2773
2774 /* FIXME: Lock database exclusively */
2775
2776 if (lpService->bDeleted)
2777 {
2778 /* FIXME: Unlock database */
2779 DPRINT1("The service has already been marked for delete!\n");
2780 return ERROR_SERVICE_MARKED_FOR_DELETE;
2781 }
2782
2783 /* Open the service key */
2784 dwError = ScmOpenServiceKey(lpService->szServiceName,
2785 KEY_SET_VALUE,
2786 &hServiceKey);
2787 if (dwError != ERROR_SUCCESS)
2788 goto done;
2789
2790 /* Write service data to the registry */
2791
2792 if (lpDisplayName != NULL && *lpDisplayName != 0)
2793 {
2794 /* Set the display name */
2795 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2796 0,
2797 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
2798 if (lpDisplayNameW == NULL)
2799 {
2800 dwError = ERROR_NOT_ENOUGH_MEMORY;
2801 goto done;
2802 }
2803
2804 MultiByteToWideChar(CP_ACP,
2805 0,
2806 lpDisplayName,
2807 -1,
2808 lpDisplayNameW,
2809 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2810
2811 RegSetValueExW(hServiceKey,
2812 L"DisplayName",
2813 0,
2814 REG_SZ,
2815 (LPBYTE)lpDisplayNameW,
2816 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
2817
2818 /* Update lpService->lpDisplayName */
2819 if (lpService->lpDisplayName)
2820 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2821
2822 lpService->lpDisplayName = lpDisplayNameW;
2823 }
2824
2825 if (dwServiceType != SERVICE_NO_CHANGE)
2826 {
2827 /* Set the service type */
2828 dwError = RegSetValueExW(hServiceKey,
2829 L"Type",
2830 0,
2831 REG_DWORD,
2832 (LPBYTE)&dwServiceType,
2833 sizeof(DWORD));
2834 if (dwError != ERROR_SUCCESS)
2835 goto done;
2836
2837 lpService->Status.dwServiceType = dwServiceType;
2838 }
2839
2840 if (dwStartType != SERVICE_NO_CHANGE)
2841 {
2842 /* Set the start value */
2843 dwError = RegSetValueExW(hServiceKey,
2844 L"Start",
2845 0,
2846 REG_DWORD,
2847 (LPBYTE)&dwStartType,
2848 sizeof(DWORD));
2849 if (dwError != ERROR_SUCCESS)
2850 goto done;
2851
2852 lpService->dwStartType = dwStartType;
2853 }
2854
2855 if (dwErrorControl != SERVICE_NO_CHANGE)
2856 {
2857 /* Set the error control value */
2858 dwError = RegSetValueExW(hServiceKey,
2859 L"ErrorControl",
2860 0,
2861 REG_DWORD,
2862 (LPBYTE)&dwErrorControl,
2863 sizeof(DWORD));
2864 if (dwError != ERROR_SUCCESS)
2865 goto done;
2866
2867 lpService->dwErrorControl = dwErrorControl;
2868 }
2869
2870 #if 0
2871 /* FIXME: set the new ImagePath value */
2872
2873 /* Set the image path */
2874 if (dwServiceType & SERVICE_WIN32)
2875 {
2876 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2877 {
2878 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
2879 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, (wcslen(lpBinaryPathNameW)+1) * sizeof(WCHAR));
2880 dwError = RegSetValueExW(hServiceKey,
2881 L"ImagePath",
2882 0,
2883 REG_EXPAND_SZ,
2884 (LPBYTE)lpBinaryPathNameW,
2885 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
2886 if (dwError != ERROR_SUCCESS)
2887 goto done;
2888 }
2889 }
2890 else if (dwServiceType & SERVICE_DRIVER)
2891 {
2892 if (lpImagePath != NULL && *lpImagePath != 0)
2893 {
2894 dwError = RegSetValueExW(hServiceKey,
2895 L"ImagePath",
2896 0,
2897 REG_EXPAND_SZ,
2898 (LPBYTE)lpImagePath,
2899 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
2900 if (dwError != ERROR_SUCCESS)
2901 goto done;
2902 }
2903 }
2904 #endif
2905
2906 /* Set the group name */
2907 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2908 {
2909 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
2910 0,
2911 (strlen(lpLoadOrderGroup)+1) * sizeof(WCHAR));
2912 if (lpLoadOrderGroupW == NULL)
2913 {
2914 dwError = ERROR_NOT_ENOUGH_MEMORY;
2915 goto done;
2916 }
2917
2918 MultiByteToWideChar(CP_ACP,
2919 0,
2920 lpLoadOrderGroup,
2921 -1,
2922 lpLoadOrderGroupW,
2923 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
2924
2925 dwError = RegSetValueExW(hServiceKey,
2926 L"Group",
2927 0,
2928 REG_SZ,
2929 (LPBYTE)lpLoadOrderGroupW,
2930 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
2931 if (dwError != ERROR_SUCCESS)
2932 goto done;
2933
2934 /* FIXME: Update lpService->lpServiceGroup */
2935
2936 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
2937 }
2938
2939 if (lpdwTagId != NULL)
2940 {
2941 dwError = ScmAssignNewTag(lpService);
2942 if (dwError != ERROR_SUCCESS)
2943 goto done;
2944
2945 dwError = RegSetValueExW(hServiceKey,
2946 L"Tag",
2947 0,
2948 REG_DWORD,
2949 (LPBYTE)&lpService->dwTag,
2950 sizeof(DWORD));
2951 if (dwError != ERROR_SUCCESS)
2952 goto done;
2953
2954 *lpdwTagId = lpService->dwTag;
2955 }
2956
2957 /* Write dependencies */
2958 if (lpDependencies != NULL && *lpDependencies != 0)
2959 {
2960 lpDependenciesW = HeapAlloc(GetProcessHeap(),
2961 0,
2962 (strlen(lpDependencies)+1) * sizeof(WCHAR));
2963 if (lpDependenciesW == NULL)
2964 {
2965 dwError = ERROR_NOT_ENOUGH_MEMORY;
2966 goto done;
2967 }
2968
2969 MultiByteToWideChar(CP_ACP,
2970 0,
2971 lpDependencies,
2972 dwDependSize,
2973 lpDependenciesW,
2974 (wcslen(lpDependenciesW)+1) * sizeof(WCHAR));
2975
2976 dwError = ScmWriteDependencies(hServiceKey,
2977 (LPWSTR)lpDependenciesW,
2978 dwDependSize);
2979
2980 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
2981 }
2982
2983 if (lpPassword != NULL)
2984 {
2985 /* FIXME: Write password */
2986 }
2987
2988 /* FIXME: Unlock database */
2989
2990 done:
2991 if (hServiceKey != NULL)
2992 RegCloseKey(hServiceKey);
2993
2994 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
2995
2996 return dwError;
2997 }
2998
2999
3000 /* Function 24 */
3001 DWORD RCreateServiceA(
3002 handle_t BindingHandle,
3003 SC_RPC_HANDLE hSCManager,
3004 LPSTR lpServiceName,
3005 LPSTR lpDisplayName,
3006 DWORD dwDesiredAccess,
3007 DWORD dwServiceType,
3008 DWORD dwStartType,
3009 DWORD dwErrorControl,
3010 LPSTR lpBinaryPathName,
3011 LPSTR lpLoadOrderGroup,
3012 LPDWORD lpdwTagId,
3013 LPBYTE lpDependencies,
3014 DWORD dwDependSize,
3015 LPSTR lpServiceStartName,
3016 LPBYTE lpPassword,
3017 DWORD dwPwSize,
3018 LPSC_RPC_HANDLE lpServiceHandle)
3019 {
3020 UNIMPLEMENTED;
3021 return ERROR_CALL_NOT_IMPLEMENTED;
3022 }
3023
3024
3025 /* Function 25 */
3026 DWORD REnumDependentServicesA(
3027 handle_t BindingHandle,
3028 SC_RPC_HANDLE hService,
3029 DWORD dwServiceState,
3030 LPBYTE lpServices,
3031 DWORD cbBufSize,
3032 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3033 LPBOUNDED_DWORD_256K lpServicesReturned)
3034 {
3035 DWORD dwError = ERROR_SUCCESS;
3036 DWORD dwServicesReturned = 0;
3037 DWORD dwServiceCount;
3038 HKEY hServicesKey = NULL;
3039 LPSC_RPC_HANDLE hSCObject;
3040 PSERVICE_HANDLE hSvc;
3041 PSERVICE lpService = NULL;
3042 PSERVICE *lpServicesArray = NULL;
3043 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3044 LPSTR lpStr;
3045
3046 *pcbBytesNeeded = 0;
3047 *lpServicesReturned = 0;
3048
3049 DPRINT("REnumDependentServicesA() called\n");
3050
3051 hSCObject = &hService;
3052 hSvc = (PSERVICE_HANDLE) *hSCObject;
3053 lpService = hSvc->ServiceEntry;
3054
3055 /* Check access rights */
3056 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3057 SC_MANAGER_ENUMERATE_SERVICE))
3058 {
3059 DPRINT1("Insufficient access rights! 0x%lx\n",
3060 hSvc->Handle.DesiredAccess);
3061 return ERROR_ACCESS_DENIED;
3062 }
3063
3064 /* Open the Services Reg key */
3065 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3066 L"System\\CurrentControlSet\\Services",
3067 0,
3068 KEY_READ,
3069 &hServicesKey);
3070
3071 if (dwError != ERROR_SUCCESS) return dwError;
3072
3073 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3074 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3075 are the same for both. Verified in WINXP. */
3076
3077 /* First determine the bytes needed and get the number of dependent services*/
3078 dwError = Int_EnumDependentServicesW(hServicesKey,
3079 lpService,
3080 dwServiceState,
3081 NULL,
3082 pcbBytesNeeded,
3083 &dwServicesReturned);
3084 if (dwError != ERROR_SUCCESS)
3085 goto Done;
3086
3087 /* If buffer size is less than the bytes needed or pointer is null*/
3088 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3089 {
3090 dwError = ERROR_MORE_DATA;
3091 goto Done;
3092 }
3093
3094 /* Allocate memory for array of service pointers */
3095 lpServicesArray = HeapAlloc(GetProcessHeap(),
3096 0,
3097 (dwServicesReturned + 1) * sizeof(PSERVICE));
3098 if (!lpServicesArray)
3099 {
3100 DPRINT1("Could not allocate a buffer!!\n");
3101 dwError = ERROR_NOT_ENOUGH_MEMORY;
3102 goto Done;
3103 }
3104
3105 dwServicesReturned = 0;
3106 *pcbBytesNeeded = 0;
3107
3108 dwError = Int_EnumDependentServicesW(hServicesKey,
3109 lpService,
3110 dwServiceState,
3111 lpServicesArray,
3112 pcbBytesNeeded,
3113 &dwServicesReturned);
3114 if (dwError != ERROR_SUCCESS)
3115 {
3116 goto Done;
3117 }
3118
3119 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3120 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3121
3122 /* Copy EnumDepenedentService to Buffer */
3123 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3124 {
3125 lpService = lpServicesArray[dwServiceCount];
3126
3127 /* Copy the status info */
3128 memcpy(&lpServicesPtr->ServiceStatus,
3129 &lpService->Status,
3130 sizeof(SERVICE_STATUS));
3131
3132 /* Copy display name */
3133 WideCharToMultiByte(CP_ACP,
3134 0,
3135 lpService->lpDisplayName,
3136 -1,
3137 lpStr,
3138 wcslen(lpService->lpDisplayName),
3139 0,
3140 0);
3141 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3142 lpStr += strlen(lpStr) + 1;
3143
3144 /* Copy service name */
3145 WideCharToMultiByte(CP_ACP,
3146 0,
3147 lpService->lpServiceName,
3148 -1,
3149 lpStr,
3150 wcslen(lpService->lpServiceName),
3151 0,
3152 0);
3153 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3154 lpStr += strlen(lpStr) + 1;
3155
3156 lpServicesPtr ++;
3157 }
3158
3159 *lpServicesReturned = dwServicesReturned;
3160
3161 Done:
3162 if (lpServicesArray)
3163 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3164
3165 RegCloseKey(hServicesKey);
3166
3167 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3168
3169 return dwError;
3170 }
3171
3172
3173 /* Function 26 */
3174 DWORD REnumServicesStatusA(
3175 handle_t BindingHandle,
3176 SC_RPC_HANDLE hSCManager,
3177 DWORD dwServiceType,
3178 DWORD dwServiceState,
3179 LPBYTE lpBuffer,
3180 DWORD dwBufSize,
3181 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3182 LPBOUNDED_DWORD_256K lpServicesReturned,
3183 LPBOUNDED_DWORD_256K lpResumeHandle)
3184 {
3185 UNIMPLEMENTED;
3186 return ERROR_CALL_NOT_IMPLEMENTED;
3187 }
3188
3189
3190 /* Function 27 */
3191 DWORD ROpenSCManagerA(
3192 handle_t BindingHandle,
3193 LPSTR lpMachineName,
3194 LPSTR lpDatabaseName,
3195 DWORD dwDesiredAccess,
3196 LPSC_RPC_HANDLE lpScHandle)
3197 {
3198 UNICODE_STRING MachineName;
3199 UNICODE_STRING DatabaseName;
3200 DWORD dwError;
3201
3202 DPRINT("ROpenSCManagerA() called\n");
3203
3204 if (lpMachineName)
3205 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3206 lpMachineName);
3207
3208 if (lpDatabaseName)
3209 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3210 lpDatabaseName);
3211
3212 dwError = ROpenSCManagerW(BindingHandle,
3213 lpMachineName ? MachineName.Buffer : NULL,
3214 lpDatabaseName ? DatabaseName.Buffer : NULL,
3215 dwDesiredAccess,
3216 lpScHandle);
3217
3218 if (lpMachineName)
3219 RtlFreeUnicodeString(&MachineName);
3220
3221 if (lpDatabaseName)
3222 RtlFreeUnicodeString(&DatabaseName);
3223
3224 return dwError;
3225 }
3226
3227
3228 /* Function 28 */
3229 DWORD ROpenServiceA(
3230 handle_t BindingHandle,
3231 SC_RPC_HANDLE hSCManager,
3232 LPSTR lpServiceName,
3233 DWORD dwDesiredAccess,
3234 LPSC_RPC_HANDLE lpServiceHandle)
3235 {
3236 UNICODE_STRING ServiceName;
3237 DWORD dwError;
3238
3239 DPRINT("ROpenServiceA() called\n");
3240
3241 if (lpServiceName)
3242 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3243 lpServiceName);
3244
3245 dwError = ROpenServiceW(BindingHandle,
3246 hSCManager,
3247 ServiceName.Buffer,
3248 dwDesiredAccess,
3249 lpServiceHandle);
3250
3251 if (lpServiceName)
3252 RtlFreeUnicodeString(&ServiceName);
3253
3254 return dwError;
3255 }
3256
3257
3258 /* Function 29 */
3259 DWORD RQueryServiceConfigA(
3260 handle_t BindingHandle,
3261 SC_RPC_HANDLE hService,
3262 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3263 DWORD cbBufSize,
3264 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3265 {
3266 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3267 DWORD dwError = ERROR_SUCCESS;
3268 PSERVICE_HANDLE hSvc;
3269 PSERVICE lpService = NULL;
3270 HKEY hServiceKey = NULL;
3271 LPWSTR lpImagePath = NULL;
3272 LPWSTR lpServiceStartName = NULL;
3273 DWORD dwRequiredSize;
3274 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3275 CHAR lpEmptyString[]={0,0};