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