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