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