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