[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 DPRINT("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 DPRINT("RpcServerRegisterIf() failed (Status %lx)\n", Status);
131 return;
132 }
133
134 Status = RpcServerListen(1, 20, TRUE);
135 if (Status != RPC_S_OK)
136 {
137 DPRINT("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 lpServiceStatus);
642 }
643
644 if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
645 dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
646
647 if (dwError == ERROR_SUCCESS &&
648 dwControl == SERVICE_CONTROL_STOP &&
649 lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
650 {
651 lpService->ProcessId = 0; /* FIXME */
652 lpService->ThreadId = 0;
653 }
654
655 /* Return service status information */
656 RtlCopyMemory(lpServiceStatus,
657 &lpService->Status,
658 sizeof(SERVICE_STATUS));
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 /* Return service status information */
982 RtlCopyMemory(lpServiceStatus,
983 &lpService->Status,
984 sizeof(SERVICE_STATUS));
985
986 return ERROR_SUCCESS;
987 }
988
989
990 static BOOL
991 ScmIsValidServiceState(DWORD dwCurrentState)
992 {
993 switch (dwCurrentState)
994 {
995 case SERVICE_STOPPED:
996 case SERVICE_START_PENDING:
997 case SERVICE_STOP_PENDING:
998 case SERVICE_RUNNING:
999 case SERVICE_CONTINUE_PENDING:
1000 case SERVICE_PAUSE_PENDING:
1001 case SERVICE_PAUSED:
1002 return TRUE;
1003
1004 default:
1005 return FALSE;
1006 }
1007 }
1008
1009
1010 /* Function 7 */
1011 DWORD RSetServiceStatus(
1012 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1013 LPSERVICE_STATUS lpServiceStatus)
1014 {
1015 PSERVICE lpService;
1016
1017 DPRINT("RSetServiceStatus() called\n");
1018 DPRINT("hServiceStatus = %p\n", hServiceStatus);
1019 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1020 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1021 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1022 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1023 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1024 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1025 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1026
1027 if (hServiceStatus == 0)
1028 {
1029 DPRINT("hServiceStatus == NULL!\n");
1030 return ERROR_INVALID_HANDLE;
1031 }
1032
1033 lpService = ScmGetServiceEntryByClientHandle((HANDLE)hServiceStatus);
1034 if (lpService == NULL)
1035 {
1036 DPRINT("lpService == NULL!\n");
1037 return ERROR_INVALID_HANDLE;
1038 }
1039
1040 /* Check current state */
1041 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1042 {
1043 DPRINT("Invalid service state!\n");
1044 return ERROR_INVALID_DATA;
1045 }
1046
1047 /* Check service type */
1048 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1049 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1050 {
1051 DPRINT("Invalid service type!\n");
1052 return ERROR_INVALID_DATA;
1053 }
1054
1055 /* Check accepted controls */
1056 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1057 {
1058 DPRINT("Invalid controls accepted!\n");
1059 return ERROR_INVALID_DATA;
1060 }
1061
1062
1063 RtlCopyMemory(&lpService->Status,
1064 lpServiceStatus,
1065 sizeof(SERVICE_STATUS));
1066
1067 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1068 DPRINT("RSetServiceStatus() done\n");
1069
1070 return ERROR_SUCCESS;
1071 }
1072
1073
1074 /* Function 8 */
1075 DWORD RUnlockServiceDatabase(
1076 LPSC_RPC_LOCK Lock)
1077 {
1078 UNIMPLEMENTED;
1079 return ERROR_SUCCESS;
1080 }
1081
1082
1083 /* Function 9 */
1084 DWORD RNotifyBootConfigStatus(
1085 SVCCTL_HANDLEW lpMachineName,
1086 DWORD BootAcceptable)
1087 {
1088 UNIMPLEMENTED;
1089 return ERROR_CALL_NOT_IMPLEMENTED;
1090 }
1091
1092
1093 /* Function 10 */
1094 DWORD RI_ScSetServiceBitsW(
1095 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1096 DWORD dwServiceBits,
1097 int bSetBitsOn,
1098 int bUpdateImmediately,
1099 wchar_t *lpString)
1100 {
1101 UNIMPLEMENTED;
1102 return ERROR_CALL_NOT_IMPLEMENTED;
1103 }
1104
1105
1106 /* Function 11 */
1107 DWORD RChangeServiceConfigW(
1108 SC_RPC_HANDLE hService,
1109 DWORD dwServiceType,
1110 DWORD dwStartType,
1111 DWORD dwErrorControl,
1112 LPWSTR lpBinaryPathName,
1113 LPWSTR lpLoadOrderGroup,
1114 LPDWORD lpdwTagId,
1115 LPBYTE lpDependencies,
1116 DWORD dwDependSize,
1117 LPWSTR lpServiceStartName,
1118 LPBYTE lpPassword,
1119 DWORD dwPwSize,
1120 LPWSTR lpDisplayName)
1121 {
1122 DWORD dwError = ERROR_SUCCESS;
1123 PSERVICE_HANDLE hSvc;
1124 PSERVICE lpService = NULL;
1125 HKEY hServiceKey = NULL;
1126 LPWSTR lpDisplayNameW = NULL;
1127
1128 DPRINT("RChangeServiceConfigW() called\n");
1129 DPRINT("dwServiceType = %lu\n", dwServiceType);
1130 DPRINT("dwStartType = %lu\n", dwStartType);
1131 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1132 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1133 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1134 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1135
1136 if (ScmShutdown)
1137 return ERROR_SHUTDOWN_IN_PROGRESS;
1138
1139 hSvc = (PSERVICE_HANDLE)hService;
1140 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
1141 {
1142 DPRINT("Invalid handle tag!\n");
1143 return ERROR_INVALID_HANDLE;
1144 }
1145
1146 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1147 SERVICE_CHANGE_CONFIG))
1148 {
1149 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1150 return ERROR_ACCESS_DENIED;
1151 }
1152
1153 lpService = hSvc->ServiceEntry;
1154 if (lpService == NULL)
1155 {
1156 DPRINT("lpService == NULL!\n");
1157 return ERROR_INVALID_HANDLE;
1158 }
1159
1160 /* FIXME: Lock database exclusively */
1161
1162 if (lpService->bDeleted)
1163 {
1164 /* FIXME: Unlock database */
1165 DPRINT("The service has already been marked for delete!\n");
1166 return ERROR_SERVICE_MARKED_FOR_DELETE;
1167 }
1168
1169 /* Open the service key */
1170 dwError = ScmOpenServiceKey(lpService->szServiceName,
1171 KEY_SET_VALUE,
1172 &hServiceKey);
1173 if (dwError != ERROR_SUCCESS)
1174 goto done;
1175
1176 /* Write service data to the registry */
1177 /* Set the display name */
1178 if (lpDisplayName != NULL && *lpDisplayName != 0)
1179 {
1180 RegSetValueExW(hServiceKey,
1181 L"DisplayName",
1182 0,
1183 REG_SZ,
1184 (LPBYTE)lpDisplayName,
1185 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1186
1187 /* Update the display name */
1188 lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
1189 0,
1190 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1191 if (lpDisplayNameW == NULL)
1192 {
1193 dwError = ERROR_NOT_ENOUGH_MEMORY;
1194 goto done;
1195 }
1196
1197 if (lpService->lpDisplayName != lpService->lpServiceName)
1198 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1199
1200 lpService->lpDisplayName = lpDisplayNameW;
1201 }
1202
1203 if (dwServiceType != SERVICE_NO_CHANGE)
1204 {
1205 /* Set the service type */
1206 dwError = RegSetValueExW(hServiceKey,
1207 L"Type",
1208 0,
1209 REG_DWORD,
1210 (LPBYTE)&dwServiceType,
1211 sizeof(DWORD));
1212 if (dwError != ERROR_SUCCESS)
1213 goto done;
1214
1215 lpService->Status.dwServiceType = dwServiceType;
1216 }
1217
1218 if (dwStartType != SERVICE_NO_CHANGE)
1219 {
1220 /* Set the start value */
1221 dwError = RegSetValueExW(hServiceKey,
1222 L"Start",
1223 0,
1224 REG_DWORD,
1225 (LPBYTE)&dwStartType,
1226 sizeof(DWORD));
1227 if (dwError != ERROR_SUCCESS)
1228 goto done;
1229
1230 lpService->dwStartType = dwStartType;
1231 }
1232
1233 if (dwErrorControl != SERVICE_NO_CHANGE)
1234 {
1235 /* Set the error control value */
1236 dwError = RegSetValueExW(hServiceKey,
1237 L"ErrorControl",
1238 0,
1239 REG_DWORD,
1240 (LPBYTE)&dwErrorControl,
1241 sizeof(DWORD));
1242 if (dwError != ERROR_SUCCESS)
1243 goto done;
1244
1245 lpService->dwErrorControl = dwErrorControl;
1246 }
1247
1248 #if 0
1249 /* FIXME: set the new ImagePath value */
1250
1251 /* Set the image path */
1252 if (dwServiceType & SERVICE_WIN32)
1253 {
1254 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1255 {
1256 dwError = RegSetValueExW(hServiceKey,
1257 L"ImagePath",
1258 0,
1259 REG_EXPAND_SZ,
1260 (LPBYTE)lpBinaryPathName,
1261 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1262 if (dwError != ERROR_SUCCESS)
1263 goto done;
1264 }
1265 }
1266 else if (dwServiceType & SERVICE_DRIVER)
1267 {
1268 if (lpImagePath != NULL && *lpImagePath != 0)
1269 {
1270 dwError = RegSetValueExW(hServiceKey,
1271 L"ImagePath",
1272 0,
1273 REG_EXPAND_SZ,
1274 (LPBYTE)lpImagePath,
1275 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
1276 if (dwError != ERROR_SUCCESS)
1277 goto done;
1278 }
1279 }
1280 #endif
1281
1282 /* Set the group name */
1283 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1284 {
1285 dwError = RegSetValueExW(hServiceKey,
1286 L"Group",
1287 0,
1288 REG_SZ,
1289 (LPBYTE)lpLoadOrderGroup,
1290 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1291 if (dwError != ERROR_SUCCESS)
1292 goto done;
1293
1294 dwError = ScmSetServiceGroup(lpService,
1295 lpLoadOrderGroup);
1296 if (dwError != ERROR_SUCCESS)
1297 goto done;
1298 }
1299
1300 if (lpdwTagId != NULL)
1301 {
1302 dwError = ScmAssignNewTag(lpService);
1303 if (dwError != ERROR_SUCCESS)
1304 goto done;
1305
1306 dwError = RegSetValueExW(hServiceKey,
1307 L"Tag",
1308 0,
1309 REG_DWORD,
1310 (LPBYTE)&lpService->dwTag,
1311 sizeof(DWORD));
1312 if (dwError != ERROR_SUCCESS)
1313 goto done;
1314
1315 *lpdwTagId = lpService->dwTag;
1316 }
1317
1318 /* Write dependencies */
1319 if (lpDependencies != NULL && *lpDependencies != 0)
1320 {
1321 dwError = ScmWriteDependencies(hServiceKey,
1322 (LPWSTR)lpDependencies,
1323 dwDependSize);
1324 if (dwError != ERROR_SUCCESS)
1325 goto done;
1326 }
1327
1328 if (lpPassword != NULL)
1329 {
1330 /* FIXME: Write password */
1331 }
1332
1333 /* FIXME: Unlock database */
1334
1335 done:
1336 if (hServiceKey != NULL)
1337 RegCloseKey(hServiceKey);
1338
1339 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1340
1341 return dwError;
1342 }
1343
1344
1345 /* Create a path suitable for the bootloader out of the full path */
1346 DWORD
1347 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1348 {
1349 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1350 WCHAR Dest;
1351 WCHAR *Expanded;
1352 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1353 OBJECT_ATTRIBUTES ObjectAttributes;
1354 NTSTATUS Status;
1355 HANDLE SymbolicLinkHandle;
1356
1357 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1358
1359 ServiceNameLen = wcslen(CanonName);
1360
1361 /* First check, if it's already good */
1362 if (ServiceNameLen > 12 &&
1363 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1364 {
1365 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1366 if (*RelativeName == NULL)
1367 {
1368 DPRINT("Error allocating memory for boot driver name!\n");
1369 return ERROR_NOT_ENOUGH_MEMORY;
1370 }
1371
1372 /* Copy it */
1373 wcscpy(*RelativeName, CanonName);
1374
1375 DPRINT("Bootdriver name %S\n", *RelativeName);
1376 return ERROR_SUCCESS;
1377 }
1378
1379 /* If it has %SystemRoot% prefix, substitute it to \System*/
1380 if (ServiceNameLen > 13 &&
1381 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1382 {
1383 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1384 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1385
1386 if (*RelativeName == NULL)
1387 {
1388 DPRINT("Error allocating memory for boot driver name!\n");
1389 return ERROR_NOT_ENOUGH_MEMORY;
1390 }
1391
1392 /* Copy it */
1393 wcscpy(*RelativeName, L"\\SystemRoot\\");
1394 wcscat(*RelativeName, CanonName + 13);
1395
1396 DPRINT("Bootdriver name %S\n", *RelativeName);
1397 return ERROR_SUCCESS;
1398 }
1399
1400 /* Get buffer size needed for expanding env strings */
1401 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1402
1403 if (BufferSize <= 1)
1404 {
1405 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1406 return ERROR_INVALID_ENVIRONMENT;
1407 }
1408
1409 /* Allocate memory, since the size is known now */
1410 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1411 if (!Expanded)
1412 {
1413 DPRINT("Error allocating memory for boot driver name!\n");
1414 return ERROR_NOT_ENOUGH_MEMORY;
1415 }
1416
1417 /* Expand it */
1418 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1419 BufferSize)
1420 {
1421 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1422 LocalFree(Expanded);
1423 return ERROR_NOT_ENOUGH_MEMORY;
1424 }
1425
1426 /* Convert to NY-style path */
1427 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1428 {
1429 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1430 return ERROR_INVALID_ENVIRONMENT;
1431 }
1432
1433 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1434
1435 /* No need to keep the dos-path anymore */
1436 LocalFree(Expanded);
1437
1438 /* Copy it to the allocated place */
1439 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1440 if (!Expanded)
1441 {
1442 DPRINT("Error allocating memory for boot driver name!\n");
1443 return ERROR_NOT_ENOUGH_MEMORY;
1444 }
1445
1446 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1447 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1448 Expanded[ExpandedLen] = 0;
1449
1450 if (ServiceNameLen > ExpandedLen &&
1451 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
1452 {
1453 /* Only \SystemRoot\ is missing */
1454 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1455 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1456 if (*RelativeName == NULL)
1457 {
1458 DPRINT("Error allocating memory for boot driver name!\n");
1459 LocalFree(Expanded);
1460 return ERROR_NOT_ENOUGH_MEMORY;
1461 }
1462
1463 wcscpy(*RelativeName, L"\\SystemRoot\\");
1464 wcscat(*RelativeName, CanonName + ExpandedLen);
1465
1466 RtlFreeUnicodeString(&NtPathName);
1467 return ERROR_SUCCESS;
1468 }
1469
1470 /* The most complex case starts here */
1471 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1472 InitializeObjectAttributes(&ObjectAttributes,
1473 &SystemRoot,
1474 OBJ_CASE_INSENSITIVE,
1475 NULL,
1476 NULL);
1477
1478 /* Open this symlink */
1479 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1480
1481 if (NT_SUCCESS(Status))
1482 {
1483 LinkTarget.Length = 0;
1484 LinkTarget.MaximumLength = 0;
1485
1486 DPRINT("Opened symbolic link object\n");
1487
1488 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1489 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1490 {
1491 /* Check if required buffer size is sane */
1492 if (BufferSize > 0xFFFD)
1493 {
1494 DPRINT("Too large buffer required\n");
1495 *RelativeName = 0;
1496
1497 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1498 LocalFree(Expanded);
1499 return ERROR_NOT_ENOUGH_MEMORY;
1500 }
1501
1502 /* Alloc the string */
1503 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1504 if (!LinkTarget.Buffer)
1505 {
1506 DPRINT("Unable to alloc buffer\n");
1507 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1508 LocalFree(Expanded);
1509 return ERROR_NOT_ENOUGH_MEMORY;
1510 }
1511
1512 /* Do a real query now */
1513 LinkTarget.Length = BufferSize;
1514 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1515
1516 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1517 if (NT_SUCCESS(Status))
1518 {
1519 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1520
1521 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1522 if ((ServiceNameLen > ExpandedLen) &&
1523 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1524 {
1525 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1526 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1527
1528 if (*RelativeName == NULL)
1529 {
1530 DPRINT("Unable to alloc buffer\n");
1531 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1532 LocalFree(Expanded);
1533 RtlFreeUnicodeString(&NtPathName);
1534 return ERROR_NOT_ENOUGH_MEMORY;
1535 }
1536
1537 /* Copy it over, substituting the first part
1538 with SystemRoot */
1539 wcscpy(*RelativeName, L"\\SystemRoot\\");
1540 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1541
1542 /* Cleanup */
1543 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1544 LocalFree(Expanded);
1545 RtlFreeUnicodeString(&NtPathName);
1546
1547 /* Return success */
1548 return ERROR_SUCCESS;
1549 }
1550 else
1551 {
1552 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1553 LocalFree(Expanded);
1554 RtlFreeUnicodeString(&NtPathName);
1555 return ERROR_INVALID_PARAMETER;
1556 }
1557 }
1558 else
1559 {
1560 DPRINT("Error, Status = %08X\n", Status);
1561 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1562 LocalFree(Expanded);
1563 RtlFreeUnicodeString(&NtPathName);
1564 return ERROR_INVALID_PARAMETER;
1565 }
1566 }
1567 else
1568 {
1569 DPRINT("Error, Status = %08X\n", Status);
1570 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1571 LocalFree(Expanded);
1572 RtlFreeUnicodeString(&NtPathName);
1573 return ERROR_INVALID_PARAMETER;
1574 }
1575 }
1576 else
1577 {
1578 DPRINT("Error, Status = %08X\n", Status);
1579 LocalFree(Expanded);
1580 return ERROR_INVALID_PARAMETER;
1581 }
1582
1583 /* Failure */
1584 *RelativeName = NULL;
1585 return ERROR_INVALID_PARAMETER;
1586 }
1587
1588 DWORD
1589 ScmCanonDriverImagePath(DWORD dwStartType,
1590 const wchar_t *lpServiceName,
1591 wchar_t **lpCanonName)
1592 {
1593 DWORD ServiceNameLen, Result;
1594 UNICODE_STRING NtServiceName;
1595 WCHAR *RelativeName;
1596 const WCHAR *SourceName = lpServiceName;
1597
1598 /* Calculate the length of the service's name */
1599 ServiceNameLen = wcslen(lpServiceName);
1600
1601 /* 12 is wcslen(L"\\SystemRoot\\") */
1602 if (ServiceNameLen > 12 &&
1603 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1604 {
1605 /* SystemRoot prefix is already included */
1606
1607 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1608
1609 if (*lpCanonName == NULL)
1610 {
1611 DPRINT("Error allocating memory for canonized service name!\n");
1612 return ERROR_NOT_ENOUGH_MEMORY;
1613 }
1614
1615 /* If it's a boot-time driver, it must be systemroot relative */
1616 if (dwStartType == SERVICE_BOOT_START)
1617 SourceName += 12;
1618
1619 /* Copy it */
1620 wcscpy(*lpCanonName, SourceName);
1621
1622 DPRINT("Canonicalized name %S\n", *lpCanonName);
1623 return NO_ERROR;
1624 }
1625
1626 /* Check if it has %SystemRoot% (len=13) */
1627 if (ServiceNameLen > 13 &&
1628 !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1629 {
1630 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1631 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1632
1633 if (*lpCanonName == NULL)
1634 {
1635 DPRINT("Error allocating memory for canonized service name!\n");
1636 return ERROR_NOT_ENOUGH_MEMORY;
1637 }
1638
1639 /* If it's a boot-time driver, it must be systemroot relative */
1640 if (dwStartType == SERVICE_BOOT_START)
1641 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1642
1643 wcscat(*lpCanonName, lpServiceName + 13);
1644
1645 DPRINT("Canonicalized name %S\n", *lpCanonName);
1646 return NO_ERROR;
1647 }
1648
1649 /* Check if it's a relative path name */
1650 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1651 {
1652 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1653
1654 if (*lpCanonName == NULL)
1655 {
1656 DPRINT("Error allocating memory for canonized service name!\n");
1657 return ERROR_NOT_ENOUGH_MEMORY;
1658 }
1659
1660 /* Just copy it over without changing */
1661 wcscpy(*lpCanonName, lpServiceName);
1662
1663 return NO_ERROR;
1664 }
1665
1666 /* It seems to be a DOS path, convert it */
1667 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1668 {
1669 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
1670 return ERROR_INVALID_PARAMETER;
1671 }
1672
1673 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1674
1675 if (*lpCanonName == NULL)
1676 {
1677 DPRINT("Error allocating memory for canonized service name!\n");
1678 RtlFreeUnicodeString(&NtServiceName);
1679 return ERROR_NOT_ENOUGH_MEMORY;
1680 }
1681
1682 /* Copy the string */
1683 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1684
1685 /* The unicode string is not needed anymore */
1686 RtlFreeUnicodeString(&NtServiceName);
1687
1688 if (dwStartType != SERVICE_BOOT_START)
1689 {
1690 DPRINT("Canonicalized name %S\n", *lpCanonName);
1691 return NO_ERROR;
1692 }
1693
1694 /* The service is boot-started, so must be relative */
1695 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1696 if (Result)
1697 {
1698 /* There is a problem, free name and return */
1699 LocalFree(*lpCanonName);
1700 DPRINT("Error converting named!\n");
1701 return Result;
1702 }
1703
1704 ASSERT(RelativeName);
1705
1706 /* Copy that string */
1707 wcscpy(*lpCanonName, RelativeName + 12);
1708
1709 /* Free the allocated buffer */
1710 LocalFree(RelativeName);
1711
1712 DPRINT("Canonicalized name %S\n", *lpCanonName);
1713
1714 /* Success */
1715 return NO_ERROR;
1716 }
1717
1718
1719 /* Function 12 */
1720 DWORD RCreateServiceW(
1721 SC_RPC_HANDLE hSCManager,
1722 LPCWSTR lpServiceName,
1723 LPCWSTR lpDisplayName,
1724 DWORD dwDesiredAccess,
1725 DWORD dwServiceType,
1726 DWORD dwStartType,
1727 DWORD dwErrorControl,
1728 LPCWSTR lpBinaryPathName,
1729 LPCWSTR lpLoadOrderGroup,
1730 LPDWORD lpdwTagId,
1731 LPBYTE lpDependencies,
1732 DWORD dwDependSize,
1733 LPCWSTR lpServiceStartName,
1734 LPBYTE lpPassword,
1735 DWORD dwPwSize,
1736 LPSC_RPC_HANDLE lpServiceHandle)
1737 {
1738 PMANAGER_HANDLE hManager;
1739 DWORD dwError = ERROR_SUCCESS;
1740 PSERVICE lpService = NULL;
1741 SC_HANDLE hServiceHandle = NULL;
1742 LPWSTR lpImagePath = NULL;
1743 HKEY hServiceKey = NULL;
1744 LPWSTR lpObjectName;
1745
1746 DPRINT("RCreateServiceW() called\n");
1747 DPRINT("lpServiceName = %S\n", lpServiceName);
1748 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1749 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1750 DPRINT("dwServiceType = %lu\n", dwServiceType);
1751 DPRINT("dwStartType = %lu\n", dwStartType);
1752 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1753 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1754 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1755
1756 if (ScmShutdown)
1757 return ERROR_SHUTDOWN_IN_PROGRESS;
1758
1759 hManager = (PMANAGER_HANDLE)hSCManager;
1760 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
1761 {
1762 DPRINT("Invalid manager handle!\n");
1763 return ERROR_INVALID_HANDLE;
1764 }
1765
1766 /* Check access rights */
1767 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1768 SC_MANAGER_CREATE_SERVICE))
1769 {
1770 DPRINT("Insufficient access rights! 0x%lx\n",
1771 hManager->Handle.DesiredAccess);
1772 return ERROR_ACCESS_DENIED;
1773 }
1774
1775 if (wcslen(lpServiceName) == 0)
1776 {
1777 return ERROR_INVALID_NAME;
1778 }
1779
1780 if (wcslen(lpBinaryPathName) == 0)
1781 {
1782 return ERROR_INVALID_PARAMETER;
1783 }
1784
1785 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1786 (lpServiceStartName))
1787 {
1788 return ERROR_INVALID_PARAMETER;
1789 }
1790
1791 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
1792 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1793 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
1794 {
1795 return ERROR_INVALID_PARAMETER;
1796 }
1797
1798 if (dwStartType > SERVICE_DISABLED)
1799 {
1800 return ERROR_INVALID_PARAMETER;
1801 }
1802
1803 lpService = ScmGetServiceEntryByName(lpServiceName);
1804 if (lpService)
1805 {
1806 /* check if it is marked for deletion */
1807 if (lpService->bDeleted)
1808 return ERROR_SERVICE_MARKED_FOR_DELETE;
1809 /* Return Error exist */
1810 return ERROR_SERVICE_EXISTS;
1811 }
1812
1813 if (lpDisplayName != NULL &&
1814 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
1815 return ERROR_DUPLICATE_SERVICE_NAME;
1816
1817 if (dwServiceType & SERVICE_DRIVER)
1818 {
1819 dwError = ScmCanonDriverImagePath(dwStartType,
1820 lpBinaryPathName,
1821 &lpImagePath);
1822 if (dwError != ERROR_SUCCESS)
1823 goto done;
1824 }
1825 else
1826 {
1827 if (dwStartType == SERVICE_BOOT_START ||
1828 dwStartType == SERVICE_SYSTEM_START)
1829 {
1830 return ERROR_INVALID_PARAMETER;
1831 }
1832 }
1833
1834 /* Allocate a new service entry */
1835 dwError = ScmCreateNewServiceRecord(lpServiceName,
1836 &lpService);
1837 if (dwError != ERROR_SUCCESS)
1838 goto done;
1839
1840 /* Fill the new service entry */
1841 lpService->Status.dwServiceType = dwServiceType;
1842 lpService->dwStartType = dwStartType;
1843 lpService->dwErrorControl = dwErrorControl;
1844
1845 /* Fill the display name */
1846 if (lpDisplayName != NULL &&
1847 *lpDisplayName != 0 &&
1848 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1849 {
1850 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1851 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1852 if (lpService->lpDisplayName == NULL)
1853 {
1854 dwError = ERROR_NOT_ENOUGH_MEMORY;
1855 goto done;
1856 }
1857 wcscpy(lpService->lpDisplayName, lpDisplayName);
1858 }
1859
1860 /* Assign the service to a group */
1861 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1862 {
1863 dwError = ScmSetServiceGroup(lpService,
1864 lpLoadOrderGroup);
1865 if (dwError != ERROR_SUCCESS)
1866 goto done;
1867 }
1868
1869 /* Assign a new tag */
1870 if (lpdwTagId != NULL)
1871 {
1872 dwError = ScmAssignNewTag(lpService);
1873 if (dwError != ERROR_SUCCESS)
1874 goto done;
1875 }
1876
1877 /* Write service data to the registry */
1878 /* Create the service key */
1879 dwError = ScmCreateServiceKey(lpServiceName,
1880 KEY_WRITE,
1881 &hServiceKey);
1882 if (dwError != ERROR_SUCCESS)
1883 goto done;
1884
1885 /* Set the display name */
1886 if (lpDisplayName != NULL && *lpDisplayName != 0)
1887 {
1888 RegSetValueExW(hServiceKey,
1889 L"DisplayName",
1890 0,
1891 REG_SZ,
1892 (LPBYTE)lpDisplayName,
1893 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1894 }
1895
1896 /* Set the service type */
1897 dwError = RegSetValueExW(hServiceKey,
1898 L"Type",
1899 0,
1900 REG_DWORD,
1901 (LPBYTE)&dwServiceType,
1902 sizeof(DWORD));
1903 if (dwError != ERROR_SUCCESS)
1904 goto done;
1905
1906 /* Set the start value */
1907 dwError = RegSetValueExW(hServiceKey,
1908 L"Start",
1909 0,
1910 REG_DWORD,
1911 (LPBYTE)&dwStartType,
1912 sizeof(DWORD));
1913 if (dwError != ERROR_SUCCESS)
1914 goto done;
1915
1916 /* Set the error control value */
1917 dwError = RegSetValueExW(hServiceKey,
1918 L"ErrorControl",
1919 0,
1920 REG_DWORD,
1921 (LPBYTE)&dwErrorControl,
1922 sizeof(DWORD));
1923 if (dwError != ERROR_SUCCESS)
1924 goto done;
1925
1926 /* Set the image path */
1927 if (dwServiceType & SERVICE_WIN32)
1928 {
1929 dwError = RegSetValueExW(hServiceKey,
1930 L"ImagePath",
1931 0,
1932 REG_EXPAND_SZ,
1933 (LPBYTE)lpBinaryPathName,
1934 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1935 if (dwError != ERROR_SUCCESS)
1936 goto done;
1937 }
1938 else if (dwServiceType & SERVICE_DRIVER)
1939 {
1940 dwError = RegSetValueExW(hServiceKey,
1941 L"ImagePath",
1942 0,
1943 REG_EXPAND_SZ,
1944 (LPBYTE)lpImagePath,
1945 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
1946 if (dwError != ERROR_SUCCESS)
1947 goto done;
1948 }
1949
1950 /* Set the group name */
1951 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1952 {
1953 dwError = RegSetValueExW(hServiceKey,
1954 L"Group",
1955 0,
1956 REG_SZ,
1957 (LPBYTE)lpLoadOrderGroup,
1958 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1959 if (dwError != ERROR_SUCCESS)
1960 goto done;
1961 }
1962
1963 if (lpdwTagId != NULL)
1964 {
1965 dwError = RegSetValueExW(hServiceKey,
1966 L"Tag",
1967 0,
1968 REG_DWORD,
1969 (LPBYTE)&lpService->dwTag,
1970 sizeof(DWORD));
1971 if (dwError != ERROR_SUCCESS)
1972 goto done;
1973 }
1974
1975 /* Write dependencies */
1976 if (lpDependencies != NULL && *lpDependencies != 0)
1977 {
1978 dwError = ScmWriteDependencies(hServiceKey,
1979 (LPWSTR)lpDependencies,
1980 dwDependSize);
1981 if (dwError != ERROR_SUCCESS)
1982 goto done;
1983 }
1984
1985 /* Write service start name */
1986 if (dwServiceType & SERVICE_WIN32)
1987 {
1988 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
1989 dwError = RegSetValueExW(hServiceKey,
1990 L"ObjectName",
1991 0,
1992 REG_SZ,
1993 (LPBYTE)lpObjectName,
1994 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
1995 if (dwError != ERROR_SUCCESS)
1996 goto done;
1997 }
1998
1999 if (lpPassword != NULL)
2000 {
2001 /* FIXME: Write password */
2002 }
2003
2004 dwError = ScmCreateServiceHandle(lpService,
2005 &hServiceHandle);
2006 if (dwError != ERROR_SUCCESS)
2007 goto done;
2008
2009 dwError = ScmCheckAccess(hServiceHandle,
2010 dwDesiredAccess);
2011 if (dwError != ERROR_SUCCESS)
2012 goto done;
2013
2014 lpService->dwRefCount = 1;
2015 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2016
2017 done:;
2018 if (hServiceKey != NULL)
2019 RegCloseKey(hServiceKey);
2020
2021 if (dwError == ERROR_SUCCESS)
2022 {
2023 DPRINT("hService %p\n", hServiceHandle);
2024 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2025
2026 if (lpdwTagId != NULL)
2027 *lpdwTagId = lpService->dwTag;
2028 }
2029 else
2030 {
2031 /* Release the display name buffer */
2032 if (lpService->lpServiceName != NULL)
2033 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2034
2035 if (hServiceHandle)
2036 {
2037 /* Remove the service handle */
2038 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2039 }
2040
2041 if (lpService != NULL)
2042 {
2043 /* FIXME: remove the service entry */
2044 }
2045 }
2046
2047 if (lpImagePath != NULL)
2048 HeapFree(GetProcessHeap(), 0, lpImagePath);
2049
2050 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2051
2052 return dwError;
2053 }
2054
2055
2056 /* Function 13 */
2057 DWORD REnumDependentServicesW(
2058 SC_RPC_HANDLE hService,
2059 DWORD dwServiceState,
2060 LPBYTE lpServices,
2061 DWORD cbBufSize,
2062 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2063 LPBOUNDED_DWORD_256K lpServicesReturned)
2064 {
2065 DWORD dwError = ERROR_SUCCESS;
2066 DWORD dwServicesReturned = 0;
2067 DWORD dwServiceCount;
2068 HKEY hServicesKey = NULL;
2069 LPSC_RPC_HANDLE hSCObject;
2070 PSERVICE_HANDLE hSvc;
2071 PSERVICE lpService = NULL;
2072 PSERVICE *lpServicesArray = NULL;
2073 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2074 LPWSTR lpStr;
2075
2076 *pcbBytesNeeded = 0;
2077 *lpServicesReturned = 0;
2078
2079 DPRINT("REnumDependentServicesW() called\n");
2080
2081 hSCObject = &hService;
2082 hSvc = (PSERVICE_HANDLE) *hSCObject;
2083 lpService = hSvc->ServiceEntry;
2084
2085 /* Check access rights */
2086 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2087 SC_MANAGER_ENUMERATE_SERVICE))
2088 {
2089 DPRINT("Insufficient access rights! 0x%lx\n",
2090 hSvc->Handle.DesiredAccess);
2091 return ERROR_ACCESS_DENIED;
2092 }
2093
2094 /* Open the Services Reg key */
2095 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2096 L"System\\CurrentControlSet\\Services",
2097 0,
2098 KEY_READ,
2099 &hServicesKey);
2100 if (dwError != ERROR_SUCCESS)
2101 return dwError;
2102
2103 /* First determine the bytes needed and get the number of dependent services */
2104 dwError = Int_EnumDependentServicesW(hServicesKey,
2105 lpService,
2106 dwServiceState,
2107 NULL,
2108 pcbBytesNeeded,
2109 &dwServicesReturned);
2110 if (dwError != ERROR_SUCCESS)
2111 goto Done;
2112
2113 /* If buffer size is less than the bytes needed or pointer is null */
2114 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2115 {
2116 dwError = ERROR_MORE_DATA;
2117 goto Done;
2118 }
2119
2120 /* Allocate memory for array of service pointers */
2121 lpServicesArray = HeapAlloc(GetProcessHeap(),
2122 0,
2123 (dwServicesReturned + 1) * sizeof(PSERVICE));
2124 if (!lpServicesArray)
2125 {
2126 DPRINT("Could not allocate a buffer!!\n");
2127 dwError = ERROR_NOT_ENOUGH_MEMORY;
2128 goto Done;
2129 }
2130
2131 dwServicesReturned = 0;
2132 *pcbBytesNeeded = 0;
2133
2134 dwError = Int_EnumDependentServicesW(hServicesKey,
2135 lpService,
2136 dwServiceState,
2137 lpServicesArray,
2138 pcbBytesNeeded,
2139 &dwServicesReturned);
2140 if (dwError != ERROR_SUCCESS)
2141 {
2142 goto Done;
2143 }
2144
2145 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2146 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2147
2148 /* Copy EnumDepenedentService to Buffer */
2149 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2150 {
2151 lpService = lpServicesArray[dwServiceCount];
2152
2153 /* Copy status info */
2154 memcpy(&lpServicesPtr->ServiceStatus,
2155 &lpService->Status,
2156 sizeof(SERVICE_STATUS));
2157
2158 /* Copy display name */
2159 wcscpy(lpStr, lpService->lpDisplayName);
2160 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2161 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2162
2163 /* Copy service name */
2164 wcscpy(lpStr, lpService->lpServiceName);
2165 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2166 lpStr += (wcslen(lpService->lpServiceName) + 1);
2167
2168 lpServicesPtr ++;
2169 }
2170
2171 *lpServicesReturned = dwServicesReturned;
2172
2173 Done:
2174 if (lpServicesArray != NULL)
2175 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2176
2177 RegCloseKey(hServicesKey);
2178
2179 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2180
2181 return dwError;
2182 }
2183
2184
2185 /* Function 14 */
2186 DWORD REnumServicesStatusW(
2187 SC_RPC_HANDLE hSCManager,
2188 DWORD dwServiceType,
2189 DWORD dwServiceState,
2190 LPBYTE lpBuffer,
2191 DWORD dwBufSize,
2192 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2193 LPBOUNDED_DWORD_256K lpServicesReturned,
2194 LPBOUNDED_DWORD_256K lpResumeHandle)
2195 {
2196 PMANAGER_HANDLE hManager;
2197 PSERVICE lpService;
2198 DWORD dwError = ERROR_SUCCESS;
2199 PLIST_ENTRY ServiceEntry;
2200 PSERVICE CurrentService;
2201 DWORD dwState;
2202 DWORD dwRequiredSize;
2203 DWORD dwServiceCount;
2204 DWORD dwSize;
2205 DWORD dwLastResumeCount = 0;
2206 LPENUM_SERVICE_STATUSW lpStatusPtr;
2207 LPWSTR lpStringPtr;
2208
2209 DPRINT("REnumServicesStatusW() called\n");
2210
2211 if (ScmShutdown)
2212 return ERROR_SHUTDOWN_IN_PROGRESS;
2213
2214 hManager = (PMANAGER_HANDLE)hSCManager;
2215 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2216 {
2217 DPRINT("Invalid manager handle!\n");
2218 return ERROR_INVALID_HANDLE;
2219 }
2220
2221 *pcbBytesNeeded = 0;
2222 *lpServicesReturned = 0;
2223
2224 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2225 {
2226 DPRINT("Not a valid Service Type!\n");
2227 return ERROR_INVALID_PARAMETER;
2228 }
2229
2230 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2231 {
2232 DPRINT("Not a valid Service State!\n");
2233 return ERROR_INVALID_PARAMETER;
2234 }
2235
2236 /* Check access rights */
2237 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2238 SC_MANAGER_ENUMERATE_SERVICE))
2239 {
2240 DPRINT("Insufficient access rights! 0x%lx\n",
2241 hManager->Handle.DesiredAccess);
2242 return ERROR_ACCESS_DENIED;
2243 }
2244
2245 if (lpResumeHandle)
2246 dwLastResumeCount = *lpResumeHandle;
2247
2248 /* FIXME: Lock the service list shared */
2249
2250 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2251 if (lpService == NULL)
2252 {
2253 dwError = ERROR_SUCCESS;
2254 goto Done;
2255 }
2256
2257 dwRequiredSize = 0;
2258 dwServiceCount = 0;
2259
2260 for (ServiceEntry = &lpService->ServiceListEntry;
2261 ServiceEntry != &ServiceListHead;
2262 ServiceEntry = ServiceEntry->Flink)
2263 {
2264 CurrentService = CONTAINING_RECORD(ServiceEntry,
2265 SERVICE,
2266 ServiceListEntry);
2267
2268 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2269 continue;
2270
2271 dwState = SERVICE_ACTIVE;
2272 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2273 dwState = SERVICE_INACTIVE;
2274
2275 if ((dwState & dwServiceState) == 0)
2276 continue;
2277
2278 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2279 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2280 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2281
2282 if (dwRequiredSize + dwSize > dwBufSize)
2283 {
2284 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2285 break;
2286 }
2287
2288 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2289 dwRequiredSize += dwSize;
2290 dwServiceCount++;
2291 dwLastResumeCount = CurrentService->dwResumeCount;
2292 }
2293
2294 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2295 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2296
2297 for (;
2298 ServiceEntry != &ServiceListHead;
2299 ServiceEntry = ServiceEntry->Flink)
2300 {
2301 CurrentService = CONTAINING_RECORD(ServiceEntry,
2302 SERVICE,
2303 ServiceListEntry);
2304
2305 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2306 continue;
2307
2308 dwState = SERVICE_ACTIVE;
2309 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2310 dwState = SERVICE_INACTIVE;
2311
2312 if ((dwState & dwServiceState) == 0)
2313 continue;
2314
2315 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2316 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2317 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2318
2319 dwError = ERROR_MORE_DATA;
2320 }
2321
2322 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2323
2324 if (lpResumeHandle)
2325 *lpResumeHandle = dwLastResumeCount;
2326
2327 *lpServicesReturned = dwServiceCount;
2328 *pcbBytesNeeded = dwRequiredSize;
2329
2330 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2331 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2332 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2333
2334 dwRequiredSize = 0;
2335 for (ServiceEntry = &lpService->ServiceListEntry;
2336 ServiceEntry != &ServiceListHead;
2337 ServiceEntry = ServiceEntry->Flink)
2338 {
2339 CurrentService = CONTAINING_RECORD(ServiceEntry,
2340 SERVICE,
2341 ServiceListEntry);
2342
2343 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2344 continue;
2345
2346 dwState = SERVICE_ACTIVE;
2347 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2348 dwState = SERVICE_INACTIVE;
2349
2350 if ((dwState & dwServiceState) == 0)
2351 continue;
2352
2353 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2354 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2355 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2356
2357 if (dwRequiredSize + dwSize > dwBufSize)
2358 break;
2359
2360 /* Copy the service name */
2361 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2362 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2363 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2364
2365 /* Copy the display name */
2366 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2367 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2368 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2369
2370 /* Copy the status information */
2371 memcpy(&lpStatusPtr->ServiceStatus,
2372 &CurrentService->Status,
2373 sizeof(SERVICE_STATUS));
2374
2375 lpStatusPtr++;
2376 dwRequiredSize += dwSize;
2377 }
2378
2379 if (dwError == 0)
2380 {
2381 *pcbBytesNeeded = 0;
2382 if (lpResumeHandle) *lpResumeHandle = 0;
2383 }
2384
2385 Done:;
2386 /* FIXME: Unlock the service list */
2387
2388 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2389
2390 return dwError;
2391 }
2392
2393
2394 /* Function 15 */
2395 DWORD ROpenSCManagerW(
2396 LPWSTR lpMachineName,
2397 LPWSTR lpDatabaseName,
2398 DWORD dwDesiredAccess,
2399 LPSC_RPC_HANDLE lpScHandle)
2400 {
2401 DWORD dwError;
2402 SC_HANDLE hHandle;
2403
2404 DPRINT("ROpenSCManagerW() called\n");
2405 DPRINT("lpMachineName = %p\n", lpMachineName);
2406 DPRINT("lpMachineName: %S\n", lpMachineName);
2407 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2408 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2409 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2410
2411 if (ScmShutdown)
2412 return ERROR_SHUTDOWN_IN_PROGRESS;
2413
2414 if (!lpScHandle)
2415 return ERROR_INVALID_PARAMETER;
2416
2417 dwError = ScmCreateManagerHandle(lpDatabaseName,
2418 &hHandle);
2419 if (dwError != ERROR_SUCCESS)
2420 {
2421 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2422 return dwError;
2423 }
2424
2425 /* Check the desired access */
2426 dwError = ScmCheckAccess(hHandle,
2427 dwDesiredAccess | SC_MANAGER_CONNECT);
2428 if (dwError != ERROR_SUCCESS)
2429 {
2430 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2431 HeapFree(GetProcessHeap(), 0, hHandle);
2432 return dwError;
2433 }
2434
2435 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2436 DPRINT("*hScm = %p\n", *lpScHandle);
2437
2438 DPRINT("ROpenSCManagerW() done\n");
2439
2440 return ERROR_SUCCESS;
2441 }
2442
2443
2444 /* Function 16 */
2445 DWORD ROpenServiceW(
2446 SC_RPC_HANDLE hSCManager,
2447 LPWSTR lpServiceName,
2448 DWORD dwDesiredAccess,
2449 LPSC_RPC_HANDLE lpServiceHandle)
2450 {
2451 PSERVICE lpService;
2452 PMANAGER_HANDLE hManager;
2453 SC_HANDLE hHandle;
2454 DWORD dwError;
2455
2456 DPRINT("ROpenServiceW() called\n");
2457 DPRINT("hSCManager = %p\n", hSCManager);
2458 DPRINT("lpServiceName = %p\n", lpServiceName);
2459 DPRINT("lpServiceName: %S\n", lpServiceName);
2460 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2461
2462 if (ScmShutdown)
2463 return ERROR_SHUTDOWN_IN_PROGRESS;
2464
2465 hManager = (PMANAGER_HANDLE)hSCManager;
2466 if (!hManager || hManager->Handle.Tag != MANAGER_TAG)
2467 {
2468 DPRINT("Invalid manager handle!\n");
2469 return ERROR_INVALID_HANDLE;
2470 }
2471
2472 if (!lpServiceHandle)
2473 return ERROR_INVALID_PARAMETER;
2474
2475 if (!lpServiceName)
2476 return ERROR_INVALID_ADDRESS;
2477
2478 /* FIXME: Lock the service list */
2479
2480 /* Get service database entry */
2481 lpService = ScmGetServiceEntryByName(lpServiceName);
2482 if (lpService == NULL)
2483 {
2484 DPRINT("Could not find a service!\n");
2485 return ERROR_SERVICE_DOES_NOT_EXIST;
2486 }
2487
2488 /* Create a service handle */
2489 dwError = ScmCreateServiceHandle(lpService,
2490 &hHandle);
2491 if (dwError != ERROR_SUCCESS)
2492 {
2493 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2494 return dwError;
2495 }
2496
2497 /* Check the desired access */
2498 dwError = ScmCheckAccess(hHandle,
2499 dwDesiredAccess);
2500 if (dwError != ERROR_SUCCESS)
2501 {
2502 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2503 HeapFree(GetProcessHeap(), 0, hHandle);
2504 return dwError;
2505 }
2506
2507 lpService->dwRefCount++;
2508 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2509
2510 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2511 DPRINT("*hService = %p\n", *lpServiceHandle);
2512
2513 DPRINT("ROpenServiceW() done\n");
2514
2515 return ERROR_SUCCESS;
2516 }
2517
2518
2519 /* Function 17 */
2520 DWORD RQueryServiceConfigW(
2521 SC_RPC_HANDLE hService,
2522 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2523 DWORD cbBufSize,
2524 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2525 {
2526 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2527 DWORD dwError = ERROR_SUCCESS;
2528 PSERVICE_HANDLE hSvc;
2529 PSERVICE lpService = NULL;
2530 HKEY hServiceKey = NULL;
2531 LPWSTR lpImagePath = NULL;
2532 LPWSTR lpServiceStartName = NULL;
2533 LPWSTR lpDependencies = NULL;
2534 DWORD dwDependenciesLength = 0;
2535 DWORD dwRequiredSize;
2536 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2537 WCHAR lpEmptyString[] = {0,0};
2538 LPWSTR lpStr;
2539
2540 DPRINT("RQueryServiceConfigW() called\n");
2541
2542 if (ScmShutdown)
2543 return ERROR_SHUTDOWN_IN_PROGRESS;
2544
2545 hSvc = (PSERVICE_HANDLE)hService;
2546 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2547 {
2548 DPRINT("Invalid handle tag!\n");
2549 return ERROR_INVALID_HANDLE;
2550 }
2551
2552 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2553 SERVICE_QUERY_CONFIG))
2554 {
2555 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2556 return ERROR_ACCESS_DENIED;
2557 }
2558
2559 lpService = hSvc->ServiceEntry;
2560 if (lpService == NULL)
2561 {
2562 DPRINT("lpService == NULL!\n");
2563 return ERROR_INVALID_HANDLE;
2564 }
2565
2566 /* FIXME: Lock the service database shared */
2567
2568 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2569 KEY_READ,
2570 &hServiceKey);
2571 if (dwError != ERROR_SUCCESS)
2572 goto Done;
2573
2574 /* Read the image path */
2575 dwError = ScmReadString(hServiceKey,
2576 L"ImagePath",
2577 &lpImagePath);
2578 if (dwError != ERROR_SUCCESS)
2579 goto Done;
2580
2581 /* Read the service start name */
2582 ScmReadString(hServiceKey,
2583 L"ObjectName",
2584 &lpServiceStartName);
2585
2586 /* Read the dependencies */
2587 ScmReadDependencies(hServiceKey,
2588 &lpDependencies,
2589 &dwDependenciesLength);
2590
2591 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2592
2593 if (lpImagePath != NULL)
2594 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2595 else
2596 dwRequiredSize += 2 * sizeof(WCHAR);
2597
2598 if (lpService->lpGroup != NULL)
2599 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2600 else
2601 dwRequiredSize += 2 * sizeof(WCHAR);
2602
2603 if (lpDependencies != NULL)
2604 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2605 else
2606 dwRequiredSize += 2 * sizeof(WCHAR);
2607
2608 if (lpServiceStartName != NULL)
2609 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2610 else
2611 dwRequiredSize += 2 * sizeof(WCHAR);
2612
2613 if (lpService->lpDisplayName != NULL)
2614 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2615 else
2616 dwRequiredSize += 2 * sizeof(WCHAR);
2617
2618 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2619 {
2620 dwError = ERROR_INSUFFICIENT_BUFFER;
2621 }
2622 else
2623 {
2624 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2625 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2626 lpConfig->dwStartType = lpService->dwStartType;
2627 lpConfig->dwErrorControl = lpService->dwErrorControl;
2628 lpConfig->dwTagId = lpService->dwTag;
2629
2630 lpStr = (LPWSTR)(lpConfig + 1);
2631
2632 /* Append the image path */
2633 if (lpImagePath != NULL)
2634 {
2635 wcscpy(lpStr, lpImagePath);
2636 }
2637 else
2638 {
2639 wcscpy(lpStr, lpEmptyString);
2640 }
2641
2642 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2643 lpStr += (wcslen(lpStr) + 1);
2644
2645 /* Append the group name */
2646 if (lpService->lpGroup != NULL)
2647 {
2648 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2649 }
2650 else
2651 {
2652 wcscpy(lpStr, lpEmptyString);
2653 }
2654
2655 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2656 lpStr += (wcslen(lpStr) + 1);
2657
2658 /* Append Dependencies */
2659 if (lpDependencies != NULL)
2660 {
2661 memcpy(lpStr,
2662 lpDependencies,
2663 dwDependenciesLength * sizeof(WCHAR));
2664 }
2665 else
2666 {
2667 wcscpy(lpStr, lpEmptyString);
2668 }
2669
2670 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2671 if (lpDependencies != NULL)
2672 lpStr += dwDependenciesLength * sizeof(WCHAR);
2673 else
2674 lpStr += (wcslen(lpStr) + 1);
2675
2676 /* Append the service start name */
2677 if (lpServiceStartName != NULL)
2678 {
2679 wcscpy(lpStr, lpServiceStartName);
2680 }
2681 else
2682 {
2683 wcscpy(lpStr, lpEmptyString);
2684 }
2685
2686 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2687 lpStr += (wcslen(lpStr) + 1);
2688
2689 /* Append the display name */
2690 if (lpService->lpDisplayName != NULL)
2691 {
2692 wcscpy(lpStr, lpService->lpDisplayName);
2693 }
2694 else
2695 {
2696 wcscpy(lpStr, lpEmptyString);
2697 }
2698
2699 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2700 }
2701
2702 if (pcbBytesNeeded != NULL)
2703 *pcbBytesNeeded = dwRequiredSize;
2704
2705 Done:;
2706 if (lpImagePath != NULL)
2707 HeapFree(GetProcessHeap(), 0, lpImagePath);
2708
2709 if (lpServiceStartName != NULL)
2710 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2711
2712 if (lpDependencies != NULL)
2713 HeapFree(GetProcessHeap(), 0, lpDependencies);
2714
2715 if (hServiceKey != NULL)
2716 RegCloseKey(hServiceKey);
2717
2718 /* FIXME: Unlock the service database */
2719
2720 DPRINT("RQueryServiceConfigW() done\n");
2721
2722 return dwError;
2723 }
2724
2725
2726 /* Function 18 */
2727 DWORD RQueryServiceLockStatusW(
2728 SC_RPC_HANDLE hSCManager,
2729 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2730 DWORD cbBufSize,
2731 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2732 {
2733 UNIMPLEMENTED;
2734 return ERROR_CALL_NOT_IMPLEMENTED;
2735 }
2736
2737
2738 /* Function 19 */
2739 DWORD RStartServiceW(
2740 SC_RPC_HANDLE hService,
2741 DWORD argc,
2742 LPSTRING_PTRSW argv)
2743 {
2744 DWORD dwError = ERROR_SUCCESS;
2745 PSERVICE_HANDLE hSvc;
2746 PSERVICE lpService = NULL;
2747
2748 DPRINT("RStartServiceW() called\n");
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 DPRINT("Invalid handle tag!\n");
2757 return ERROR_INVALID_HANDLE;
2758 }
2759
2760 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2761 SERVICE_START))
2762 {
2763 DPRINT("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 DPRINT("lpService == NULL!\n");
2771 return ERROR_INVALID_HANDLE;
2772 }
2773
2774 if (lpService->dwStartType == SERVICE_DISABLED)
2775 return ERROR_SERVICE_DISABLED;
2776
2777 if (lpService->bDeleted)
2778 return ERROR_SERVICE_MARKED_FOR_DELETE;
2779
2780 if (argv) {
2781 UNIMPLEMENTED;
2782 argv = NULL;
2783 }
2784
2785 /* Start the service */
2786 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2787
2788 return dwError;
2789 }
2790
2791
2792 /* Function 20 */
2793 DWORD RGetServiceDisplayNameW(
2794 SC_RPC_HANDLE hSCManager,
2795 LPCWSTR lpServiceName,
2796 LPWSTR lpDisplayName,
2797 DWORD *lpcchBuffer)
2798 {
2799 // PMANAGER_HANDLE hManager;
2800 PSERVICE lpService;
2801 DWORD dwLength;
2802 DWORD dwError;
2803
2804 DPRINT("RGetServiceDisplayNameW() called\n");
2805 DPRINT("hSCManager = %p\n", hSCManager);
2806 DPRINT("lpServiceName: %S\n", lpServiceName);
2807 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2808 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2809
2810 // hManager = (PMANAGER_HANDLE)hSCManager;
2811 // if (hManager->Handle.Tag != MANAGER_TAG)
2812 // {
2813 // DPRINT("Invalid manager handle!\n");
2814 // return ERROR_INVALID_HANDLE;
2815 // }
2816
2817 /* Get service database entry */
2818 lpService = ScmGetServiceEntryByName(lpServiceName);
2819 if (lpService == NULL)
2820 {
2821 DPRINT("Could not find a service!\n");
2822
2823 /* If the service could not be found and lpcchBuffer is less than 2, windows
2824 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2825 if (*lpcchBuffer < 2)
2826 {
2827 *lpcchBuffer = 2;
2828 if (lpDisplayName != NULL)
2829 {
2830 *lpDisplayName = '\0';
2831 }
2832 }
2833
2834 return ERROR_SERVICE_DOES_NOT_EXIST;
2835 }
2836
2837 if (!lpService->lpDisplayName)
2838 {
2839 dwLength = wcslen(lpService->lpServiceName);
2840
2841 if (lpDisplayName != NULL &&
2842 *lpcchBuffer > dwLength)
2843 {
2844 wcscpy(lpDisplayName, lpService->lpServiceName);
2845 }
2846 }
2847 else
2848 {
2849 dwLength = wcslen(lpService->lpDisplayName);
2850
2851 if (lpDisplayName != NULL &&
2852 *lpcchBuffer > dwLength)
2853 {
2854 wcscpy(lpDisplayName, lpService->lpDisplayName);
2855 }
2856 }
2857
2858 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2859
2860 *lpcchBuffer = dwLength;
2861
2862 return dwError;
2863 }
2864
2865
2866 /* Function 21 */
2867 DWORD RGetServiceKeyNameW(
2868 SC_RPC_HANDLE hSCManager,
2869 LPCWSTR lpDisplayName,
2870 LPWSTR lpServiceName,
2871 DWORD *lpcchBuffer)
2872 {
2873 // PMANAGER_HANDLE hManager;
2874 PSERVICE lpService;
2875 DWORD dwLength;
2876 DWORD dwError;
2877
2878 DPRINT("RGetServiceKeyNameW() called\n");
2879 DPRINT("hSCManager = %p\n", hSCManager);
2880 DPRINT("lpDisplayName: %S\n", lpDisplayName);
2881 DPRINT("lpServiceName: %p\n", lpServiceName);
2882 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2883
2884 // hManager = (PMANAGER_HANDLE)hSCManager;
2885 // if (hManager->Handle.Tag != MANAGER_TAG)
2886 // {
2887 // DPRINT("Invalid manager handle!\n");
2888 // return ERROR_INVALID_HANDLE;
2889 // }
2890
2891 /* Get service database entry */
2892 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
2893 if (lpService == NULL)
2894 {
2895 DPRINT("Could not find a service!\n");
2896
2897 /* If the service could not be found and lpcchBuffer is less than 2, windows
2898 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2899 if (*lpcchBuffer < 2)
2900 {
2901 *lpcchBuffer = 2;
2902 if (lpServiceName != NULL)
2903 {
2904 *lpServiceName = '\0';
2905 }
2906 }
2907
2908 return ERROR_SERVICE_DOES_NOT_EXIST;
2909 }
2910
2911 dwLength = wcslen(lpService->lpServiceName);
2912
2913 if (lpServiceName != NULL &&
2914 *lpcchBuffer > dwLength)
2915 {
2916 wcscpy(lpServiceName, lpService->lpServiceName);
2917 *lpcchBuffer = dwLength;
2918 return ERROR_SUCCESS;
2919 }
2920
2921 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2922
2923 *lpcchBuffer = dwLength;
2924
2925 return dwError;
2926 }
2927
2928
2929 /* Function 22 */
2930 DWORD RI_ScSetServiceBitsA(
2931 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
2932 DWORD dwServiceBits,
2933 int bSetBitsOn,
2934 int bUpdateImmediately,
2935 char *lpString)
2936 {
2937 UNIMPLEMENTED;
2938 return ERROR_CALL_NOT_IMPLEMENTED;
2939 }
2940
2941
2942 /* Function 23 */
2943 DWORD RChangeServiceConfigA(
2944 SC_RPC_HANDLE hService,
2945 DWORD dwServiceType,
2946 DWORD dwStartType,
2947 DWORD dwErrorControl,
2948 LPSTR lpBinaryPathName,
2949 LPSTR lpLoadOrderGroup,
2950 LPDWORD lpdwTagId,
2951 LPSTR lpDependencies,
2952 DWORD dwDependSize,
2953 LPSTR lpServiceStartName,
2954 LPBYTE lpPassword,
2955 DWORD dwPwSize,
2956 LPSTR lpDisplayName)
2957 {
2958 DWORD dwError = ERROR_SUCCESS;
2959 PSERVICE_HANDLE hSvc;
2960 PSERVICE lpService = NULL;
2961 HKEY hServiceKey = NULL;
2962 LPWSTR lpDisplayNameW = NULL;
2963 // LPWSTR lpBinaryPathNameW = NULL;
2964 LPWSTR lpLoadOrderGroupW = NULL;
2965 LPWSTR lpDependenciesW = NULL;
2966 // LPWSTR lpPasswordW = NULL;
2967
2968 DPRINT("RChangeServiceConfigA() called\n");
2969 DPRINT("dwServiceType = %lu\n", dwServiceType);
2970 DPRINT("dwStartType = %lu\n", dwStartType);
2971 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2972 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
2973 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
2974 DPRINT("lpDisplayName = %s\n", lpDisplayName);
2975
2976 if (ScmShutdown)
2977 return ERROR_SHUTDOWN_IN_PROGRESS;
2978
2979 hSvc = (PSERVICE_HANDLE)hService;
2980 if (!hSvc || hSvc->Handle.Tag != SERVICE_TAG)
2981 {
2982 DPRINT("Invalid handle tag!\n");
2983 return ERROR_INVALID_HANDLE;
2984 }
2985
2986 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2987 SERVICE_CHANGE_CONFIG))
2988 {
2989 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2990 return ERROR_ACCESS_DENIED;
2991 }
2992
2993 lpService = hSvc->ServiceEntry;
2994 if (lpService == NULL)
2995 {
2996 DPRINT("lpService == NULL!\n");
2997 return ERROR_INVALID_HANDLE;
2998 }
2999
3000 /* FIXME: Lock database exclusively */
3001
3002 if (lpService->bDeleted)
3003 {
3004 /* FIXME: Unlock database */
3005 DPRINT("The service has already been marked for delete!\n");
3006 return ERROR_SERVICE_MARKED_FOR_DELETE;
3007 }
3008
3009 /* Open the service key */
3010 dwError = ScmOpenServiceKey(lpService->szServiceName,
3011 KEY_SET_VALUE,
3012 &hServiceKey);
3013 if (dwError != ERROR_SUCCESS)
3014 goto done;
3015
3016 /* Write service data to the registry */
3017
3018 if (lpDisplayName != NULL && *lpDisplayName != 0)
3019 {
3020 /* Set the display name */
3021 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3022 0,
3023 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3024 if (lpDisplayNameW == NULL)
3025 {
3026 dwError = ERROR_NOT_ENOUGH_MEMORY;
3027 goto done;
3028 }
3029
3030 MultiByteToWideChar(CP_ACP,
3031 0,
3032 lpDisplayName,
3033 -1,
3034 lpDisplayNameW,
3035 strlen(lpDisplayName) + 1);
3036
3037 RegSetValueExW(hServiceKey,
3038 L"DisplayName",
3039 0,
3040 REG_SZ,
3041 (LPBYTE)lpDisplayNameW,
3042 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3043
3044 /* Update lpService->lpDisplayName */
3045 if (lpService->lpDisplayName)
3046 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3047
3048 lpService->lpDisplayName = lpDisplayNameW;
3049 }
3050
3051 if (dwServiceType != SERVICE_NO_CHANGE)
3052 {
3053 /* Set the service type */
3054 dwError = RegSetValueExW(hServiceKey,
3055 L"Type",
3056 0,
3057 REG_DWORD,
3058 (LPBYTE)&dwServiceType,
3059 sizeof(DWORD));
3060 if (dwError != ERROR_SUCCESS)
3061 goto done;
3062
3063 lpService->Status.dwServiceType = dwServiceType;
3064 }
3065
3066 if (dwStartType != SERVICE_NO_CHANGE)
3067 {
3068 /* Set the start value */
3069 dwError = RegSetValueExW(hServiceKey,
3070 L"Start",
3071 0,
3072 REG_DWORD,
3073 (LPBYTE)&dwStartType,
3074 sizeof(DWORD));
3075 if (dwError != ERROR_SUCCESS)
3076 goto done;
3077
3078 lpService->dwStartType = dwStartType;
3079 }
3080
3081 if (dwErrorControl != SERVICE_NO_CHANGE)
3082 {
3083 /* Set the error control value */
3084 dwError = RegSetValueExW(hServiceKey,
3085 L"ErrorControl",
3086 0,
3087 REG_DWORD,
3088 (LPBYTE)&dwErrorControl,
3089 sizeof(DWORD));
3090 if (dwError != ERROR_SUCCESS)
3091 goto done;
3092
3093 lpService->dwErrorControl = dwErrorControl;
3094 }
3095
3096 #if 0
3097 /* FIXME: set the new ImagePath value */
3098
3099 /* Set the image path */
3100 if (dwServiceType & SERVICE_WIN32)
3101 {
3102 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3103 {
3104 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3105 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
3106 dwError = RegSetValueExW(hServiceKey,
3107 L"ImagePath",
3108 0,
3109 REG_EXPAND_SZ,
3110 (LPBYTE)lpBinaryPathNameW,
3111 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3112 if (dwError != ERROR_SUCCESS)
3113 goto done;
3114 }
3115 }
3116 else if (dwServiceType & SERVICE_DRIVER)
3117 {
3118 if (lpImagePath != NULL && *lpImagePath != 0)
3119 {
3120 dwError = RegSetValueExW(hServiceKey,
3121 L"ImagePath",
3122 0,
3123 REG_EXPAND_SZ,
3124 (LPBYTE)lpImagePath,
3125 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3126 if (dwError != ERROR_SUCCESS)
3127 goto done;
3128 }
3129 }
3130 #endif
3131
3132 /* Set the group name */
3133 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3134 {
3135 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3136 0,
3137 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3138 if (lpLoadOrderGroupW == NULL)
3139 {
3140 dwError = ERROR_NOT_ENOUGH_MEMORY;
3141 goto done;
3142 }
3143
3144 MultiByteToWideChar(CP_ACP,
3145 0,
3146 lpLoadOrderGroup,
3147 -1,
3148 lpLoadOrderGroupW,
3149 strlen(lpLoadOrderGroup) + 1);
3150
3151 dwError = RegSetValueExW(hServiceKey,
3152 L"Group",
3153 0,
3154 REG_SZ,
3155 (LPBYTE)lpLoadOrderGroupW,
3156 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3157 if (dwError != ERROR_SUCCESS)
3158 {
3159 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3160 goto done;
3161 }
3162
3163 dwError = ScmSetServiceGroup(lpService,
3164 lpLoadOrderGroupW);
3165
3166 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3167
3168 if (dwError != ERROR_SUCCESS)
3169 goto done;
3170 }
3171
3172 if (lpdwTagId != NULL)
3173 {
3174 dwError = ScmAssignNewTag(lpService);
3175 if (dwError != ERROR_SUCCESS)
3176 goto done;
3177
3178 dwError = RegSetValueExW(hServiceKey,
3179 L"Tag",
3180 0,
3181 REG_DWORD,
3182 (LPBYTE)&lpService->dwTag,
3183 sizeof(DWORD));
3184 if (dwError != ERROR_SUCCESS)
3185 goto done;
3186
3187 *lpdwTagId = lpService->dwTag;
3188 }
3189
3190 /* Write dependencies */
3191 if (lpDependencies != NULL && *lpDependencies != 0)
3192 {
3193 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3194 0,
3195 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3196 if (lpDependenciesW == NULL)
3197 {
3198 dwError = ERROR_NOT_ENOUGH_MEMORY;
3199 goto done;
3200 }
3201
3202 MultiByteToWideChar(CP_ACP,
3203 0,
3204 lpDependencies,
3205 dwDependSize,
3206 lpDependenciesW,
3207 strlen(lpDependencies) + 1);
3208
3209 dwError = ScmWriteDependencies(hServiceKey,
3210 (LPWSTR)lpDependenciesW,
3211 dwDependSize);
3212
3213 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3214 }
3215
3216 if (lpPassword != NULL)
3217 {
3218 /* FIXME: Write password */
3219 }
3220
3221 /* FIXME: Unlock database */
3222
3223 done:
3224 if (hServiceKey != NULL)
3225 RegCloseKey(hServiceKey);
3226
3227 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3228
3229 return dwError;
3230 }
3231
3232
3233 /* Function 24 */
3234 DWORD RCreateServiceA(
3235 SC_RPC_HANDLE hSCManager,
3236 LPSTR lpServiceName,
3237 LPSTR lpDisplayName,
3238 DWORD dwDesiredAccess,
3239 DWORD dwServiceType,
3240 DWORD dwStartType,
3241 DWORD dwErrorControl,
3242 LPSTR lpBinaryPathName,
3243 LPSTR lpLoadOrderGroup,
3244 LPDWORD lpdwTagId,
3245 LPBYTE lpDependencies,
3246 DWORD dwDependSize,
3247 LPSTR lpServiceStartName,
3248 LPBYTE lpPassword,
3249 DWORD dwPwSize,
3250 LPSC_RPC_HANDLE lpServiceHandle)
3251 {
3252 DWORD dwError = ERROR_SUCCESS;
3253 LPWSTR lpServiceNameW = NULL;
3254 LPWSTR lpDisplayNameW = NULL;
3255 LPWSTR lpBinaryPathNameW = NULL;
3256 LPWSTR lpLoadOrderGroupW = NULL;
3257 LPWSTR lpDependenciesW = NULL;
3258 LPWSTR lpServiceStartNameW = NULL;