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