58d8b5d3452934980e8a4254aae7999fddfaa0a5
[reactos.git] / reactos / base / system / services / rpcserver.c
1 /*
2 * PROJECT: ReactOS Service Control Manager
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: base/system/services/rpcserver.c
5 * PURPOSE: RPC server interface for the advapi32 calls
6 * COPYRIGHT: Copyright 2005-2006 Eric Kohl
7 * Copyright 2006-2007 Hervé Poussineau <hpoussin@reactos.org>
8 * Copyright 2007 Ged Murphy <gedmurphy@reactos.org>
9 */
10
11 /* INCLUDES ****************************************************************/
12
13 #include "services.h"
14 #include "svcctl_s.h"
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS *****************************************************************/
20
21 #define MANAGER_TAG 0x72674D68 /* 'hMgr' */
22 #define SERVICE_TAG 0x63765368 /* 'hSvc' */
23
24 typedef struct _SCMGR_HANDLE
25 {
26 DWORD Tag;
27 DWORD DesiredAccess;
28 } SCMGR_HANDLE;
29
30
31 typedef struct _MANAGER_HANDLE
32 {
33 SCMGR_HANDLE Handle;
34 WCHAR DatabaseName[1];
35 } MANAGER_HANDLE, *PMANAGER_HANDLE;
36
37
38 typedef struct _SERVICE_HANDLE
39 {
40 SCMGR_HANDLE Handle;
41 PSERVICE ServiceEntry;
42 } SERVICE_HANDLE, *PSERVICE_HANDLE;
43
44
45 #define SC_MANAGER_READ \
46 (STANDARD_RIGHTS_READ | \
47 SC_MANAGER_QUERY_LOCK_STATUS | \
48 SC_MANAGER_ENUMERATE_SERVICE)
49
50 #define SC_MANAGER_WRITE \
51 (STANDARD_RIGHTS_WRITE | \
52 SC_MANAGER_MODIFY_BOOT_CONFIG | \
53 SC_MANAGER_CREATE_SERVICE)
54
55 #define SC_MANAGER_EXECUTE \
56 (STANDARD_RIGHTS_EXECUTE | \
57 SC_MANAGER_LOCK | \
58 SC_MANAGER_ENUMERATE_SERVICE | \
59 SC_MANAGER_CONNECT | \
60 SC_MANAGER_CREATE_SERVICE)
61
62
63 #define SERVICE_READ \
64 (STANDARD_RIGHTS_READ | \
65 SERVICE_INTERROGATE | \
66 SERVICE_ENUMERATE_DEPENDENTS | \
67 SERVICE_QUERY_STATUS | \
68 SERVICE_QUERY_CONFIG)
69
70 #define SERVICE_WRITE \
71 (STANDARD_RIGHTS_WRITE | \
72 SERVICE_CHANGE_CONFIG)
73
74 #define SERVICE_EXECUTE \
75 (STANDARD_RIGHTS_EXECUTE | \
76 SERVICE_USER_DEFINED_CONTROL | \
77 SERVICE_PAUSE_CONTINUE | \
78 SERVICE_STOP | \
79 SERVICE_START)
80
81
82 /* VARIABLES ***************************************************************/
83
84 static GENERIC_MAPPING
85 ScmManagerMapping = {SC_MANAGER_READ,
86 SC_MANAGER_WRITE,
87 SC_MANAGER_EXECUTE,
88 SC_MANAGER_ALL_ACCESS};
89
90 static GENERIC_MAPPING
91 ScmServiceMapping = {SERVICE_READ,
92 SERVICE_WRITE,
93 SERVICE_EXECUTE,
94 SC_MANAGER_ALL_ACCESS};
95
96
97 /* FUNCTIONS ***************************************************************/
98
99 VOID
100 ScmStartRpcServer(VOID)
101 {
102 RPC_STATUS Status;
103
104 DPRINT("ScmStartRpcServer() called\n");
105
106 Status = RpcServerUseProtseqEpW(L"ncacn_np",
107 10,
108 L"\\pipe\\ntsvcs",
109 NULL);
110 if (Status != RPC_S_OK)
111 {
112 DPRINT1("RpcServerUseProtseqEpW() failed (Status %lx)\n", Status);
113 return;
114 }
115
116 Status = RpcServerRegisterIf(svcctl_v2_0_s_ifspec,
117 NULL,
118 NULL);
119 if (Status != RPC_S_OK)
120 {
121 DPRINT1("RpcServerRegisterIf() failed (Status %lx)\n", Status);
122 return;
123 }
124
125 Status = RpcServerListen(1, 20, TRUE);
126 if (Status != RPC_S_OK)
127 {
128 DPRINT1("RpcServerListen() failed (Status %lx)\n", Status);
129 return;
130 }
131
132 DPRINT("ScmStartRpcServer() done\n");
133 }
134
135
136 static DWORD
137 ScmCreateManagerHandle(LPWSTR lpDatabaseName,
138 SC_HANDLE *Handle)
139 {
140 PMANAGER_HANDLE Ptr;
141
142 if (lpDatabaseName == NULL)
143 lpDatabaseName = SERVICES_ACTIVE_DATABASEW;
144
145 if (_wcsicmp(lpDatabaseName, SERVICES_FAILED_DATABASEW) == 0)
146 {
147 DPRINT("Database %S, does not exist\n",lpDatabaseName);
148 return ERROR_DATABASE_DOES_NOT_EXIST;
149 }
150 else if (_wcsicmp(lpDatabaseName, SERVICES_ACTIVE_DATABASEW) != 0)
151 {
152 DPRINT("Invalid Database name %S.\n",lpDatabaseName);
153 return ERROR_INVALID_NAME;
154 }
155
156 Ptr = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
157 HEAP_ZERO_MEMORY,
158 sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
159 if (Ptr == NULL)
160 return ERROR_NOT_ENOUGH_MEMORY;
161
162 Ptr->Handle.Tag = MANAGER_TAG;
163
164 wcscpy(Ptr->DatabaseName, lpDatabaseName);
165
166 *Handle = (SC_HANDLE)Ptr;
167
168 return ERROR_SUCCESS;
169 }
170
171
172 static DWORD
173 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
174 SC_HANDLE *Handle)
175 {
176 PSERVICE_HANDLE Ptr;
177
178 Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
179 HEAP_ZERO_MEMORY,
180 sizeof(SERVICE_HANDLE));
181 if (Ptr == NULL)
182 return ERROR_NOT_ENOUGH_MEMORY;
183
184 Ptr->Handle.Tag = SERVICE_TAG;
185
186 Ptr->ServiceEntry = lpServiceEntry;
187
188 *Handle = (SC_HANDLE)Ptr;
189
190 return ERROR_SUCCESS;
191 }
192
193
194 static PMANAGER_HANDLE
195 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
196 {
197 PMANAGER_HANDLE pManager = NULL;
198
199 _SEH2_TRY
200 {
201 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
202 pManager = (PMANAGER_HANDLE)Handle;
203 }
204 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
205 {
206 DPRINT1("Exception: Invalid Service Manager handle!\n");
207 }
208 _SEH2_END;
209
210 return pManager;
211 }
212
213
214 static PSERVICE_HANDLE
215 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
216 {
217 PSERVICE_HANDLE pService = NULL;
218
219 _SEH2_TRY
220 {
221 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
222 pService = (PSERVICE_HANDLE)Handle;
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 DPRINT1("Exception: Invalid Service handle!\n");
227 }
228 _SEH2_END;
229
230 return pService;
231 }
232
233
234 static DWORD
235 ScmCheckAccess(SC_HANDLE Handle,
236 DWORD dwDesiredAccess)
237 {
238 PMANAGER_HANDLE hMgr;
239
240 hMgr = (PMANAGER_HANDLE)Handle;
241 if (hMgr->Handle.Tag == MANAGER_TAG)
242 {
243 RtlMapGenericMask(&dwDesiredAccess,
244 &ScmManagerMapping);
245
246 hMgr->Handle.DesiredAccess = dwDesiredAccess;
247
248 return ERROR_SUCCESS;
249 }
250 else if (hMgr->Handle.Tag == SERVICE_TAG)
251 {
252 RtlMapGenericMask(&dwDesiredAccess,
253 &ScmServiceMapping);
254
255 hMgr->Handle.DesiredAccess = dwDesiredAccess;
256
257 return ERROR_SUCCESS;
258 }
259
260 return ERROR_INVALID_HANDLE;
261 }
262
263
264 DWORD
265 ScmAssignNewTag(PSERVICE lpService)
266 {
267 /* FIXME */
268 DPRINT("Assigning new tag to service %S\n", lpService->lpServiceName);
269 lpService->dwTag = 0;
270 return ERROR_SUCCESS;
271 }
272
273
274 /* Internal recursive function */
275 /* Need to search for every dependency on every service */
276 static DWORD
277 Int_EnumDependentServicesW(HKEY hServicesKey,
278 PSERVICE lpService,
279 DWORD dwServiceState,
280 PSERVICE *lpServices,
281 LPDWORD pcbBytesNeeded,
282 LPDWORD lpServicesReturned)
283 {
284 DWORD dwError = ERROR_SUCCESS;
285 WCHAR szNameBuf[MAX_PATH];
286 WCHAR szValueBuf[MAX_PATH];
287 WCHAR *lpszNameBuf = szNameBuf;
288 WCHAR *lpszValueBuf = szValueBuf;
289 DWORD dwSize;
290 DWORD dwNumSubKeys;
291 DWORD dwIteration;
292 PSERVICE lpCurrentService;
293 HKEY hServiceEnumKey;
294 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
295 DWORD dwDependServiceStrPtr = 0;
296 DWORD dwRequiredSize = 0;
297
298 /* Get the number of service keys */
299 dwError = RegQueryInfoKeyW(hServicesKey,
300 NULL,
301 NULL,
302 NULL,
303 &dwNumSubKeys,
304 NULL,
305 NULL,
306 NULL,
307 NULL,
308 NULL,
309 NULL,
310 NULL);
311 if (dwError != ERROR_SUCCESS)
312 {
313 DPRINT("ERROR! Unable to get number of services keys.\n");
314 return dwError;
315 }
316
317 /* Iterate the service keys to see if another service depends on the this service */
318 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
319 {
320 dwSize = MAX_PATH;
321 dwError = RegEnumKeyExW(hServicesKey,
322 dwIteration,
323 lpszNameBuf,
324 &dwSize,
325 NULL,
326 NULL,
327 NULL,
328 NULL);
329 if (dwError != ERROR_SUCCESS)
330 return dwError;
331
332 /* Open the Service key */
333 dwError = RegOpenKeyExW(hServicesKey,
334 lpszNameBuf,
335 0,
336 KEY_READ,
337 &hServiceEnumKey);
338 if (dwError != ERROR_SUCCESS)
339 return dwError;
340
341 dwSize = MAX_PATH;
342
343 /* Check for the DependOnService Value */
344 dwError = RegQueryValueExW(hServiceEnumKey,
345 L"DependOnService",
346 NULL,
347 NULL,
348 (LPBYTE)lpszValueBuf,
349 &dwSize);
350
351 /* FIXME: Handle load order. */
352
353 /* If the service found has a DependOnService value */
354 if (dwError == ERROR_SUCCESS)
355 {
356 dwDependServiceStrPtr = 0;
357
358 /* Can be more than one Dependencies in the DependOnService string */
359 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
360 {
361 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
362 {
363 /* Get the current enumed service pointer */
364 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
365
366 /* Check for valid Service */
367 if (!lpCurrentService)
368 {
369 /* This should never happen! */
370 DPRINT("This should not happen at this point, report to Developer\n");
371 return ERROR_NOT_FOUND;
372 }
373
374 /* Determine state the service is in */
375 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
376 dwCurrentServiceState = SERVICE_INACTIVE;
377
378 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
379 if ((dwCurrentServiceState == dwServiceState) ||
380 (dwServiceState == SERVICE_STATE_ALL))
381 {
382 /* Calculate the required size */
383 dwRequiredSize += sizeof(SERVICE_STATUS);
384 dwRequiredSize += ((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
385 dwRequiredSize += ((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
386
387 /* Add the size for service name and display name pointers */
388 dwRequiredSize += (2 * sizeof(PVOID));
389
390 /* increase the BytesNeeded size */
391 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
392
393 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
394 comes first */
395
396 /* Recursive call to check for its dependencies */
397 Int_EnumDependentServicesW(hServicesKey,
398 lpCurrentService,
399 dwServiceState,
400 lpServices,
401 pcbBytesNeeded,
402 lpServicesReturned);
403
404 /* If the lpServices is valid set the service pointer */
405 if (lpServices)
406 lpServices[*lpServicesReturned] = lpCurrentService;
407
408 *lpServicesReturned = *lpServicesReturned + 1;
409 }
410 }
411
412 dwDependServiceStrPtr += (wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
413 }
414 }
415 else if (*pcbBytesNeeded)
416 {
417 dwError = ERROR_SUCCESS;
418 }
419
420 RegCloseKey(hServiceEnumKey);
421 }
422
423 return dwError;
424 }
425
426
427 /* Function 0 */
428 DWORD RCloseServiceHandle(
429 LPSC_RPC_HANDLE hSCObject)
430 {
431 PMANAGER_HANDLE hManager;
432 PSERVICE_HANDLE hService;
433 PSERVICE lpService;
434 HKEY hServicesKey;
435 DWORD dwError;
436 DWORD pcbBytesNeeded = 0;
437 DWORD dwServicesReturned = 0;
438
439 DPRINT("RCloseServiceHandle() called\n");
440
441 DPRINT("hSCObject = %p\n", *hSCObject);
442
443 if (*hSCObject == 0)
444 return ERROR_INVALID_HANDLE;
445
446 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
447 hService = ScmGetServiceFromHandle(*hSCObject);
448
449 if (hManager != NULL)
450 {
451 DPRINT("Found manager handle\n");
452
453 /* FIXME: add handle cleanup code */
454
455 HeapFree(GetProcessHeap(), 0, hManager);
456 hManager = NULL;
457
458 *hSCObject = NULL;
459
460 DPRINT("RCloseServiceHandle() done\n");
461 return ERROR_SUCCESS;
462 }
463 else if (hService != NULL)
464 {
465 DPRINT("Found service handle\n");
466
467 /* Lock the service database exlusively */
468 ScmLockDatabaseExclusive();
469
470 /* Get the pointer to the service record */
471 lpService = hService->ServiceEntry;
472
473 /* FIXME: add handle cleanup code */
474
475 /* Free the handle */
476 HeapFree(GetProcessHeap(), 0, hService);
477 hService = NULL;
478
479 ASSERT(lpService->dwRefCount > 0);
480
481 lpService->dwRefCount--;
482 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
483 lpService->dwRefCount);
484
485 if (lpService->dwRefCount == 0)
486 {
487 /* If this service has been marked for deletion */
488 if (lpService->bDeleted)
489 {
490 /* Open the Services Reg key */
491 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
492 L"System\\CurrentControlSet\\Services",
493 0,
494 KEY_SET_VALUE | KEY_READ,
495 &hServicesKey);
496 if (dwError != ERROR_SUCCESS)
497 {
498 DPRINT("Failed to open services key\n");
499 ScmUnlockDatabase();
500 return dwError;
501 }
502
503 /* Call the internal function with NULL, just to get bytes we need */
504 Int_EnumDependentServicesW(hServicesKey,
505 lpService,
506 SERVICE_ACTIVE,
507 NULL,
508 &pcbBytesNeeded,
509 &dwServicesReturned);
510
511 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service*/
512 if (pcbBytesNeeded)
513 {
514 DPRINT("Deletion failed due to running dependencies.\n");
515 RegCloseKey(hServicesKey);
516 ScmUnlockDatabase();
517 return ERROR_SUCCESS;
518 }
519
520 /* There are no references and no runnning dependencies,
521 it is now safe to delete the service */
522
523 /* Delete the Service Key */
524 dwError = RegDeleteKeyW(hServicesKey,
525 lpService->lpServiceName);
526
527 RegCloseKey(hServicesKey);
528
529 if (dwError != ERROR_SUCCESS)
530 {
531 DPRINT("Failed to Delete the Service Registry key\n");
532 ScmUnlockDatabase();
533 return dwError;
534 }
535
536 /* Delete the Service */
537 ScmDeleteServiceRecord(lpService);
538 }
539 }
540
541 ScmUnlockDatabase();
542
543 *hSCObject = NULL;
544
545 DPRINT("RCloseServiceHandle() done\n");
546 return ERROR_SUCCESS;
547 }
548
549 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
550
551 return ERROR_INVALID_HANDLE;
552 }
553
554
555 /* Function 1 */
556 DWORD RControlService(
557 SC_RPC_HANDLE hService,
558 DWORD dwControl,
559 LPSERVICE_STATUS lpServiceStatus)
560 {
561 PSERVICE_HANDLE hSvc;
562 PSERVICE lpService;
563 ACCESS_MASK DesiredAccess;
564 DWORD dwError = ERROR_SUCCESS;
565 DWORD pcbBytesNeeded = 0;
566 DWORD dwServicesReturned = 0;
567 DWORD dwControlsAccepted;
568 DWORD dwCurrentState;
569 HKEY hServicesKey = NULL;
570
571 DPRINT("RControlService() called\n");
572
573 if (ScmShutdown)
574 return ERROR_SHUTDOWN_IN_PROGRESS;
575
576 /* Check the service handle */
577 hSvc = ScmGetServiceFromHandle(hService);
578 if (hSvc == NULL)
579 {
580 DPRINT1("Invalid service handle!\n");
581 return ERROR_INVALID_HANDLE;
582 }
583
584
585 /* Check the service entry point */
586 lpService = hSvc->ServiceEntry;
587 if (lpService == NULL)
588 {
589 DPRINT1("lpService == NULL!\n");
590 return ERROR_INVALID_HANDLE;
591 }
592
593 /* Check access rights */
594 switch (dwControl)
595 {
596 case SERVICE_CONTROL_STOP:
597 DesiredAccess = SERVICE_STOP;
598 break;
599
600 case SERVICE_CONTROL_PAUSE:
601 case SERVICE_CONTROL_CONTINUE:
602 DesiredAccess = SERVICE_PAUSE_CONTINUE;
603 break;
604
605 case SERVICE_INTERROGATE:
606 DesiredAccess = SERVICE_INTERROGATE;
607 break;
608
609 default:
610 if (dwControl >= 128 && dwControl <= 255)
611 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
612 else
613 DesiredAccess = SERVICE_QUERY_CONFIG |
614 SERVICE_CHANGE_CONFIG |
615 SERVICE_QUERY_STATUS |
616 SERVICE_START |
617 SERVICE_PAUSE_CONTINUE;
618 break;
619 }
620
621 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
622 DesiredAccess))
623 return ERROR_ACCESS_DENIED;
624
625 if (dwControl == SERVICE_CONTROL_STOP)
626 {
627 /* Check if the service has dependencies running as windows
628 doesn't stop a service that does */
629
630 /* Open the Services Reg key */
631 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
632 L"System\\CurrentControlSet\\Services",
633 0,
634 KEY_READ,
635 &hServicesKey);
636 if (dwError != ERROR_SUCCESS)
637 {
638 DPRINT("Failed to open services key\n");
639 return dwError;
640 }
641
642 /* Call the internal function with NULL, just to get bytes we need */
643 Int_EnumDependentServicesW(hServicesKey,
644 lpService,
645 SERVICE_ACTIVE,
646 NULL,
647 &pcbBytesNeeded,
648 &dwServicesReturned);
649
650 RegCloseKey(hServicesKey);
651
652 /* If pcbBytesNeeded is not zero then there are services running that
653 are dependent on this service */
654 if (pcbBytesNeeded != 0)
655 {
656 DPRINT("Service has running dependencies. Failed to stop service.\n");
657 return ERROR_DEPENDENT_SERVICES_RUNNING;
658 }
659 }
660
661 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
662 {
663 /* Send control code to the driver */
664 dwError = ScmControlDriver(lpService,
665 dwControl,
666 lpServiceStatus);
667 }
668 else
669 {
670 dwControlsAccepted = lpService->Status.dwControlsAccepted;
671 dwCurrentState = lpService->Status.dwCurrentState;
672
673 /* Check the current state before sending a control request */
674 switch (dwCurrentState)
675 {
676 case SERVICE_STOP_PENDING:
677 case SERVICE_STOPPED:
678 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
679
680 case SERVICE_START_PENDING:
681 switch (dwControl)
682 {
683 case SERVICE_CONTROL_STOP:
684 break;
685
686 case SERVICE_CONTROL_INTERROGATE:
687 RtlCopyMemory(lpServiceStatus,
688 &lpService->Status,
689 sizeof(SERVICE_STATUS));
690 return ERROR_SUCCESS;
691
692 default:
693 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
694 }
695 break;
696 }
697
698 /* Check if the control code is acceptable to the service */
699 switch (dwControl)
700 {
701 case SERVICE_CONTROL_STOP:
702 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
703 return ERROR_INVALID_SERVICE_CONTROL;
704 break;
705
706 case SERVICE_CONTROL_PAUSE:
707 case SERVICE_CONTROL_CONTINUE:
708 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
709 return ERROR_INVALID_SERVICE_CONTROL;
710 break;
711 }
712
713 /* Send control code to the service */
714 dwError = ScmControlService(lpService,
715 dwControl);
716
717 /* Return service status information */
718 RtlCopyMemory(lpServiceStatus,
719 &lpService->Status,
720 sizeof(SERVICE_STATUS));
721 }
722
723 if ((dwError == ERROR_SUCCESS) && (pcbBytesNeeded))
724 dwError = ERROR_DEPENDENT_SERVICES_RUNNING;
725
726 if (dwError == ERROR_SUCCESS &&
727 dwControl == SERVICE_CONTROL_STOP &&
728 lpServiceStatus->dwCurrentState == SERVICE_STOPPED)
729 {
730 lpService->ProcessId = 0; /* FIXME */
731 lpService->ThreadId = 0;
732 }
733
734
735 return dwError;
736 }
737
738
739 /* Function 2 */
740 DWORD RDeleteService(
741 SC_RPC_HANDLE hService)
742 {
743 PSERVICE_HANDLE hSvc;
744 PSERVICE lpService;
745 DWORD dwError;
746
747 DPRINT("RDeleteService() called\n");
748
749 if (ScmShutdown)
750 return ERROR_SHUTDOWN_IN_PROGRESS;
751
752 hSvc = ScmGetServiceFromHandle(hService);
753 if (hSvc == NULL)
754 {
755 DPRINT1("Invalid service handle!\n");
756 return ERROR_INVALID_HANDLE;
757 }
758
759 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
760 DELETE))
761 return ERROR_ACCESS_DENIED;
762
763 lpService = hSvc->ServiceEntry;
764 if (lpService == NULL)
765 {
766 DPRINT("lpService == NULL!\n");
767 return ERROR_INVALID_HANDLE;
768 }
769
770 /* Lock the service database exclusively */
771 ScmLockDatabaseExclusive();
772
773 if (lpService->bDeleted)
774 {
775 DPRINT("The service has already been marked for delete!\n");
776 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
777 goto Done;
778 }
779
780 /* Mark service for delete */
781 lpService->bDeleted = TRUE;
782
783 dwError = ScmMarkServiceForDelete(lpService);
784
785 Done:;
786 /* Unlock the service database */
787 ScmUnlockDatabase();
788
789 DPRINT("RDeleteService() done\n");
790
791 return dwError;
792 }
793
794
795 /* Function 3 */
796 DWORD RLockServiceDatabase(
797 SC_RPC_HANDLE hSCManager,
798 LPSC_RPC_LOCK lpLock)
799 {
800 PMANAGER_HANDLE hMgr;
801
802 DPRINT("RLockServiceDatabase() called\n");
803
804 *lpLock = 0;
805
806 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
807 if (hMgr == NULL)
808 {
809 DPRINT1("Invalid service manager handle!\n");
810 return ERROR_INVALID_HANDLE;
811 }
812
813 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
814 SC_MANAGER_LOCK))
815 return ERROR_ACCESS_DENIED;
816
817 // return ScmLockDatabase(0, hMgr->0xC, hLock);
818
819 /* FIXME: Lock the database */
820 *lpLock = (SC_RPC_LOCK)0x12345678; /* Dummy! */
821
822 return ERROR_SUCCESS;
823 }
824
825
826 /* Function 4 */
827 DWORD RQueryServiceObjectSecurity(
828 SC_RPC_HANDLE hService,
829 SECURITY_INFORMATION dwSecurityInformation,
830 LPBYTE lpSecurityDescriptor,
831 DWORD cbBufSize,
832 LPBOUNDED_DWORD_256K pcbBytesNeeded)
833 {
834 PSERVICE_HANDLE hSvc;
835 PSERVICE lpService;
836 ULONG DesiredAccess = 0;
837 NTSTATUS Status;
838 DWORD dwBytesNeeded;
839 DWORD dwError;
840
841
842 SECURITY_DESCRIPTOR ObjectDescriptor;
843
844 DPRINT("RQueryServiceObjectSecurity() called\n");
845
846 hSvc = ScmGetServiceFromHandle(hService);
847 if (hSvc == NULL)
848 {
849 DPRINT1("Invalid service handle!\n");
850 return ERROR_INVALID_HANDLE;
851 }
852
853 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
854 GROUP_SECURITY_INFORMATION |
855 OWNER_SECURITY_INFORMATION))
856 DesiredAccess |= READ_CONTROL;
857
858 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
859 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
860
861 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
862 DesiredAccess))
863 {
864 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
865 return ERROR_ACCESS_DENIED;
866 }
867
868 lpService = hSvc->ServiceEntry;
869 if (lpService == NULL)
870 {
871 DPRINT("lpService == NULL!\n");
872 return ERROR_INVALID_HANDLE;
873 }
874
875 /* FIXME: Lock the service list */
876
877 /* hack */
878 Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
879
880 Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
881 dwSecurityInformation,
882 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
883 cbBufSize,
884 &dwBytesNeeded);
885
886 /* FIXME: Unlock the service list */
887
888 if (NT_SUCCESS(Status))
889 {
890 *pcbBytesNeeded = dwBytesNeeded;
891 dwError = STATUS_SUCCESS;
892 }
893 else if (Status == STATUS_BUFFER_TOO_SMALL)
894 {
895 *pcbBytesNeeded = dwBytesNeeded;
896 dwError = ERROR_INSUFFICIENT_BUFFER;
897 }
898 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
899 {
900 dwError = ERROR_GEN_FAILURE;
901 }
902 else
903 {
904 dwError = RtlNtStatusToDosError(Status);
905 }
906
907 return dwError;
908 }
909
910
911 /* Function 5 */
912 DWORD RSetServiceObjectSecurity(
913 SC_RPC_HANDLE hService,
914 DWORD dwSecurityInformation,
915 LPBYTE lpSecurityDescriptor,
916 DWORD dwSecuityDescriptorSize)
917 {
918 PSERVICE_HANDLE hSvc;
919 PSERVICE lpService;
920 ULONG DesiredAccess = 0;
921 /* HANDLE hToken = NULL; */
922 HKEY hServiceKey;
923 /* NTSTATUS Status; */
924 DWORD dwError;
925
926 DPRINT("RSetServiceObjectSecurity() called\n");
927
928 hSvc = ScmGetServiceFromHandle(hService);
929 if (hSvc == NULL)
930 {
931 DPRINT1("Invalid service handle!\n");
932 return ERROR_INVALID_HANDLE;
933 }
934
935 if (dwSecurityInformation == 0 ||
936 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
937 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
938 return ERROR_INVALID_PARAMETER;
939
940 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
941 return ERROR_INVALID_PARAMETER;
942
943 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
944 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
945
946 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
947 DesiredAccess |= WRITE_DAC;
948
949 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
950 DesiredAccess |= WRITE_OWNER;
951
952 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
953 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
954 return ERROR_INVALID_PARAMETER;
955
956 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
957 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
958 return ERROR_INVALID_PARAMETER;
959
960 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
961 DesiredAccess))
962 {
963 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
964 return ERROR_ACCESS_DENIED;
965 }
966
967 lpService = hSvc->ServiceEntry;
968 if (lpService == NULL)
969 {
970 DPRINT("lpService == NULL!\n");
971 return ERROR_INVALID_HANDLE;
972 }
973
974 if (lpService->bDeleted)
975 return ERROR_SERVICE_MARKED_FOR_DELETE;
976
977 #if 0
978 RpcImpersonateClient(NULL);
979
980 Status = NtOpenThreadToken(NtCurrentThread(),
981 8,
982 TRUE,
983 &hToken);
984 if (!NT_SUCCESS(Status))
985 return RtlNtStatusToDosError(Status);
986
987 RpcRevertToSelf();
988
989 /* FIXME: Lock service database */
990
991 Status = RtlSetSecurityObject(dwSecurityInformation,
992 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
993 &lpService->lpSecurityDescriptor,
994 &ScmServiceMapping,
995 hToken);
996 if (!NT_SUCCESS(Status))
997 {
998 dwError = RtlNtStatusToDosError(Status);
999 goto Done;
1000 }
1001 #endif
1002
1003 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1004 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1005 &hServiceKey);
1006 if (dwError != ERROR_SUCCESS)
1007 goto Done;
1008
1009 UNIMPLEMENTED;
1010 dwError = ERROR_SUCCESS;
1011 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1012 // lpService->lpSecurityDescriptor);
1013
1014 RegFlushKey(hServiceKey);
1015 RegCloseKey(hServiceKey);
1016
1017 Done:
1018
1019 #if 0
1020 if (hToken != NULL)
1021 NtClose(hToken);
1022 #endif
1023
1024 /* FIXME: Unlock service database */
1025
1026 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1027
1028 return dwError;
1029 }
1030
1031
1032 /* Function 6 */
1033 DWORD RQueryServiceStatus(
1034 SC_RPC_HANDLE hService,
1035 LPSERVICE_STATUS lpServiceStatus)
1036 {
1037 PSERVICE_HANDLE hSvc;
1038 PSERVICE lpService;
1039
1040 DPRINT("RQueryServiceStatus() called\n");
1041
1042 if (ScmShutdown)
1043 return ERROR_SHUTDOWN_IN_PROGRESS;
1044
1045 hSvc = ScmGetServiceFromHandle(hService);
1046 if (hSvc == NULL)
1047 {
1048 DPRINT1("Invalid service handle!\n");
1049 return ERROR_INVALID_HANDLE;
1050 }
1051
1052 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1053 SERVICE_QUERY_STATUS))
1054 {
1055 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1056 return ERROR_ACCESS_DENIED;
1057 }
1058
1059 lpService = hSvc->ServiceEntry;
1060 if (lpService == NULL)
1061 {
1062 DPRINT("lpService == NULL!\n");
1063 return ERROR_INVALID_HANDLE;
1064 }
1065
1066 /* Lock the srevice database shared */
1067 ScmLockDatabaseShared();
1068
1069 /* Return service status information */
1070 RtlCopyMemory(lpServiceStatus,
1071 &lpService->Status,
1072 sizeof(SERVICE_STATUS));
1073
1074 /* Unlock the service database */
1075 ScmUnlockDatabase();
1076
1077 return ERROR_SUCCESS;
1078 }
1079
1080
1081 static BOOL
1082 ScmIsValidServiceState(DWORD dwCurrentState)
1083 {
1084 switch (dwCurrentState)
1085 {
1086 case SERVICE_STOPPED:
1087 case SERVICE_START_PENDING:
1088 case SERVICE_STOP_PENDING:
1089 case SERVICE_RUNNING:
1090 case SERVICE_CONTINUE_PENDING:
1091 case SERVICE_PAUSE_PENDING:
1092 case SERVICE_PAUSED:
1093 return TRUE;
1094
1095 default:
1096 return FALSE;
1097 }
1098 }
1099
1100
1101 /* Function 7 */
1102 DWORD RSetServiceStatus(
1103 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1104 LPSERVICE_STATUS lpServiceStatus)
1105 {
1106 PSERVICE lpService;
1107
1108 DPRINT("RSetServiceStatus() called\n");
1109 DPRINT("hServiceStatus = %p\n", hServiceStatus);
1110 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1111 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1112 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1113 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1114 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1115 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1116 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1117
1118 if (hServiceStatus == 0)
1119 {
1120 DPRINT("hServiceStatus == NULL!\n");
1121 return ERROR_INVALID_HANDLE;
1122 }
1123
1124 lpService = (PSERVICE)hServiceStatus;
1125 if (lpService == NULL)
1126 {
1127 DPRINT("lpService == NULL!\n");
1128 return ERROR_INVALID_HANDLE;
1129 }
1130
1131 /* Check current state */
1132 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1133 {
1134 DPRINT("Invalid service state!\n");
1135 return ERROR_INVALID_DATA;
1136 }
1137
1138 /* Check service type */
1139 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1140 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1141 {
1142 DPRINT("Invalid service type!\n");
1143 return ERROR_INVALID_DATA;
1144 }
1145
1146 /* Check accepted controls */
1147 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1148 {
1149 DPRINT("Invalid controls accepted!\n");
1150 return ERROR_INVALID_DATA;
1151 }
1152
1153 /* Lock the service database exclusively */
1154 ScmLockDatabaseExclusive();
1155
1156 RtlCopyMemory(&lpService->Status,
1157 lpServiceStatus,
1158 sizeof(SERVICE_STATUS));
1159
1160 /* Unlock the service database */
1161 ScmUnlockDatabase();
1162
1163 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1164 DPRINT("RSetServiceStatus() done\n");
1165
1166 return ERROR_SUCCESS;
1167 }
1168
1169
1170 /* Function 8 */
1171 DWORD RUnlockServiceDatabase(
1172 LPSC_RPC_LOCK Lock)
1173 {
1174 UNIMPLEMENTED;
1175 return ERROR_SUCCESS;
1176 }
1177
1178
1179 /* Function 9 */
1180 DWORD RNotifyBootConfigStatus(
1181 SVCCTL_HANDLEW lpMachineName,
1182 DWORD BootAcceptable)
1183 {
1184 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1185 return ERROR_SUCCESS;
1186
1187 // UNIMPLEMENTED;
1188 // return ERROR_CALL_NOT_IMPLEMENTED;
1189 }
1190
1191
1192 /* Function 10 */
1193 DWORD RI_ScSetServiceBitsW(
1194 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1195 DWORD dwServiceBits,
1196 int bSetBitsOn,
1197 int bUpdateImmediately,
1198 wchar_t *lpString)
1199 {
1200 UNIMPLEMENTED;
1201 return ERROR_CALL_NOT_IMPLEMENTED;
1202 }
1203
1204
1205 /* Function 11 */
1206 DWORD RChangeServiceConfigW(
1207 SC_RPC_HANDLE hService,
1208 DWORD dwServiceType,
1209 DWORD dwStartType,
1210 DWORD dwErrorControl,
1211 LPWSTR lpBinaryPathName,
1212 LPWSTR lpLoadOrderGroup,
1213 LPDWORD lpdwTagId,
1214 LPBYTE lpDependencies,
1215 DWORD dwDependSize,
1216 LPWSTR lpServiceStartName,
1217 LPBYTE lpPassword,
1218 DWORD dwPwSize,
1219 LPWSTR lpDisplayName)
1220 {
1221 DWORD dwError = ERROR_SUCCESS;
1222 PSERVICE_HANDLE hSvc;
1223 PSERVICE lpService = NULL;
1224 HKEY hServiceKey = NULL;
1225 LPWSTR lpDisplayNameW = NULL;
1226
1227 DPRINT("RChangeServiceConfigW() called\n");
1228 DPRINT("dwServiceType = %lu\n", dwServiceType);
1229 DPRINT("dwStartType = %lu\n", dwStartType);
1230 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1231 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1232 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1233 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1234
1235 if (ScmShutdown)
1236 return ERROR_SHUTDOWN_IN_PROGRESS;
1237
1238 hSvc = ScmGetServiceFromHandle(hService);
1239 if (hSvc == NULL)
1240 {
1241 DPRINT1("Invalid service handle!\n");
1242 return ERROR_INVALID_HANDLE;
1243 }
1244
1245 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1246 SERVICE_CHANGE_CONFIG))
1247 {
1248 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1249 return ERROR_ACCESS_DENIED;
1250 }
1251
1252 lpService = hSvc->ServiceEntry;
1253 if (lpService == NULL)
1254 {
1255 DPRINT("lpService == NULL!\n");
1256 return ERROR_INVALID_HANDLE;
1257 }
1258
1259 /* Lock the service database exclusively */
1260 ScmLockDatabaseExclusive();
1261
1262 if (lpService->bDeleted)
1263 {
1264 DPRINT("The service has already been marked for delete!\n");
1265 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1266 goto done;
1267 }
1268
1269 /* Open the service key */
1270 dwError = ScmOpenServiceKey(lpService->szServiceName,
1271 KEY_SET_VALUE,
1272 &hServiceKey);
1273 if (dwError != ERROR_SUCCESS)
1274 goto done;
1275
1276 /* Write service data to the registry */
1277 /* Set the display name */
1278 if (lpDisplayName != NULL && *lpDisplayName != 0)
1279 {
1280 RegSetValueExW(hServiceKey,
1281 L"DisplayName",
1282 0,
1283 REG_SZ,
1284 (LPBYTE)lpDisplayName,
1285 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1286
1287 /* Update the display name */
1288 lpDisplayNameW = (LPWSTR)HeapAlloc(GetProcessHeap(),
1289 0,
1290 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1291 if (lpDisplayNameW == NULL)
1292 {
1293 dwError = ERROR_NOT_ENOUGH_MEMORY;
1294 goto done;
1295 }
1296
1297 if (lpService->lpDisplayName != lpService->lpServiceName)
1298 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1299
1300 lpService->lpDisplayName = lpDisplayNameW;
1301 }
1302
1303 if (dwServiceType != SERVICE_NO_CHANGE)
1304 {
1305 /* Set the service type */
1306 dwError = RegSetValueExW(hServiceKey,
1307 L"Type",
1308 0,
1309 REG_DWORD,
1310 (LPBYTE)&dwServiceType,
1311 sizeof(DWORD));
1312 if (dwError != ERROR_SUCCESS)
1313 goto done;
1314
1315 lpService->Status.dwServiceType = dwServiceType;
1316 }
1317
1318 if (dwStartType != SERVICE_NO_CHANGE)
1319 {
1320 /* Set the start value */
1321 dwError = RegSetValueExW(hServiceKey,
1322 L"Start",
1323 0,
1324 REG_DWORD,
1325 (LPBYTE)&dwStartType,
1326 sizeof(DWORD));
1327 if (dwError != ERROR_SUCCESS)
1328 goto done;
1329
1330 lpService->dwStartType = dwStartType;
1331 }
1332
1333 if (dwErrorControl != SERVICE_NO_CHANGE)
1334 {
1335 /* Set the error control value */
1336 dwError = RegSetValueExW(hServiceKey,
1337 L"ErrorControl",
1338 0,
1339 REG_DWORD,
1340 (LPBYTE)&dwErrorControl,
1341 sizeof(DWORD));
1342 if (dwError != ERROR_SUCCESS)
1343 goto done;
1344
1345 lpService->dwErrorControl = dwErrorControl;
1346 }
1347
1348 #if 0
1349 /* FIXME: set the new ImagePath value */
1350
1351 /* Set the image path */
1352 if (dwServiceType & SERVICE_WIN32)
1353 {
1354 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1355 {
1356 dwError = RegSetValueExW(hServiceKey,
1357 L"ImagePath",
1358 0,
1359 REG_EXPAND_SZ,
1360 (LPBYTE)lpBinaryPathName,
1361 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
1362 if (dwError != ERROR_SUCCESS)
1363 goto done;
1364 }
1365 }
1366 else if (dwServiceType & SERVICE_DRIVER)
1367 {
1368 if (lpImagePath != NULL && *lpImagePath != 0)
1369 {
1370 dwError = RegSetValueExW(hServiceKey,
1371 L"ImagePath",
1372 0,
1373 REG_EXPAND_SZ,
1374 (LPBYTE)lpImagePath,
1375 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
1376 if (dwError != ERROR_SUCCESS)
1377 goto done;
1378 }
1379 }
1380 #endif
1381
1382 /* Set the group name */
1383 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1384 {
1385 dwError = RegSetValueExW(hServiceKey,
1386 L"Group",
1387 0,
1388 REG_SZ,
1389 (LPBYTE)lpLoadOrderGroup,
1390 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
1391 if (dwError != ERROR_SUCCESS)
1392 goto done;
1393
1394 dwError = ScmSetServiceGroup(lpService,
1395 lpLoadOrderGroup);
1396 if (dwError != ERROR_SUCCESS)
1397 goto done;
1398 }
1399
1400 if (lpdwTagId != NULL)
1401 {
1402 dwError = ScmAssignNewTag(lpService);
1403 if (dwError != ERROR_SUCCESS)
1404 goto done;
1405
1406 dwError = RegSetValueExW(hServiceKey,
1407 L"Tag",
1408 0,
1409 REG_DWORD,
1410 (LPBYTE)&lpService->dwTag,
1411 sizeof(DWORD));
1412 if (dwError != ERROR_SUCCESS)
1413 goto done;
1414
1415 *lpdwTagId = lpService->dwTag;
1416 }
1417
1418 /* Write dependencies */
1419 if (lpDependencies != NULL && *lpDependencies != 0)
1420 {
1421 dwError = ScmWriteDependencies(hServiceKey,
1422 (LPWSTR)lpDependencies,
1423 dwDependSize);
1424 if (dwError != ERROR_SUCCESS)
1425 goto done;
1426 }
1427
1428 if (lpPassword != NULL)
1429 {
1430 /* FIXME: Write password */
1431 }
1432
1433 done:
1434 if (hServiceKey != NULL)
1435 RegCloseKey(hServiceKey);
1436
1437 /* Unlock the service database */
1438 ScmUnlockDatabase();
1439
1440 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1441
1442 return dwError;
1443 }
1444
1445
1446 /* Create a path suitable for the bootloader out of the full path */
1447 DWORD
1448 ScmConvertToBootPathName(wchar_t *CanonName, wchar_t **RelativeName)
1449 {
1450 DWORD ServiceNameLen, BufferSize, ExpandedLen;
1451 WCHAR Dest;
1452 WCHAR *Expanded;
1453 UNICODE_STRING NtPathName, SystemRoot, LinkTarget;
1454 OBJECT_ATTRIBUTES ObjectAttributes;
1455 NTSTATUS Status;
1456 HANDLE SymbolicLinkHandle;
1457
1458 DPRINT("ScmConvertToBootPathName %S\n", CanonName);
1459
1460 ServiceNameLen = wcslen(CanonName);
1461
1462 /* First check, if it's already good */
1463 if (ServiceNameLen > 12 &&
1464 !_wcsnicmp(L"\\SystemRoot\\", CanonName, 12))
1465 {
1466 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1467 if (*RelativeName == NULL)
1468 {
1469 DPRINT("Error allocating memory for boot driver name!\n");
1470 return ERROR_NOT_ENOUGH_MEMORY;
1471 }
1472
1473 /* Copy it */
1474 wcscpy(*RelativeName, CanonName);
1475
1476 DPRINT("Bootdriver name %S\n", *RelativeName);
1477 return ERROR_SUCCESS;
1478 }
1479
1480 /* If it has %SystemRoot% prefix, substitute it to \System*/
1481 if (ServiceNameLen > 13 &&
1482 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1483 {
1484 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1485 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1486
1487 if (*RelativeName == NULL)
1488 {
1489 DPRINT("Error allocating memory for boot driver name!\n");
1490 return ERROR_NOT_ENOUGH_MEMORY;
1491 }
1492
1493 /* Copy it */
1494 wcscpy(*RelativeName, L"\\SystemRoot\\");
1495 wcscat(*RelativeName, CanonName + 13);
1496
1497 DPRINT("Bootdriver name %S\n", *RelativeName);
1498 return ERROR_SUCCESS;
1499 }
1500
1501 /* Get buffer size needed for expanding env strings */
1502 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1503
1504 if (BufferSize <= 1)
1505 {
1506 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1507 return ERROR_INVALID_ENVIRONMENT;
1508 }
1509
1510 /* Allocate memory, since the size is known now */
1511 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1512 if (!Expanded)
1513 {
1514 DPRINT("Error allocating memory for boot driver name!\n");
1515 return ERROR_NOT_ENOUGH_MEMORY;
1516 }
1517
1518 /* Expand it */
1519 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1520 BufferSize)
1521 {
1522 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1523 LocalFree(Expanded);
1524 return ERROR_NOT_ENOUGH_MEMORY;
1525 }
1526
1527 /* Convert to NY-style path */
1528 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1529 {
1530 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1531 return ERROR_INVALID_ENVIRONMENT;
1532 }
1533
1534 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1535
1536 /* No need to keep the dos-path anymore */
1537 LocalFree(Expanded);
1538
1539 /* Copy it to the allocated place */
1540 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1541 if (!Expanded)
1542 {
1543 DPRINT("Error allocating memory for boot driver name!\n");
1544 return ERROR_NOT_ENOUGH_MEMORY;
1545 }
1546
1547 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1548 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1549 Expanded[ExpandedLen] = 0;
1550
1551 if (ServiceNameLen > ExpandedLen &&
1552 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
1553 {
1554 /* Only \SystemRoot\ is missing */
1555 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1556 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1557 if (*RelativeName == NULL)
1558 {
1559 DPRINT("Error allocating memory for boot driver name!\n");
1560 LocalFree(Expanded);
1561 return ERROR_NOT_ENOUGH_MEMORY;
1562 }
1563
1564 wcscpy(*RelativeName, L"\\SystemRoot\\");
1565 wcscat(*RelativeName, CanonName + ExpandedLen);
1566
1567 RtlFreeUnicodeString(&NtPathName);
1568 return ERROR_SUCCESS;
1569 }
1570
1571 /* The most complex case starts here */
1572 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1573 InitializeObjectAttributes(&ObjectAttributes,
1574 &SystemRoot,
1575 OBJ_CASE_INSENSITIVE,
1576 NULL,
1577 NULL);
1578
1579 /* Open this symlink */
1580 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1581
1582 if (NT_SUCCESS(Status))
1583 {
1584 LinkTarget.Length = 0;
1585 LinkTarget.MaximumLength = 0;
1586
1587 DPRINT("Opened symbolic link object\n");
1588
1589 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1590 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1591 {
1592 /* Check if required buffer size is sane */
1593 if (BufferSize > 0xFFFD)
1594 {
1595 DPRINT("Too large buffer required\n");
1596 *RelativeName = 0;
1597
1598 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1599 LocalFree(Expanded);
1600 return ERROR_NOT_ENOUGH_MEMORY;
1601 }
1602
1603 /* Alloc the string */
1604 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1605 if (!LinkTarget.Buffer)
1606 {
1607 DPRINT("Unable to alloc buffer\n");
1608 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1609 LocalFree(Expanded);
1610 return ERROR_NOT_ENOUGH_MEMORY;
1611 }
1612
1613 /* Do a real query now */
1614 LinkTarget.Length = BufferSize;
1615 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1616
1617 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1618 if (NT_SUCCESS(Status))
1619 {
1620 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1621
1622 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1623 if ((ServiceNameLen > ExpandedLen) &&
1624 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1625 {
1626 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1627 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1628
1629 if (*RelativeName == NULL)
1630 {
1631 DPRINT("Unable to alloc buffer\n");
1632 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1633 LocalFree(Expanded);
1634 RtlFreeUnicodeString(&NtPathName);
1635 return ERROR_NOT_ENOUGH_MEMORY;
1636 }
1637
1638 /* Copy it over, substituting the first part
1639 with SystemRoot */
1640 wcscpy(*RelativeName, L"\\SystemRoot\\");
1641 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1642
1643 /* Cleanup */
1644 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1645 LocalFree(Expanded);
1646 RtlFreeUnicodeString(&NtPathName);
1647
1648 /* Return success */
1649 return ERROR_SUCCESS;
1650 }
1651 else
1652 {
1653 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1654 LocalFree(Expanded);
1655 RtlFreeUnicodeString(&NtPathName);
1656 return ERROR_INVALID_PARAMETER;
1657 }
1658 }
1659 else
1660 {
1661 DPRINT("Error, Status = %08X\n", Status);
1662 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1663 LocalFree(Expanded);
1664 RtlFreeUnicodeString(&NtPathName);
1665 return ERROR_INVALID_PARAMETER;
1666 }
1667 }
1668 else
1669 {
1670 DPRINT("Error, Status = %08X\n", Status);
1671 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1672 LocalFree(Expanded);
1673 RtlFreeUnicodeString(&NtPathName);
1674 return ERROR_INVALID_PARAMETER;
1675 }
1676 }
1677 else
1678 {
1679 DPRINT("Error, Status = %08X\n", Status);
1680 LocalFree(Expanded);
1681 return ERROR_INVALID_PARAMETER;
1682 }
1683
1684 /* Failure */
1685 *RelativeName = NULL;
1686 return ERROR_INVALID_PARAMETER;
1687 }
1688
1689 DWORD
1690 ScmCanonDriverImagePath(DWORD dwStartType,
1691 const wchar_t *lpServiceName,
1692 wchar_t **lpCanonName)
1693 {
1694 DWORD ServiceNameLen, Result;
1695 UNICODE_STRING NtServiceName;
1696 WCHAR *RelativeName;
1697 const WCHAR *SourceName = lpServiceName;
1698
1699 /* Calculate the length of the service's name */
1700 ServiceNameLen = wcslen(lpServiceName);
1701
1702 /* 12 is wcslen(L"\\SystemRoot\\") */
1703 if (ServiceNameLen > 12 &&
1704 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1705 {
1706 /* SystemRoot prefix is already included */
1707
1708 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1709
1710 if (*lpCanonName == NULL)
1711 {
1712 DPRINT("Error allocating memory for canonized service name!\n");
1713 return ERROR_NOT_ENOUGH_MEMORY;
1714 }
1715
1716 /* If it's a boot-time driver, it must be systemroot relative */
1717 if (dwStartType == SERVICE_BOOT_START)
1718 SourceName += 12;
1719
1720 /* Copy it */
1721 wcscpy(*lpCanonName, SourceName);
1722
1723 DPRINT("Canonicalized name %S\n", *lpCanonName);
1724 return NO_ERROR;
1725 }
1726
1727 /* Check if it has %SystemRoot% (len=13) */
1728 if (ServiceNameLen > 13 &&
1729 !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1730 {
1731 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1732 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1733
1734 if (*lpCanonName == NULL)
1735 {
1736 DPRINT("Error allocating memory for canonized service name!\n");
1737 return ERROR_NOT_ENOUGH_MEMORY;
1738 }
1739
1740 /* If it's a boot-time driver, it must be systemroot relative */
1741 if (dwStartType == SERVICE_BOOT_START)
1742 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1743
1744 wcscat(*lpCanonName, lpServiceName + 13);
1745
1746 DPRINT("Canonicalized name %S\n", *lpCanonName);
1747 return NO_ERROR;
1748 }
1749
1750 /* Check if it's a relative path name */
1751 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1752 {
1753 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1754
1755 if (*lpCanonName == NULL)
1756 {
1757 DPRINT("Error allocating memory for canonized service name!\n");
1758 return ERROR_NOT_ENOUGH_MEMORY;
1759 }
1760
1761 /* Just copy it over without changing */
1762 wcscpy(*lpCanonName, lpServiceName);
1763
1764 return NO_ERROR;
1765 }
1766
1767 /* It seems to be a DOS path, convert it */
1768 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1769 {
1770 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
1771 return ERROR_INVALID_PARAMETER;
1772 }
1773
1774 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1775
1776 if (*lpCanonName == NULL)
1777 {
1778 DPRINT("Error allocating memory for canonized service name!\n");
1779 RtlFreeUnicodeString(&NtServiceName);
1780 return ERROR_NOT_ENOUGH_MEMORY;
1781 }
1782
1783 /* Copy the string */
1784 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1785
1786 /* The unicode string is not needed anymore */
1787 RtlFreeUnicodeString(&NtServiceName);
1788
1789 if (dwStartType != SERVICE_BOOT_START)
1790 {
1791 DPRINT("Canonicalized name %S\n", *lpCanonName);
1792 return NO_ERROR;
1793 }
1794
1795 /* The service is boot-started, so must be relative */
1796 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1797 if (Result)
1798 {
1799 /* There is a problem, free name and return */
1800 LocalFree(*lpCanonName);
1801 DPRINT("Error converting named!\n");
1802 return Result;
1803 }
1804
1805 ASSERT(RelativeName);
1806
1807 /* Copy that string */
1808 wcscpy(*lpCanonName, RelativeName + 12);
1809
1810 /* Free the allocated buffer */
1811 LocalFree(RelativeName);
1812
1813 DPRINT("Canonicalized name %S\n", *lpCanonName);
1814
1815 /* Success */
1816 return NO_ERROR;
1817 }
1818
1819
1820 /* Function 12 */
1821 DWORD RCreateServiceW(
1822 SC_RPC_HANDLE hSCManager,
1823 LPCWSTR lpServiceName,
1824 LPCWSTR lpDisplayName,
1825 DWORD dwDesiredAccess,
1826 DWORD dwServiceType,
1827 DWORD dwStartType,
1828 DWORD dwErrorControl,
1829 LPCWSTR lpBinaryPathName,
1830 LPCWSTR lpLoadOrderGroup,
1831 LPDWORD lpdwTagId,
1832 LPBYTE lpDependencies,
1833 DWORD dwDependSize,
1834 LPCWSTR lpServiceStartName,
1835 LPBYTE lpPassword,
1836 DWORD dwPwSize,
1837 LPSC_RPC_HANDLE lpServiceHandle)
1838 {
1839 PMANAGER_HANDLE hManager;
1840 DWORD dwError = ERROR_SUCCESS;
1841 PSERVICE lpService = NULL;
1842 SC_HANDLE hServiceHandle = NULL;
1843 LPWSTR lpImagePath = NULL;
1844 HKEY hServiceKey = NULL;
1845 LPWSTR lpObjectName;
1846
1847 DPRINT("RCreateServiceW() called\n");
1848 DPRINT("lpServiceName = %S\n", lpServiceName);
1849 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1850 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1851 DPRINT("dwServiceType = %lu\n", dwServiceType);
1852 DPRINT("dwStartType = %lu\n", dwStartType);
1853 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1854 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1855 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1856
1857 if (ScmShutdown)
1858 return ERROR_SHUTDOWN_IN_PROGRESS;
1859
1860 hManager = ScmGetServiceManagerFromHandle(hSCManager);
1861 if (hManager == NULL)
1862 {
1863 DPRINT1("Invalid service manager handle!\n");
1864 return ERROR_INVALID_HANDLE;
1865 }
1866
1867 /* Check access rights */
1868 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1869 SC_MANAGER_CREATE_SERVICE))
1870 {
1871 DPRINT("Insufficient access rights! 0x%lx\n",
1872 hManager->Handle.DesiredAccess);
1873 return ERROR_ACCESS_DENIED;
1874 }
1875
1876 if (wcslen(lpServiceName) == 0)
1877 {
1878 return ERROR_INVALID_NAME;
1879 }
1880
1881 if (wcslen(lpBinaryPathName) == 0)
1882 {
1883 return ERROR_INVALID_PARAMETER;
1884 }
1885
1886 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1887 (lpServiceStartName))
1888 {
1889 return ERROR_INVALID_PARAMETER;
1890 }
1891
1892 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
1893 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
1894 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
1895 {
1896 return ERROR_INVALID_PARAMETER;
1897 }
1898
1899 if (dwStartType > SERVICE_DISABLED)
1900 {
1901 return ERROR_INVALID_PARAMETER;
1902 }
1903
1904 /* Lock the service database exclusively */
1905 ScmLockDatabaseExclusive();
1906
1907 lpService = ScmGetServiceEntryByName(lpServiceName);
1908 if (lpService)
1909 {
1910 /* Unlock the service database */
1911 ScmUnlockDatabase();
1912
1913 /* check if it is marked for deletion */
1914 if (lpService->bDeleted)
1915 return ERROR_SERVICE_MARKED_FOR_DELETE;
1916 /* Return Error exist */
1917 return ERROR_SERVICE_EXISTS;
1918 }
1919
1920 if (lpDisplayName != NULL &&
1921 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
1922 {
1923 /* Unlock the service database */
1924 ScmUnlockDatabase();
1925
1926 return ERROR_DUPLICATE_SERVICE_NAME;
1927 }
1928
1929 if (dwServiceType & SERVICE_DRIVER)
1930 {
1931 dwError = ScmCanonDriverImagePath(dwStartType,
1932 lpBinaryPathName,
1933 &lpImagePath);
1934 if (dwError != ERROR_SUCCESS)
1935 goto done;
1936 }
1937 else
1938 {
1939 if (dwStartType == SERVICE_BOOT_START ||
1940 dwStartType == SERVICE_SYSTEM_START)
1941 {
1942 /* Unlock the service database */
1943 ScmUnlockDatabase();
1944
1945 return ERROR_INVALID_PARAMETER;
1946 }
1947 }
1948
1949 /* Allocate a new service entry */
1950 dwError = ScmCreateNewServiceRecord(lpServiceName,
1951 &lpService);
1952 if (dwError != ERROR_SUCCESS)
1953 goto done;
1954
1955 /* Fill the new service entry */
1956 lpService->Status.dwServiceType = dwServiceType;
1957 lpService->dwStartType = dwStartType;
1958 lpService->dwErrorControl = dwErrorControl;
1959
1960 /* Fill the display name */
1961 if (lpDisplayName != NULL &&
1962 *lpDisplayName != 0 &&
1963 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
1964 {
1965 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
1966 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1967 if (lpService->lpDisplayName == NULL)
1968 {
1969 dwError = ERROR_NOT_ENOUGH_MEMORY;
1970 goto done;
1971 }
1972 wcscpy(lpService->lpDisplayName, lpDisplayName);
1973 }
1974
1975 /* Assign the service to a group */
1976 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1977 {
1978 dwError = ScmSetServiceGroup(lpService,
1979 lpLoadOrderGroup);
1980 if (dwError != ERROR_SUCCESS)
1981 goto done;
1982 }
1983
1984 /* Assign a new tag */
1985 if (lpdwTagId != NULL)
1986 {
1987 dwError = ScmAssignNewTag(lpService);
1988 if (dwError != ERROR_SUCCESS)
1989 goto done;
1990 }
1991
1992 /* Write service data to the registry */
1993 /* Create the service key */
1994 dwError = ScmCreateServiceKey(lpServiceName,
1995 KEY_WRITE,
1996 &hServiceKey);
1997 if (dwError != ERROR_SUCCESS)
1998 goto done;
1999
2000 /* Set the display name */
2001 if (lpDisplayName != NULL && *lpDisplayName != 0)
2002 {
2003 RegSetValueExW(hServiceKey,
2004 L"DisplayName",
2005 0,
2006 REG_SZ,
2007 (LPBYTE)lpDisplayName,
2008 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2009 }
2010
2011 /* Set the service type */
2012 dwError = RegSetValueExW(hServiceKey,
2013 L"Type",
2014 0,
2015 REG_DWORD,
2016 (LPBYTE)&dwServiceType,
2017 sizeof(DWORD));
2018 if (dwError != ERROR_SUCCESS)
2019 goto done;
2020
2021 /* Set the start value */
2022 dwError = RegSetValueExW(hServiceKey,
2023 L"Start",
2024 0,
2025 REG_DWORD,
2026 (LPBYTE)&dwStartType,
2027 sizeof(DWORD));
2028 if (dwError != ERROR_SUCCESS)
2029 goto done;
2030
2031 /* Set the error control value */
2032 dwError = RegSetValueExW(hServiceKey,
2033 L"ErrorControl",
2034 0,
2035 REG_DWORD,
2036 (LPBYTE)&dwErrorControl,
2037 sizeof(DWORD));
2038 if (dwError != ERROR_SUCCESS)
2039 goto done;
2040
2041 /* Set the image path */
2042 if (dwServiceType & SERVICE_WIN32)
2043 {
2044 dwError = RegSetValueExW(hServiceKey,
2045 L"ImagePath",
2046 0,
2047 REG_EXPAND_SZ,
2048 (LPBYTE)lpBinaryPathName,
2049 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
2050 if (dwError != ERROR_SUCCESS)
2051 goto done;
2052 }
2053 else if (dwServiceType & SERVICE_DRIVER)
2054 {
2055 dwError = RegSetValueExW(hServiceKey,
2056 L"ImagePath",
2057 0,
2058 REG_EXPAND_SZ,
2059 (LPBYTE)lpImagePath,
2060 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2061 if (dwError != ERROR_SUCCESS)
2062 goto done;
2063 }
2064
2065 /* Set the group name */
2066 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2067 {
2068 dwError = RegSetValueExW(hServiceKey,
2069 L"Group",
2070 0,
2071 REG_SZ,
2072 (LPBYTE)lpLoadOrderGroup,
2073 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
2074 if (dwError != ERROR_SUCCESS)
2075 goto done;
2076 }
2077
2078 if (lpdwTagId != NULL)
2079 {
2080 dwError = RegSetValueExW(hServiceKey,
2081 L"Tag",
2082 0,
2083 REG_DWORD,
2084 (LPBYTE)&lpService->dwTag,
2085 sizeof(DWORD));
2086 if (dwError != ERROR_SUCCESS)
2087 goto done;
2088 }
2089
2090 /* Write dependencies */
2091 if (lpDependencies != NULL && *lpDependencies != 0)
2092 {
2093 dwError = ScmWriteDependencies(hServiceKey,
2094 (LPWSTR)lpDependencies,
2095 dwDependSize);
2096 if (dwError != ERROR_SUCCESS)
2097 goto done;
2098 }
2099
2100 /* Write service start name */
2101 if (dwServiceType & SERVICE_WIN32)
2102 {
2103 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2104 dwError = RegSetValueExW(hServiceKey,
2105 L"ObjectName",
2106 0,
2107 REG_SZ,
2108 (LPBYTE)lpObjectName,
2109 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
2110 if (dwError != ERROR_SUCCESS)
2111 goto done;
2112 }
2113
2114 if (lpPassword != NULL)
2115 {
2116 /* FIXME: Write password */
2117 }
2118
2119 dwError = ScmCreateServiceHandle(lpService,
2120 &hServiceHandle);
2121 if (dwError != ERROR_SUCCESS)
2122 goto done;
2123
2124 dwError = ScmCheckAccess(hServiceHandle,
2125 dwDesiredAccess);
2126 if (dwError != ERROR_SUCCESS)
2127 goto done;
2128
2129 lpService->dwRefCount = 1;
2130 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2131
2132 done:;
2133 /* Unlock the service database */
2134 ScmUnlockDatabase();
2135
2136 if (hServiceKey != NULL)
2137 RegCloseKey(hServiceKey);
2138
2139 if (dwError == ERROR_SUCCESS)
2140 {
2141 DPRINT("hService %p\n", hServiceHandle);
2142 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2143
2144 if (lpdwTagId != NULL)
2145 *lpdwTagId = lpService->dwTag;
2146 }
2147 else
2148 {
2149 /* Release the display name buffer */
2150 if (lpService->lpServiceName != NULL)
2151 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2152
2153 if (hServiceHandle)
2154 {
2155 /* Remove the service handle */
2156 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2157 }
2158
2159 if (lpService != NULL)
2160 {
2161 /* FIXME: remove the service entry */
2162 }
2163 }
2164
2165 if (lpImagePath != NULL)
2166 HeapFree(GetProcessHeap(), 0, lpImagePath);
2167
2168 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2169
2170 return dwError;
2171 }
2172
2173
2174 /* Function 13 */
2175 DWORD REnumDependentServicesW(
2176 SC_RPC_HANDLE hService,
2177 DWORD dwServiceState,
2178 LPBYTE lpServices,
2179 DWORD cbBufSize,
2180 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2181 LPBOUNDED_DWORD_256K lpServicesReturned)
2182 {
2183 DWORD dwError = ERROR_SUCCESS;
2184 DWORD dwServicesReturned = 0;
2185 DWORD dwServiceCount;
2186 HKEY hServicesKey = NULL;
2187 PSERVICE_HANDLE hSvc;
2188 PSERVICE lpService = NULL;
2189 PSERVICE *lpServicesArray = NULL;
2190 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2191 LPWSTR lpStr;
2192
2193 *pcbBytesNeeded = 0;
2194 *lpServicesReturned = 0;
2195
2196 DPRINT("REnumDependentServicesW() called\n");
2197
2198 hSvc = ScmGetServiceFromHandle(hService);
2199 if (hSvc == NULL)
2200 {
2201 DPRINT1("Invalid service handle!\n");
2202 return ERROR_INVALID_HANDLE;
2203 }
2204
2205 lpService = hSvc->ServiceEntry;
2206
2207 /* Check access rights */
2208 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2209 SC_MANAGER_ENUMERATE_SERVICE))
2210 {
2211 DPRINT("Insufficient access rights! 0x%lx\n",
2212 hSvc->Handle.DesiredAccess);
2213 return ERROR_ACCESS_DENIED;
2214 }
2215
2216 /* Open the Services Reg key */
2217 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2218 L"System\\CurrentControlSet\\Services",
2219 0,
2220 KEY_READ,
2221 &hServicesKey);
2222 if (dwError != ERROR_SUCCESS)
2223 return dwError;
2224
2225 /* First determine the bytes needed and get the number of dependent services */
2226 dwError = Int_EnumDependentServicesW(hServicesKey,
2227 lpService,
2228 dwServiceState,
2229 NULL,
2230 pcbBytesNeeded,
2231 &dwServicesReturned);
2232 if (dwError != ERROR_SUCCESS)
2233 goto Done;
2234
2235 /* If buffer size is less than the bytes needed or pointer is null */
2236 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2237 {
2238 dwError = ERROR_MORE_DATA;
2239 goto Done;
2240 }
2241
2242 /* Allocate memory for array of service pointers */
2243 lpServicesArray = HeapAlloc(GetProcessHeap(),
2244 0,
2245 (dwServicesReturned + 1) * sizeof(PSERVICE));
2246 if (!lpServicesArray)
2247 {
2248 DPRINT("Could not allocate a buffer!!\n");
2249 dwError = ERROR_NOT_ENOUGH_MEMORY;
2250 goto Done;
2251 }
2252
2253 dwServicesReturned = 0;
2254 *pcbBytesNeeded = 0;
2255
2256 dwError = Int_EnumDependentServicesW(hServicesKey,
2257 lpService,
2258 dwServiceState,
2259 lpServicesArray,
2260 pcbBytesNeeded,
2261 &dwServicesReturned);
2262 if (dwError != ERROR_SUCCESS)
2263 {
2264 goto Done;
2265 }
2266
2267 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2268 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2269
2270 /* Copy EnumDepenedentService to Buffer */
2271 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2272 {
2273 lpService = lpServicesArray[dwServiceCount];
2274
2275 /* Copy status info */
2276 memcpy(&lpServicesPtr->ServiceStatus,
2277 &lpService->Status,
2278 sizeof(SERVICE_STATUS));
2279
2280 /* Copy display name */
2281 wcscpy(lpStr, lpService->lpDisplayName);
2282 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2283 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2284
2285 /* Copy service name */
2286 wcscpy(lpStr, lpService->lpServiceName);
2287 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2288 lpStr += (wcslen(lpService->lpServiceName) + 1);
2289
2290 lpServicesPtr ++;
2291 }
2292
2293 *lpServicesReturned = dwServicesReturned;
2294
2295 Done:
2296 if (lpServicesArray != NULL)
2297 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2298
2299 RegCloseKey(hServicesKey);
2300
2301 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2302
2303 return dwError;
2304 }
2305
2306
2307 /* Function 14 */
2308 DWORD REnumServicesStatusW(
2309 SC_RPC_HANDLE hSCManager,
2310 DWORD dwServiceType,
2311 DWORD dwServiceState,
2312 LPBYTE lpBuffer,
2313 DWORD dwBufSize,
2314 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2315 LPBOUNDED_DWORD_256K lpServicesReturned,
2316 LPBOUNDED_DWORD_256K lpResumeHandle)
2317 {
2318 PMANAGER_HANDLE hManager;
2319 PSERVICE lpService;
2320 DWORD dwError = ERROR_SUCCESS;
2321 PLIST_ENTRY ServiceEntry;
2322 PSERVICE CurrentService;
2323 DWORD dwState;
2324 DWORD dwRequiredSize;
2325 DWORD dwServiceCount;
2326 DWORD dwSize;
2327 DWORD dwLastResumeCount = 0;
2328 LPENUM_SERVICE_STATUSW lpStatusPtr;
2329 LPWSTR lpStringPtr;
2330
2331 DPRINT("REnumServicesStatusW() called\n");
2332
2333 if (ScmShutdown)
2334 return ERROR_SHUTDOWN_IN_PROGRESS;
2335
2336 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2337 if (hManager == NULL)
2338 {
2339 DPRINT1("Invalid service manager handle!\n");
2340 return ERROR_INVALID_HANDLE;
2341 }
2342
2343
2344 *pcbBytesNeeded = 0;
2345 *lpServicesReturned = 0;
2346
2347 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2348 {
2349 DPRINT("Not a valid Service Type!\n");
2350 return ERROR_INVALID_PARAMETER;
2351 }
2352
2353 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2354 {
2355 DPRINT("Not a valid Service State!\n");
2356 return ERROR_INVALID_PARAMETER;
2357 }
2358
2359 /* Check access rights */
2360 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2361 SC_MANAGER_ENUMERATE_SERVICE))
2362 {
2363 DPRINT("Insufficient access rights! 0x%lx\n",
2364 hManager->Handle.DesiredAccess);
2365 return ERROR_ACCESS_DENIED;
2366 }
2367
2368 if (lpResumeHandle)
2369 dwLastResumeCount = *lpResumeHandle;
2370
2371 /* Lock the service database shared */
2372 ScmLockDatabaseShared();
2373
2374 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2375 if (lpService == NULL)
2376 {
2377 dwError = ERROR_SUCCESS;
2378 goto Done;
2379 }
2380
2381 dwRequiredSize = 0;
2382 dwServiceCount = 0;
2383
2384 for (ServiceEntry = &lpService->ServiceListEntry;
2385 ServiceEntry != &ServiceListHead;
2386 ServiceEntry = ServiceEntry->Flink)
2387 {
2388 CurrentService = CONTAINING_RECORD(ServiceEntry,
2389 SERVICE,
2390 ServiceListEntry);
2391
2392 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2393 continue;
2394
2395 dwState = SERVICE_ACTIVE;
2396 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2397 dwState = SERVICE_INACTIVE;
2398
2399 if ((dwState & dwServiceState) == 0)
2400 continue;
2401
2402 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2403 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2404 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2405
2406 if (dwRequiredSize + dwSize > dwBufSize)
2407 {
2408 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2409 break;
2410 }
2411
2412 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2413 dwRequiredSize += dwSize;
2414 dwServiceCount++;
2415 dwLastResumeCount = CurrentService->dwResumeCount;
2416 }
2417
2418 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2419 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2420
2421 for (;
2422 ServiceEntry != &ServiceListHead;
2423 ServiceEntry = ServiceEntry->Flink)
2424 {
2425 CurrentService = CONTAINING_RECORD(ServiceEntry,
2426 SERVICE,
2427 ServiceListEntry);
2428
2429 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2430 continue;
2431
2432 dwState = SERVICE_ACTIVE;
2433 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2434 dwState = SERVICE_INACTIVE;
2435
2436 if ((dwState & dwServiceState) == 0)
2437 continue;
2438
2439 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2440 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2441 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2442
2443 dwError = ERROR_MORE_DATA;
2444 }
2445
2446 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2447
2448 if (lpResumeHandle)
2449 *lpResumeHandle = dwLastResumeCount;
2450
2451 *lpServicesReturned = dwServiceCount;
2452 *pcbBytesNeeded = dwRequiredSize;
2453
2454 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2455 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2456 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2457
2458 dwRequiredSize = 0;
2459 for (ServiceEntry = &lpService->ServiceListEntry;
2460 ServiceEntry != &ServiceListHead;
2461 ServiceEntry = ServiceEntry->Flink)
2462 {
2463 CurrentService = CONTAINING_RECORD(ServiceEntry,
2464 SERVICE,
2465 ServiceListEntry);
2466
2467 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2468 continue;
2469
2470 dwState = SERVICE_ACTIVE;
2471 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2472 dwState = SERVICE_INACTIVE;
2473
2474 if ((dwState & dwServiceState) == 0)
2475 continue;
2476
2477 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2478 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2479 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2480
2481 if (dwRequiredSize + dwSize > dwBufSize)
2482 break;
2483
2484 /* Copy the service name */
2485 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2486 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2487 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2488
2489 /* Copy the display name */
2490 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2491 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2492 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2493
2494 /* Copy the status information */
2495 memcpy(&lpStatusPtr->ServiceStatus,
2496 &CurrentService->Status,
2497 sizeof(SERVICE_STATUS));
2498
2499 lpStatusPtr++;
2500 dwRequiredSize += dwSize;
2501 }
2502
2503 if (dwError == 0)
2504 {
2505 *pcbBytesNeeded = 0;
2506 if (lpResumeHandle) *lpResumeHandle = 0;
2507 }
2508
2509 Done:;
2510 /* Unlock the service database */
2511 ScmUnlockDatabase();
2512
2513 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2514
2515 return dwError;
2516 }
2517
2518
2519 /* Function 15 */
2520 DWORD ROpenSCManagerW(
2521 LPWSTR lpMachineName,
2522 LPWSTR lpDatabaseName,
2523 DWORD dwDesiredAccess,
2524 LPSC_RPC_HANDLE lpScHandle)
2525 {
2526 DWORD dwError;
2527 SC_HANDLE hHandle;
2528
2529 DPRINT("ROpenSCManagerW() called\n");
2530 DPRINT("lpMachineName = %p\n", lpMachineName);
2531 DPRINT("lpMachineName: %S\n", lpMachineName);
2532 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2533 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2534 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2535
2536 if (ScmShutdown)
2537 return ERROR_SHUTDOWN_IN_PROGRESS;
2538
2539 if (!lpScHandle)
2540 return ERROR_INVALID_PARAMETER;
2541
2542 dwError = ScmCreateManagerHandle(lpDatabaseName,
2543 &hHandle);
2544 if (dwError != ERROR_SUCCESS)
2545 {
2546 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2547 return dwError;
2548 }
2549
2550 /* Check the desired access */
2551 dwError = ScmCheckAccess(hHandle,
2552 dwDesiredAccess | SC_MANAGER_CONNECT);
2553 if (dwError != ERROR_SUCCESS)
2554 {
2555 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2556 HeapFree(GetProcessHeap(), 0, hHandle);
2557 return dwError;
2558 }
2559
2560 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2561 DPRINT("*hScm = %p\n", *lpScHandle);
2562
2563 DPRINT("ROpenSCManagerW() done\n");
2564
2565 return ERROR_SUCCESS;
2566 }
2567
2568
2569 /* Function 16 */
2570 DWORD ROpenServiceW(
2571 SC_RPC_HANDLE hSCManager,
2572 LPWSTR lpServiceName,
2573 DWORD dwDesiredAccess,
2574 LPSC_RPC_HANDLE lpServiceHandle)
2575 {
2576 PSERVICE lpService;
2577 PMANAGER_HANDLE hManager;
2578 SC_HANDLE hHandle;
2579 DWORD dwError = ERROR_SUCCESS;
2580
2581 DPRINT("ROpenServiceW() called\n");
2582 DPRINT("hSCManager = %p\n", hSCManager);
2583 DPRINT("lpServiceName = %p\n", lpServiceName);
2584 DPRINT("lpServiceName: %S\n", lpServiceName);
2585 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2586
2587 if (ScmShutdown)
2588 return ERROR_SHUTDOWN_IN_PROGRESS;
2589
2590 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2591 if (hManager == NULL)
2592 {
2593 DPRINT1("Invalid service manager handle!\n");
2594 return ERROR_INVALID_HANDLE;
2595 }
2596
2597 if (!lpServiceHandle)
2598 return ERROR_INVALID_PARAMETER;
2599
2600 if (!lpServiceName)
2601 return ERROR_INVALID_ADDRESS;
2602
2603 /* Lock the service database exclusive */
2604 ScmLockDatabaseExclusive();
2605
2606 /* Get service database entry */
2607 lpService = ScmGetServiceEntryByName(lpServiceName);
2608 if (lpService == NULL)
2609 {
2610 DPRINT("Could not find a service!\n");
2611 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2612 goto Done;
2613 }
2614
2615 /* Create a service handle */
2616 dwError = ScmCreateServiceHandle(lpService,
2617 &hHandle);
2618 if (dwError != ERROR_SUCCESS)
2619 {
2620 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2621 goto Done;
2622 }
2623
2624 /* Check the desired access */
2625 dwError = ScmCheckAccess(hHandle,
2626 dwDesiredAccess);
2627 if (dwError != ERROR_SUCCESS)
2628 {
2629 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2630 HeapFree(GetProcessHeap(), 0, hHandle);
2631 goto Done;
2632 }
2633
2634 lpService->dwRefCount++;
2635 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2636
2637 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2638 DPRINT("*hService = %p\n", *lpServiceHandle);
2639
2640 Done:;
2641 /* Unlock the service database */
2642 ScmUnlockDatabase();
2643
2644 DPRINT("ROpenServiceW() done\n");
2645
2646 return dwError;
2647 }
2648
2649
2650 /* Function 17 */
2651 DWORD RQueryServiceConfigW(
2652 SC_RPC_HANDLE hService,
2653 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2654 DWORD cbBufSize,
2655 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2656 {
2657 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2658 DWORD dwError = ERROR_SUCCESS;
2659 PSERVICE_HANDLE hSvc;
2660 PSERVICE lpService = NULL;
2661 HKEY hServiceKey = NULL;
2662 LPWSTR lpImagePath = NULL;
2663 LPWSTR lpServiceStartName = NULL;
2664 LPWSTR lpDependencies = NULL;
2665 DWORD dwDependenciesLength = 0;
2666 DWORD dwRequiredSize;
2667 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2668 WCHAR lpEmptyString[] = {0,0};
2669 LPWSTR lpStr;
2670
2671 DPRINT("RQueryServiceConfigW() called\n");
2672
2673 if (ScmShutdown)
2674 return ERROR_SHUTDOWN_IN_PROGRESS;
2675
2676 hSvc = ScmGetServiceFromHandle(hService);
2677 if (hSvc == NULL)
2678 {
2679 DPRINT1("Invalid service handle!\n");
2680 return ERROR_INVALID_HANDLE;
2681 }
2682
2683 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2684 SERVICE_QUERY_CONFIG))
2685 {
2686 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2687 return ERROR_ACCESS_DENIED;
2688 }
2689
2690 lpService = hSvc->ServiceEntry;
2691 if (lpService == NULL)
2692 {
2693 DPRINT("lpService == NULL!\n");
2694 return ERROR_INVALID_HANDLE;
2695 }
2696
2697 /* Lock the service database shared */
2698 ScmLockDatabaseShared();
2699
2700 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2701 KEY_READ,
2702 &hServiceKey);
2703 if (dwError != ERROR_SUCCESS)
2704 goto Done;
2705
2706 /* Read the image path */
2707 dwError = ScmReadString(hServiceKey,
2708 L"ImagePath",
2709 &lpImagePath);
2710 if (dwError != ERROR_SUCCESS)
2711 goto Done;
2712
2713 /* Read the service start name */
2714 ScmReadString(hServiceKey,
2715 L"ObjectName",
2716 &lpServiceStartName);
2717
2718 /* Read the dependencies */
2719 ScmReadDependencies(hServiceKey,
2720 &lpDependencies,
2721 &dwDependenciesLength);
2722
2723 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2724
2725 if (lpImagePath != NULL)
2726 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2727 else
2728 dwRequiredSize += 2 * sizeof(WCHAR);
2729
2730 if (lpService->lpGroup != NULL)
2731 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2732 else
2733 dwRequiredSize += 2 * sizeof(WCHAR);
2734
2735 if (lpDependencies != NULL)
2736 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2737 else
2738 dwRequiredSize += 2 * sizeof(WCHAR);
2739
2740 if (lpServiceStartName != NULL)
2741 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2742 else
2743 dwRequiredSize += 2 * sizeof(WCHAR);
2744
2745 if (lpService->lpDisplayName != NULL)
2746 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2747 else
2748 dwRequiredSize += 2 * sizeof(WCHAR);
2749
2750 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2751 {
2752 dwError = ERROR_INSUFFICIENT_BUFFER;
2753 }
2754 else
2755 {
2756 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2757 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2758 lpConfig->dwStartType = lpService->dwStartType;
2759 lpConfig->dwErrorControl = lpService->dwErrorControl;
2760 lpConfig->dwTagId = lpService->dwTag;
2761
2762 lpStr = (LPWSTR)(lpConfig + 1);
2763
2764 /* Append the image path */
2765 if (lpImagePath != NULL)
2766 {
2767 wcscpy(lpStr, lpImagePath);
2768 }
2769 else
2770 {
2771 wcscpy(lpStr, lpEmptyString);
2772 }
2773
2774 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2775 lpStr += (wcslen(lpStr) + 1);
2776
2777 /* Append the group name */
2778 if (lpService->lpGroup != NULL)
2779 {
2780 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2781 }
2782 else
2783 {
2784 wcscpy(lpStr, lpEmptyString);
2785 }
2786
2787 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2788 lpStr += (wcslen(lpStr) + 1);
2789
2790 /* Append Dependencies */
2791 if (lpDependencies != NULL)
2792 {
2793 memcpy(lpStr,
2794 lpDependencies,
2795 dwDependenciesLength * sizeof(WCHAR));
2796 }
2797 else
2798 {
2799 wcscpy(lpStr, lpEmptyString);
2800 }
2801
2802 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2803 if (lpDependencies != NULL)
2804 lpStr += dwDependenciesLength * sizeof(WCHAR);
2805 else
2806 lpStr += (wcslen(lpStr) + 1);
2807
2808 /* Append the service start name */
2809 if (lpServiceStartName != NULL)
2810 {
2811 wcscpy(lpStr, lpServiceStartName);
2812 }
2813 else
2814 {
2815 wcscpy(lpStr, lpEmptyString);
2816 }
2817
2818 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2819 lpStr += (wcslen(lpStr) + 1);
2820
2821 /* Append the display name */
2822 if (lpService->lpDisplayName != NULL)
2823 {
2824 wcscpy(lpStr, lpService->lpDisplayName);
2825 }
2826 else
2827 {
2828 wcscpy(lpStr, lpEmptyString);
2829 }
2830
2831 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2832 }
2833
2834 if (pcbBytesNeeded != NULL)
2835 *pcbBytesNeeded = dwRequiredSize;
2836
2837 Done:;
2838 /* Unlock the service database */
2839 ScmUnlockDatabase();
2840
2841 if (lpImagePath != NULL)
2842 HeapFree(GetProcessHeap(), 0, lpImagePath);
2843
2844 if (lpServiceStartName != NULL)
2845 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2846
2847 if (lpDependencies != NULL)
2848 HeapFree(GetProcessHeap(), 0, lpDependencies);
2849
2850 if (hServiceKey != NULL)
2851 RegCloseKey(hServiceKey);
2852
2853 DPRINT("RQueryServiceConfigW() done\n");
2854
2855 return dwError;
2856 }
2857
2858
2859 /* Function 18 */
2860 DWORD RQueryServiceLockStatusW(
2861 SC_RPC_HANDLE hSCManager,
2862 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2863 DWORD cbBufSize,
2864 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2865 {
2866 UNIMPLEMENTED;
2867 return ERROR_CALL_NOT_IMPLEMENTED;
2868 }
2869
2870
2871 /* Function 19 */
2872 DWORD RStartServiceW(
2873 SC_RPC_HANDLE hService,
2874 DWORD argc,
2875 LPSTRING_PTRSW argv)
2876 {
2877 DWORD dwError = ERROR_SUCCESS;
2878 PSERVICE_HANDLE hSvc;
2879 PSERVICE lpService = NULL;
2880
2881 DPRINT("RStartServiceW() called\n");
2882
2883 if (ScmShutdown)
2884 return ERROR_SHUTDOWN_IN_PROGRESS;
2885
2886 hSvc = ScmGetServiceFromHandle(hService);
2887 if (hSvc == NULL)
2888 {
2889 DPRINT1("Invalid service handle!\n");
2890 return ERROR_INVALID_HANDLE;
2891 }
2892
2893 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2894 SERVICE_START))
2895 {
2896 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2897 return ERROR_ACCESS_DENIED;
2898 }
2899
2900 lpService = hSvc->ServiceEntry;
2901 if (lpService == NULL)
2902 {
2903 DPRINT("lpService == NULL!\n");
2904 return ERROR_INVALID_HANDLE;
2905 }
2906
2907 if (lpService->dwStartType == SERVICE_DISABLED)
2908 return ERROR_SERVICE_DISABLED;
2909
2910 if (lpService->bDeleted)
2911 return ERROR_SERVICE_MARKED_FOR_DELETE;
2912
2913 if (argv) {
2914 UNIMPLEMENTED;
2915 argv = NULL;
2916 }
2917
2918 /* Start the service */
2919 dwError = ScmStartService(lpService, argc, (LPWSTR *)argv);
2920
2921 return dwError;
2922 }
2923
2924
2925 /* Function 20 */
2926 DWORD RGetServiceDisplayNameW(
2927 SC_RPC_HANDLE hSCManager,
2928 LPCWSTR lpServiceName,
2929 LPWSTR lpDisplayName,
2930 DWORD *lpcchBuffer)
2931 {
2932 // PMANAGER_HANDLE hManager;
2933 PSERVICE lpService;
2934 DWORD dwLength;
2935 DWORD dwError;
2936
2937 DPRINT("RGetServiceDisplayNameW() called\n");
2938 DPRINT("hSCManager = %p\n", hSCManager);
2939 DPRINT("lpServiceName: %S\n", lpServiceName);
2940 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2941 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2942
2943 // hManager = (PMANAGER_HANDLE)hSCManager;
2944 // if (hManager->Handle.Tag != MANAGER_TAG)
2945 // {
2946 // DPRINT("Invalid manager handle!\n");
2947 // return ERROR_INVALID_HANDLE;
2948 // }
2949
2950 /* Get service database entry */
2951 lpService = ScmGetServiceEntryByName(lpServiceName);
2952 if (lpService == NULL)
2953 {
2954 DPRINT("Could not find a service!\n");
2955
2956 /* If the service could not be found and lpcchBuffer is less than 2, windows
2957 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2958 if (*lpcchBuffer < 2)
2959 {
2960 *lpcchBuffer = 2;
2961 if (lpDisplayName != NULL)
2962 {
2963 *lpDisplayName = '\0';
2964 }
2965 }
2966
2967 return ERROR_SERVICE_DOES_NOT_EXIST;
2968 }
2969
2970 if (!lpService->lpDisplayName)
2971 {
2972 dwLength = wcslen(lpService->lpServiceName);
2973
2974 if (lpDisplayName != NULL &&
2975 *lpcchBuffer > dwLength)
2976 {
2977 wcscpy(lpDisplayName, lpService->lpServiceName);
2978 }
2979 }
2980 else
2981 {
2982 dwLength = wcslen(lpService->lpDisplayName);
2983
2984 if (lpDisplayName != NULL &&
2985 *lpcchBuffer > dwLength)
2986 {
2987 wcscpy(lpDisplayName, lpService->lpDisplayName);
2988 }
2989 }
2990
2991 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
2992
2993 *lpcchBuffer = dwLength;
2994
2995 return dwError;
2996 }
2997
2998
2999 /* Function 21 */
3000 DWORD RGetServiceKeyNameW(
3001 SC_RPC_HANDLE hSCManager,
3002 LPCWSTR lpDisplayName,
3003 LPWSTR lpServiceName,
3004 DWORD *lpcchBuffer)
3005 {
3006 // PMANAGER_HANDLE hManager;
3007 PSERVICE lpService;
3008 DWORD dwLength;
3009 DWORD dwError;
3010
3011 DPRINT("RGetServiceKeyNameW() called\n");
3012 DPRINT("hSCManager = %p\n", hSCManager);
3013 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3014 DPRINT("lpServiceName: %p\n", lpServiceName);
3015 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3016
3017 // hManager = (PMANAGER_HANDLE)hSCManager;
3018 // if (hManager->Handle.Tag != MANAGER_TAG)
3019 // {
3020 // DPRINT("Invalid manager handle!\n");
3021 // return ERROR_INVALID_HANDLE;
3022 // }
3023
3024 /* Get service database entry */
3025 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3026 if (lpService == NULL)
3027 {
3028 DPRINT("Could not find a service!\n");
3029
3030 /* If the service could not be found and lpcchBuffer is less than 2, windows
3031 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3032 if (*lpcchBuffer < 2)
3033 {
3034 *lpcchBuffer = 2;
3035 if (lpServiceName != NULL)
3036 {
3037 *lpServiceName = '\0';
3038 }
3039 }
3040
3041 return ERROR_SERVICE_DOES_NOT_EXIST;
3042 }
3043
3044 dwLength = wcslen(lpService->lpServiceName);
3045
3046 if (lpServiceName != NULL &&
3047 *lpcchBuffer > dwLength)
3048 {
3049 wcscpy(lpServiceName, lpService->lpServiceName);
3050 *lpcchBuffer = dwLength;
3051 return ERROR_SUCCESS;
3052 }
3053
3054 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3055
3056 *lpcchBuffer = dwLength;
3057
3058 return dwError;
3059 }
3060
3061
3062 /* Function 22 */
3063 DWORD RI_ScSetServiceBitsA(
3064 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3065 DWORD dwServiceBits,
3066 int bSetBitsOn,
3067 int bUpdateImmediately,
3068 char *lpString)
3069 {
3070 UNIMPLEMENTED;
3071 return ERROR_CALL_NOT_IMPLEMENTED;
3072 }
3073
3074
3075 /* Function 23 */
3076 DWORD RChangeServiceConfigA(
3077 SC_RPC_HANDLE hService,
3078 DWORD dwServiceType,
3079 DWORD dwStartType,
3080 DWORD dwErrorControl,
3081 LPSTR lpBinaryPathName,
3082 LPSTR lpLoadOrderGroup,
3083 LPDWORD lpdwTagId,
3084 LPSTR lpDependencies,
3085 DWORD dwDependSize,
3086 LPSTR lpServiceStartName,
3087 LPBYTE lpPassword,
3088 DWORD dwPwSize,
3089 LPSTR lpDisplayName)
3090 {
3091 DWORD dwError = ERROR_SUCCESS;
3092 PSERVICE_HANDLE hSvc;
3093 PSERVICE lpService = NULL;
3094 HKEY hServiceKey = NULL;
3095 LPWSTR lpDisplayNameW = NULL;
3096 // LPWSTR lpBinaryPathNameW = NULL;
3097 LPWSTR lpLoadOrderGroupW = NULL;
3098 LPWSTR lpDependenciesW = NULL;
3099 // LPWSTR lpPasswordW = NULL;
3100
3101 DPRINT("RChangeServiceConfigA() called\n");
3102 DPRINT("dwServiceType = %lu\n", dwServiceType);
3103 DPRINT("dwStartType = %lu\n", dwStartType);
3104 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3105 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3106 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3107 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3108
3109 if (ScmShutdown)
3110 return ERROR_SHUTDOWN_IN_PROGRESS;
3111
3112 hSvc = ScmGetServiceFromHandle(hService);
3113 if (hSvc == NULL)
3114 {
3115 DPRINT1("Invalid service handle!\n");
3116 return ERROR_INVALID_HANDLE;
3117 }
3118
3119 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3120 SERVICE_CHANGE_CONFIG))
3121 {
3122 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3123 return ERROR_ACCESS_DENIED;
3124 }
3125
3126 lpService = hSvc->ServiceEntry;
3127 if (lpService == NULL)
3128 {
3129 DPRINT("lpService == NULL!\n");
3130 return ERROR_INVALID_HANDLE;
3131 }
3132
3133 /* Lock the service database exclusively */
3134 ScmLockDatabaseExclusive();
3135
3136 if (lpService->bDeleted)
3137 {
3138 DPRINT("The service has already been marked for delete!\n");
3139 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3140 goto done;
3141 }
3142
3143 /* Open the service key */
3144 dwError = ScmOpenServiceKey(lpService->szServiceName,
3145 KEY_SET_VALUE,
3146 &hServiceKey);
3147 if (dwError != ERROR_SUCCESS)
3148 goto done;
3149
3150 /* Write service data to the registry */
3151
3152 if (lpDisplayName != NULL && *lpDisplayName != 0)
3153 {
3154 /* Set the display name */
3155 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3156 0,
3157 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3158 if (lpDisplayNameW == NULL)
3159 {
3160 dwError = ERROR_NOT_ENOUGH_MEMORY;
3161 goto done;
3162 }
3163
3164 MultiByteToWideChar(CP_ACP,
3165 0,
3166 lpDisplayName,
3167 -1,
3168 lpDisplayNameW,
3169 strlen(lpDisplayName) + 1);
3170
3171 RegSetValueExW(hServiceKey,
3172 L"DisplayName",
3173 0,
3174 REG_SZ,
3175 (LPBYTE)lpDisplayNameW,
3176 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3177
3178 /* Update lpService->lpDisplayName */
3179 if (lpService->lpDisplayName)
3180 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3181
3182 lpService->lpDisplayName = lpDisplayNameW;
3183 }
3184
3185 if (dwServiceType != SERVICE_NO_CHANGE)
3186 {
3187 /* Set the service type */
3188 dwError = RegSetValueExW(hServiceKey,
3189 L"Type",
3190 0,
3191 REG_DWORD,
3192 (LPBYTE)&dwServiceType,
3193 sizeof(DWORD));
3194 if (dwError != ERROR_SUCCESS)
3195 goto done;
3196
3197 lpService->Status.dwServiceType = dwServiceType;
3198 }
3199
3200 if (dwStartType != SERVICE_NO_CHANGE)
3201 {
3202 /* Set the start value */
3203 dwError = RegSetValueExW(hServiceKey,
3204 L"Start",
3205 0,
3206 REG_DWORD,
3207 (LPBYTE)&dwStartType,
3208 sizeof(DWORD));
3209 if (dwError != ERROR_SUCCESS)
3210 goto done;
3211
3212 lpService->dwStartType = dwStartType;
3213 }
3214
3215 if (dwErrorControl != SERVICE_NO_CHANGE)
3216 {
3217 /* Set the error control value */
3218 dwError = RegSetValueExW(hServiceKey,
3219 L"ErrorControl",
3220 0,
3221 REG_DWORD,
3222 (LPBYTE)&dwErrorControl,
3223 sizeof(DWORD));
3224 if (dwError != ERROR_SUCCESS)
3225 goto done;
3226
3227 lpService->dwErrorControl = dwErrorControl;
3228 }
3229
3230 #if 0
3231 /* FIXME: set the new ImagePath value */
3232
3233 /* Set the image path */
3234 if (dwServiceType & SERVICE_WIN32)
3235 {
3236 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3237 {
3238 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3239 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
3240 dwError = RegSetValueExW(hServiceKey,
3241 L"ImagePath",
3242 0,
3243 REG_EXPAND_SZ,
3244 (LPBYTE)lpBinaryPathNameW,
3245 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3246 if (dwError != ERROR_SUCCESS)
3247 goto done;
3248 }
3249 }
3250 else if (dwServiceType & SERVICE_DRIVER)
3251 {
3252 if (lpImagePath != NULL && *lpImagePath != 0)
3253 {
3254 dwError = RegSetValueExW(hServiceKey,
3255 L"ImagePath",
3256 0,
3257 REG_EXPAND_SZ,
3258 (LPBYTE)lpImagePath,
3259 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3260 if (dwError != ERROR_SUCCESS)
3261 goto done;
3262 }
3263 }
3264 #endif
3265
3266 /* Set the group name */
3267 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3268 {
3269 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3270 0,
3271 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3272 if (lpLoadOrderGroupW == NULL)
3273 {
3274 dwError = ERROR_NOT_ENOUGH_MEMORY;
3275 goto done;
3276 }
3277
3278 MultiByteToWideChar(CP_ACP,
3279 0,
3280 lpLoadOrderGroup,
3281 -1,
3282 lpLoadOrderGroupW,
3283 strlen(lpLoadOrderGroup) + 1);
3284
3285 dwError = RegSetValueExW(hServiceKey,
3286 L"Group",
3287 0,
3288 REG_SZ,
3289 (LPBYTE)lpLoadOrderGroupW,
3290 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3291 if (dwError != ERROR_SUCCESS)
3292 {
3293 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3294 goto done;
3295 }
3296
3297 dwError = ScmSetServiceGroup(lpService,
3298 lpLoadOrderGroupW);
3299
3300 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3301
3302 if (dwError != ERROR_SUCCESS)
3303 goto done;
3304 }
3305
3306 if (lpdwTagId != NULL)
3307 {
3308 dwError = ScmAssignNewTag(lpService);
3309 if (dwError != ERROR_SUCCESS)
3310 goto done;
3311
3312 dwError = RegSetValueExW(hServiceKey,
3313 L"Tag",
3314 0,
3315 REG_DWORD,
3316 (LPBYTE)&lpService->dwTag,
3317 sizeof(DWORD));
3318 if (dwError != ERROR_SUCCESS)
3319 goto done;
3320
3321 *lpdwTagId = lpService->dwTag;
3322 }
3323
3324 /* Write dependencies */
3325 if (lpDependencies != NULL && *lpDependencies != 0)
3326 {
3327 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3328 0,
3329 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3330 if (lpDependenciesW == NULL)
3331 {
3332 dwError = ERROR_NOT_ENOUGH_MEMORY;
3333 goto done;
3334 }
3335
3336 MultiByteToWideChar(CP_ACP,
3337 0,
3338 lpDependencies,
3339 dwDependSize,
3340 lpDependenciesW,
3341 strlen(lpDependencies) + 1);
3342
3343 dwError = ScmWriteDependencies(hServiceKey,
3344 (LPWSTR)lpDependenciesW,
3345 dwDependSize);
3346
3347 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3348 }
3349
3350 if (lpPassword != NULL)
3351 {
3352 /* FIXME: Write password */
3353 }
3354
3355 done:
3356 /* Unlock the service database */
3357 ScmUnlockDatabase();
3358
3359 if (hServiceKey != NULL)
3360 RegCloseKey(hServiceKey);
3361
3362 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3363
3364 return dwError;
3365 }
3366
3367
3368 /* Function 24 */
3369 DWORD RCreateServiceA(
3370 SC_RPC_HANDLE hSCManager,
3371 LPSTR lpServiceName,
3372 LPSTR lpDisplayName,
3373 DWORD dwDesiredAccess,
3374 DWORD dwServiceType,
3375 DWORD dwStartType,
3376 DWORD dwErrorControl,
3377 LPSTR lpBinaryPathName,
3378 LPSTR lpLoadOrderGroup,
3379 LPDWORD lpdwTagId,
3380 LPBYTE lpDependencies,
3381 DWORD dwDependSize,
3382 LPSTR lpServiceStartName,
3383 LPBYTE lpPassword,
3384 DWORD dwPwSize,
3385 LPSC_RPC_HANDLE lpServiceHandle)
3386 {
3387 DWORD dwError = ERROR_SUCCESS;
3388 LPWSTR lpServiceNameW = NULL;
3389 LPWSTR lpDisplayNameW = NULL;
3390 LPWSTR lpBinaryPathNameW = NULL;
3391 LPWSTR lpLoadOrderGroupW = NULL;
3392 LPWSTR lpDependenciesW = NULL;
3393 LPWSTR lpServiceStartNameW = NULL;
3394 DWORD dwDependenciesLength = 0;
3395 DWORD dwLength;
3396 int len;
3397 LPSTR lpStr;
3398
3399 if (lpServiceName)
3400 {
3401 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3402 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3403 if (!lpServiceNameW)
3404 {
3405 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3406 goto cleanup;
3407 }
3408 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3409 }
3410
3411 if (lpDisplayName)
3412 {
3413 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3414 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3415 if (!lpDisplayNameW)
3416 {
3417 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3418 goto cleanup;
3419 }
3420 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3421 }
3422
3423 if (lpBinaryPathName)
3424 {
3425 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3426 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3427 if (!lpBinaryPathNameW)
3428 {
3429 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3430 goto cleanup;
3431 }
3432 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3433 }
3434
3435 if (lpLoadOrderGroup)
3436 {
3437 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3438 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3439 if (!lpLoadOrderGroupW)
3440 {
3441 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3442 goto cleanup;
3443 }
3444 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3445 }
3446
3447 if (lpDependencies)
3448 {
3449 lpStr = (LPSTR)lpDependencies;
3450 while (*lpStr)
3451 {
3452 dwLength = strlen(lpStr) + 1;
3453 dwDependenciesLength += dwLength;
3454 lpStr = lpStr + dwLength;
3455 }
3456 dwDependenciesLength++;
3457
3458 lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
3459 if (!lpDependenciesW)
3460 {
3461 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3462 goto cleanup;
3463 }
3464 MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3465 }
3466
3467 if (lpServiceStartName)
3468 {
3469 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3470 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3471 if (!lpServiceStartNameW)
3472 {
3473 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3474 goto cleanup;
3475 }
3476 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3477 }
3478
3479 dwError = RCreateServiceW(hSCManager,
3480 lpServiceNameW,
3481 lpDisplayNameW,
3482 dwDesiredAccess,
3483 dwServiceType,
3484 dwStartType,
3485 dwErrorControl,
3486 lpBinaryPathNameW,
3487 lpLoadOrderGroupW,
3488 lpdwTagId,
3489 (LPBYTE)lpDependenciesW,
3490 dwDependenciesLength,
3491 lpServiceStartNameW,
3492 lpPassword,
3493 dwPwSize,
3494 lpServiceHandle);
3495
3496 cleanup:
3497 if (lpServiceNameW !=NULL)
3498 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3499
3500 if (lpDisplayNameW != NULL)
3501 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3502
3503 if (lpBinaryPathNameW != NULL)
3504 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3505
3506 if (lpLoadOrderGroupW != NULL)
3507 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3508
3509 if (lpDependenciesW != NULL)
3510 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3511
3512 if (lpServiceStartNameW != NULL)
3513 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3514
3515 return dwError;
3516 }
3517
3518
3519 /* Function 25 */
3520 DWORD REnumDependentServicesA(
3521 SC_RPC_HANDLE hService,
3522 DWORD dwServiceState,
3523 LPBYTE lpServices,
3524 DWORD cbBufSize,
3525 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3526 LPBOUNDED_DWORD_256K lpServicesReturned)
3527 {
3528 DWORD dwError = ERROR_SUCCESS;
3529 DWORD dwServicesReturned = 0;
3530 DWORD dwServiceCount;
3531 HKEY hServicesKey = NULL;
3532 PSERVICE_HANDLE hSvc;
3533 PSERVICE lpService = NULL;
3534 PSERVICE *lpServicesArray = NULL;
3535 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3536 LPSTR lpStr;
3537
3538 *pcbBytesNeeded = 0;
3539 *lpServicesReturned = 0;
3540
3541 DPRINT("REnumDependentServicesA() called\n");
3542
3543 hSvc = ScmGetServiceFromHandle(hService);
3544 if (hSvc == NULL)
3545 {
3546 DPRINT1("Invalid service handle!\n");
3547 return ERROR_INVALID_HANDLE;
3548 }
3549
3550 lpService = hSvc->ServiceEntry;
3551
3552 /* Check access rights */
3553 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3554 SC_MANAGER_ENUMERATE_SERVICE))
3555 {
3556 DPRINT("Insufficient access rights! 0x%lx\n",
3557 hSvc->Handle.DesiredAccess);
3558 return ERROR_ACCESS_DENIED;
3559 }
3560
3561 /* Open the Services Reg key */
3562 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3563 L"System\\CurrentControlSet\\Services",
3564 0,
3565 KEY_READ,
3566 &hServicesKey);
3567
3568 if (dwError != ERROR_SUCCESS)
3569 return dwError;
3570
3571 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3572 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3573 are the same for both. Verified in WINXP. */
3574
3575 /* First determine the bytes needed and get the number of dependent services*/
3576 dwError = Int_EnumDependentServicesW(hServicesKey,
3577 lpService,
3578 dwServiceState,
3579 NULL,
3580 pcbBytesNeeded,
3581 &dwServicesReturned);
3582 if (dwError != ERROR_SUCCESS)
3583 goto Done;
3584
3585 /* If buffer size is less than the bytes needed or pointer is null*/
3586 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3587 {
3588 dwError = ERROR_MORE_DATA;
3589 goto Done;
3590 }
3591
3592 /* Allocate memory for array of service pointers */
3593 lpServicesArray = HeapAlloc(GetProcessHeap(),
3594 0,
3595 (dwServicesReturned + 1) * sizeof(PSERVICE));
3596 if (!lpServicesArray)
3597 {
3598 DPRINT("Could not allocate a buffer!!\n");
3599 dwError = ERROR_NOT_ENOUGH_MEMORY;
3600 goto Done;
3601 }
3602
3603 dwServicesReturned = 0;
3604 *pcbBytesNeeded = 0;
3605
3606 dwError = Int_EnumDependentServicesW(hServicesKey,
3607 lpService,
3608 dwServiceState,
3609 lpServicesArray,
3610 pcbBytesNeeded,
3611 &dwServicesReturned);
3612 if (dwError != ERROR_SUCCESS)
3613 {
3614 goto Done;
3615 }
3616
3617 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3618 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3619
3620 /* Copy EnumDepenedentService to Buffer */
3621 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3622 {
3623 lpService = lpServicesArray[dwServiceCount];
3624
3625 /* Copy the status info */
3626 memcpy(&lpServicesPtr->ServiceStatus,
3627 &lpService->Status,
3628 sizeof(SERVICE_STATUS));
3629
3630 /* Copy display name */
3631 WideCharToMultiByte(CP_ACP,
3632 0,
3633 lpService->lpDisplayName,
3634 -1,
3635 lpStr,
3636 wcslen(lpService->lpDisplayName),
3637 0,
3638 0);
3639 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3640 lpStr += strlen(lpStr) + 1;
3641
3642 /* Copy service name */
3643 WideCharToMultiByte(CP_ACP,
3644 0,
3645 lpService->lpServiceName,
3646 -1,
3647 lpStr,
3648 wcslen(lpService->lpServiceName),
3649 0,
3650 0);
3651 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3652 lpStr += strlen(lpStr) + 1;
3653
3654 lpServicesPtr ++;
3655 }
3656
3657 *lpServicesReturned = dwServicesReturned;
3658
3659 Done:
3660 if (lpServicesArray)
3661 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3662
3663 RegCloseKey(hServicesKey);
3664
3665 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3666
3667 return dwError;
3668 }
3669
3670
3671 /* Function 26 */
3672 DWORD REnumServicesStatusA(
3673 SC_RPC_HANDLE hSCManager,
3674 DWORD dwServiceType,
3675 DWORD dwServiceState,
3676 LPBYTE lpBuffer,
3677 DWORD dwBufSize,
3678 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3679 LPBOUNDED_DWORD_256K lpServicesReturned,
3680 LPBOUNDED_DWORD_256K lpResumeHandle)
3681 {
3682 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3683 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3684 LPWSTR lpStringPtrW;
3685 LPSTR lpStringPtrA;
3686 DWORD dwError;
3687 DWORD dwServiceCount;
3688
3689 DPRINT("REnumServicesStatusA() called\n");
3690
3691 if ((dwBufSize > 0) && (lpBuffer))
3692 {
3693 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3694 if (!lpStatusPtrW)
3695 {
3696 DPRINT("Failed to allocate buffer!\n");
3697 return ERROR_NOT_ENOUGH_MEMORY;
3698 }
3699 }
3700
3701 dwError = REnumServicesStatusW(hSCManager,
3702 dwServiceType,
3703 dwServiceState,
3704 (LPBYTE)lpStatusPtrW,
3705 dwBufSize,
3706 pcbBytesNeeded,
3707 lpServicesReturned,
3708 lpResumeHandle);
3709
3710 /* if no services were returned then we are Done */
3711 if (*lpServicesReturned == 0)
3712 goto Done;
3713
3714 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3715 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3716 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3717 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3718 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3719
3720 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3721 {
3722 /* Copy the service name */
3723 WideCharToMultiByte(CP_ACP,
3724 0,
3725 lpStringPtrW,
3726 -1,
3727 lpStringPtrA,
3728 wcslen(lpStringPtrW),
3729 0,
3730 0);
3731
3732 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3733 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3734 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3735
3736 /* Copy the display name */
3737 WideCharToMultiByte(CP_ACP,
3738 0,
3739 lpStringPtrW,
3740 -1,
3741 lpStringPtrA,
3742 wcslen(lpStringPtrW),
3743 0,
3744 0);
3745
3746 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3747 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3748 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3749
3750 /* Copy the status information */
3751 memcpy(&lpStatusPtrA->ServiceStatus,
3752 &lpStatusPtrW->ServiceStatus,
3753 sizeof(SERVICE_STATUS));
3754
3755 lpStatusPtrA++;
3756 }
3757
3758 Done:;
3759 if (lpStatusPtrW)
3760 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3761
3762 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3763
3764 return dwError;
3765 }
3766
3767
3768 /* Function 27 */
3769 DWORD ROpenSCManagerA(
3770 LPSTR lpMachineName,
3771 LPSTR lpDatabaseName,
3772 DWORD dwDesiredAccess,
3773 LPSC_RPC_HANDLE lpScHandle)
3774 {
3775 UNICODE_STRING MachineName;
3776 UNICODE_STRING DatabaseName;
3777 DWORD dwError;
3778
3779 DPRINT("ROpenSCManagerA() called\n");
3780
3781 if (lpMachineName)
3782 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3783 lpMachineName);
3784
3785 if (lpDatabaseName)
3786 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3787 lpDatabaseName);
3788
3789 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3790 lpDatabaseName ? DatabaseName.Buffer : NULL,
3791 dwDesiredAccess,
3792 lpScHandle);
3793
3794 if (lpMachineName)
3795 RtlFreeUnicodeString(&MachineName);
3796
3797 if (lpDatabaseName)
3798 RtlFreeUnicodeString(&DatabaseName);
3799
3800 return dwError;
3801 }
3802
3803
3804 /* Function 28 */
3805 DWORD ROpenServiceA(
3806 SC_RPC_HANDLE hSCManager,
3807 LPSTR lpServiceName,
3808 DWORD dwDesiredAccess,
3809 LPSC_RPC_HANDLE lpServiceHandle)
3810 {
3811 UNICODE_STRING ServiceName;
3812 DWORD dwError;
3813
3814 DPRINT("ROpenServiceA() called\n");
3815
3816 if (lpServiceName)
3817 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3818 lpServiceName);
3819
3820 dwError = ROpenServiceW(hSCManager,
3821 lpServiceName ? ServiceName.Buffer : NULL,
3822 dwDesiredAccess,
3823 lpServiceHandle);
3824
3825 if (lpServiceName)
3826 RtlFreeUnicodeString(&ServiceName);
3827
3828 return dwError;
3829 }
3830
3831
3832 /* Function 29 */
3833 DWORD RQueryServiceConfigA(
3834 SC_RPC_HANDLE hService,
3835 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3836 DWORD cbBufSize,
3837 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3838 {
3839 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3840 DWORD dwError = ERROR_SUCCESS;
3841 PSERVICE_HANDLE hSvc;
3842 PSERVICE lpService = NULL;
3843 HKEY hServiceKey = NULL;
3844 LPWSTR lpImagePath = NULL;
3845 LPWSTR lpServiceStartName = NULL;
3846 LPWSTR lpDependencies = NULL;
3847 DWORD dwDependenciesLength = 0;
3848 DWORD dwRequiredSize;
3849 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3850 CHAR lpEmptyString[]={0,0};
3851 LPSTR lpStr;
3852
3853 DPRINT("RQueryServiceConfigA() called\n");
3854
3855 if (ScmShutdown)
3856 return ERROR_SHUTDOWN_IN_PROGRESS;
3857
3858 hSvc = ScmGetServiceFromHandle(hService);
3859 if (hSvc == NULL)
3860 {
3861 DPRINT1("Invalid service handle!\n");
3862 return ERROR_INVALID_HANDLE;
3863 }
3864
3865 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3866 SERVICE_QUERY_CONFIG))
3867 {
3868 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3869 return ERROR_ACCESS_DENIED;
3870 }
3871
3872 lpService = hSvc->ServiceEntry;
3873 if (lpService == NULL)
3874 {
3875 DPRINT("lpService == NULL!\n");
3876 return ERROR_INVALID_HANDLE;
3877 }
3878
3879 /* Lock the service database shared */
3880 ScmLockDatabaseShared();
3881
3882 dwError = ScmOpenServiceKey(lpService->lpServiceName,
3883 KEY_READ,
3884 &hServiceKey);
3885 if (dwError != ERROR_SUCCESS)
3886 goto Done;
3887
3888 /* Read the image path */
3889 dwError = ScmReadString(hServiceKey,
3890 L"ImagePath",
3891 &lpImagePath);
3892 if (dwError != ERROR_SUCCESS)
3893 goto Done;
3894
3895 /* Read the service start name */
3896 ScmReadString(hServiceKey,
3897 L"ObjectName",
3898 &lpServiceStartName);
3899
3900 /* Read the dependencies */
3901 ScmReadDependencies(hServiceKey,
3902 &lpDependencies,
3903 &dwDependenciesLength);
3904
3905 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
3906
3907 if (lpImagePath != NULL)
3908 dwRequiredSize += wcslen(lpImagePath) + 1;
3909 else
3910 dwRequiredSize += 2;
3911
3912 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3913 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
3914 else
3915 dwRequiredSize += 2;
3916
3917 /* Add Dependencies length */
3918 if (lpDependencies != NULL)
3919 dwRequiredSize += dwDependenciesLength;
3920 else
3921 dwRequiredSize += 2;
3922
3923 if (lpServiceStartName != NULL)
3924 dwRequiredSize += wcslen(lpServiceStartName) + 1;
3925 else
3926 dwRequiredSize += 2;
3927
3928 if (lpService->lpDisplayName != NULL)
3929 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
3930 else
3931 dwRequiredSize += 2;
3932
3933 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3934 {
3935 dwError = ERROR_INSUFFICIENT_BUFFER;
3936 }
3937 else
3938 {
3939 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
3940 lpConfig->dwServiceType = lpService->Status.dwServiceType;
3941 lpConfig->dwStartType = lpService->dwStartType;
3942 lpConfig->dwErrorControl = lpService->dwErrorControl;
3943 lpConfig->dwTagId = lpService->dwTag;
3944
3945 lpStr = (LPSTR)(lpServiceConfig + 1);
3946
3947 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
3948 Verified in WINXP*/
3949
3950 if (lpImagePath)
3951 {
3952 WideCharToMultiByte(CP_ACP,
3953 0,
3954 lpImagePath,
3955 -1,
3956 lpStr,
3957 wcslen(lpImagePath) + 1,
3958 0,
3959 0);
3960 }
3961 else
3962 {
3963 strcpy(lpStr, lpEmptyString);
3964 }
3965
3966 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3967 lpStr += (strlen((LPSTR)lpStr) + 1);
3968
3969 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
3970 {
3971 WideCharToMultiByte(CP_ACP,
3972 0,
3973 lpService->lpGroup->lpGroupName,
3974 -1,
3975 lpStr,
3976 wcslen(lpService->lpGroup->lpGroupName) + 1,
3977 0,
3978 0);
3979 }
3980 else
3981 {
3982 strcpy(lpStr, lpEmptyString);
3983 }
3984
3985 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
3986 lpStr += (strlen(lpStr) + 1);
3987
3988 /* Append Dependencies */
3989 if (lpDependencies)
3990 {
3991 WideCharToMultiByte(CP_ACP,
3992 0,
3993 lpDependencies,
3994 dwDependenciesLength,
3995 lpStr,
3996 dwDependenciesLength,
3997 0,
3998 0);
3999 }
4000 else
4001 {
4002 strcpy(lpStr, lpEmptyString);
4003 }
4004
4005 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4006 if (lpDependencies)
4007 lpStr += dwDependenciesLength;
4008 else
4009 lpStr += (strlen(lpStr) + 1);
4010
4011 if (lpServiceStartName)
4012 {
4013 WideCharToMultiByte(CP_ACP,
4014 0,
4015 lpServiceStartName,
4016 -1,
4017 lpStr,
4018 wcslen(lpServiceStartName) + 1,
4019 0,
4020 0);
4021 }
4022 else
4023 {
4024 strcpy(lpStr, lpEmptyString);
4025 }
4026
4027 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4028 lpStr += (strlen(lpStr) + 1);
4029
4030 if (lpService->lpDisplayName)
4031 {
4032 WideCharToMultiByte(CP_ACP,
4033 0,
4034 lpService->lpDisplayName,
4035 -1,
4036 lpStr,
4037 wcslen(lpService->lpDisplayName) + 1,
4038 0,
4039 0);
4040 }
4041 else
4042 {
4043 strcpy(lpStr, lpEmptyString);
4044 }
4045
4046 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4047 }
4048
4049 if (pcbBytesNeeded != NULL)
4050 *pcbBytesNeeded = dwRequiredSize;
4051
4052 Done:;
4053 /* Unlock the service database */
4054 ScmUnlockDatabase();
4055
4056 if (lpImagePath != NULL)
4057 HeapFree(GetProcessHeap(), 0, lpImagePath);
4058
4059 if (lpServiceStartName != NULL)
4060 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4061
4062 if (lpDependencies != NULL)
4063 HeapFree(GetProcessHeap(), 0, lpDependencies);
4064
4065 if (hServiceKey != NULL)
4066 RegCloseKey(hServiceKey);
4067
4068 DPRINT("RQueryServiceConfigA() done\n");
4069
4070 return dwError;
4071 }
4072
4073
4074 /* Function 30 */
4075 DWORD RQueryServiceLockStatusA(
4076 SC_RPC_HANDLE hSCManager,
4077 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4078 DWORD cbBufSize,
4079 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4080 {
4081 UNIMPLEMENTED;
4082 return ERROR_CALL_NOT_IMPLEMENTED;
4083 }
4084
4085
4086 /* Function 31 */
4087 DWORD RStartServiceA(
4088 SC_RPC_HANDLE hService,
4089 DWORD argc,
4090 LPSTRING_PTRSA argv)
4091 {
4092 DWORD dwError = ERROR_SUCCESS;
4093 PSERVICE_HANDLE hSvc;
4094 PSERVICE lpService = NULL;
4095
4096 DPRINT("RStartServiceA() called\n");
4097
4098 if (ScmShutdown)
4099 return ERROR_SHUTDOWN_IN_PROGRESS;
4100
4101 hSvc = ScmGetServiceFromHandle(hService);
4102 if (hSvc == NULL)
4103 {
4104 DPRINT1("Invalid service handle!\n");
4105 return ERROR_INVALID_HANDLE;
4106 }
4107
4108 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4109 SERVICE_START))
4110 {
4111 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4112 return ERROR_ACCESS_DENIED;
4113 }
4114
4115 lpService = hSvc->ServiceEntry;
4116 if (lpService == NULL)
4117 {
4118 DPRINT("lpService == NULL!\n");
4119 return ERROR_INVALID_HANDLE;
4120 }
4121
4122 if (lpService->dwStartType == SERVICE_DISABLED)
4123 return ERROR_SERVICE_DISABLED;
4124
4125 if (lpService->bDeleted)
4126 return ERROR_SERVICE_MARKED_FOR_DELETE;
4127
4128 /* FIXME: Convert argument vector to Unicode */
4129
4130 /* Start the service */
4131 dwError = ScmStartService(lpService, 0, NULL);
4132
4133 /* FIXME: Free argument vector */
4134
4135 return dwError;
4136 }
4137
4138
4139 /* Function 32 */
4140 DWORD RGetServiceDisplayNameA(
4141 SC_RPC_HANDLE hSCManager,
4142 LPCSTR lpServiceName,
4143 LPSTR lpDisplayName,
4144 LPBOUNDED_DWORD_4K lpcchBuffer)
4145 {
4146 // PMANAGER_HANDLE hManager;
4147 PSERVICE lpService = NULL;
4148 DWORD dwLength;
4149 DWORD dwError;
4150 LPWSTR lpServiceNameW;
4151
4152 DPRINT("RGetServiceDisplayNameA() called\n");
4153 DPRINT("hSCManager = %p\n", hSCManager);
4154 DPRINT("lpServiceName: %s\n", lpServiceName);
4155 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4156 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4157
4158 // hManager = (PMANAGER_HANDLE)hSCManager;
4159 // if (hManager->Handle.Tag != MANAGER_TAG)
4160 // {
4161 // DPRINT("Invalid manager handle!\n");
4162 // return ERROR_INVALID_HANDLE;
4163 // }
4164
4165 if (lpServiceName != NULL)
4166 {
4167 dwLength = strlen(lpServiceName) + 1;
4168 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4169 HEAP_ZERO_MEMORY,
4170 dwLength * sizeof(WCHAR));
4171 if (!lpServiceNameW)
4172 return ERROR_NOT_ENOUGH_MEMORY;
4173
4174 MultiByteToWideChar(CP_ACP,
4175 0,
4176 lpServiceName,
4177 -1,
4178 lpServiceNameW,
4179 dwLength);
4180
4181 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4182
4183 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4184 }
4185
4186 if (lpService == NULL)
4187 {
4188 DPRINT("Could not find a service!\n");
4189
4190 /* If the service could not be found and lpcchBuffer is 0, windows
4191 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4192 if (*lpcchBuffer == 0)
4193 {
4194 *lpcchBuffer = 1;
4195 if (lpDisplayName != NULL)
4196 {
4197 *lpDisplayName = '\0';
4198 }
4199 }
4200 return ERROR_SERVICE_DOES_NOT_EXIST;
4201 }
4202
4203 if (!lpService->lpDisplayName)
4204 {
4205 dwLength = wcslen(lpService->lpServiceName);
4206 if (lpDisplayName != NULL &&
4207 *lpcchBuffer > dwLength)
4208 {
4209 WideCharToMultiByte(CP_ACP,
4210 0,
4211 lpService->lpServiceName,
4212 wcslen(lpService->lpServiceName),
4213 lpDisplayName,
4214 dwLength + 1,
4215 NULL,
4216 NULL);
4217 return ERROR_SUCCESS;
4218 }
4219 }
4220 else
4221 {
4222 dwLength = wcslen(lpService->lpDisplayName);
4223 if (lpDisplayName != NULL &&
4224 *lpcchBuffer > dwLength)
4225 {
4226 WideCharToMultiByte(CP_ACP,
4227 0,
4228 lpService->lpDisplayName,
4229 wcslen(lpService->lpDisplayName),
4230 lpDisplayName,
4231 dwLength + 1,
4232 NULL,
4233 NULL);
4234 return ERROR_SUCCESS;
4235 }
4236 }
4237
4238 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4239
4240 *lpcchBuffer = dwLength * 2;
4241
4242 return dwError;
4243 }
4244
4245
4246 /* Function 33 */
4247 DWORD RGetServiceKeyNameA(
4248 SC_RPC_HANDLE hSCManager,
4249 LPCSTR lpDisplayName,
4250 LPSTR lpServiceName,
4251 LPBOUNDED_DWORD_4K lpcchBuffer)
4252 {
4253 PSERVICE lpService;
4254 DWORD dwLength;
4255 DWORD dwError;
4256 LPWSTR lpDisplayNameW;
4257
4258 DPRINT("RGetServiceKeyNameA() called\n");
4259 DPRINT("hSCManager = %p\n", hSCManager);
4260 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4261 DPRINT("lpServiceName: %p\n", lpServiceName);
4262 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4263
4264 dwLength = strlen(lpDisplayName) + 1;
4265 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4266 HEAP_ZERO_MEMORY,
4267 dwLength * sizeof(WCHAR));
4268 if (!lpDisplayNameW)
4269 return ERROR_NOT_ENOUGH_MEMORY;
4270
4271 MultiByteToWideChar(CP_ACP,
4272 0,
4273 lpDisplayName,
4274 -1,
4275 lpDisplayNameW,
4276 dwLength);
4277
4278 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4279
4280 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4281
4282 if (lpService == NULL)
4283 {
4284 DPRINT("Could not find the service!\n");
4285
4286 /* If the service could not be found and lpcchBuffer is 0,
4287 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4288 if (*lpcchBuffer == 0)
4289 {
4290 *lpcchBuffer = 1;
4291 if (lpServiceName != NULL)
4292 {
4293 *lpServiceName = '\0';
4294 }
4295 }
4296
4297 return ERROR_SERVICE_DOES_NOT_EXIST;
4298 }
4299
4300 dwLength = wcslen(lpService->lpServiceName);
4301 if (lpServiceName != NULL &&
4302 *lpcchBuffer > dwLength)
4303 {
4304 WideCharToMultiByte(CP_ACP,
4305 0,
4306 lpService->lpServiceName,
4307 wcslen(lpService->lpServiceName),
4308 lpServiceName,
4309 dwLength + 1,
4310 NULL,
4311 NULL);
4312 return ERROR_SUCCESS;
4313 }
4314
4315 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4316
4317 *lpcchBuffer = dwLength * 2;
4318
4319 return dwError;
4320 }
4321
4322
4323 /* Function 34 */
4324 DWORD RI_ScGetCurrentGroupStateW(
4325 SC_RPC_HANDLE hSCManager,
4326 LPWSTR lpLoadOrderGroup,
4327 LPDWORD lpState)
4328 {
4329 UNIMPLEMENTED;
4330 return ERROR_CALL_NOT_IMPLEMENTED;
4331 }
4332
4333
4334 /* Function 35 */
4335 DWORD REnumServiceGroupW(
4336 SC_RPC_HANDLE hSCManager,
4337 DWORD dwServiceType,
4338 DWORD dwServiceState,
4339 LPBYTE lpBuffer,
4340 DWORD cbBufSize,
4341 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4342 LPBOUNDED_DWORD_256K lpServicesReturned,
4343 LPBOUNDED_DWORD_256K lpResumeIndex,
4344 LPCWSTR pszGroupName)
4345 {
4346 UNIMPLEMENTED;
4347 return ERROR_CALL_NOT_IMPLEMENTED;
4348 }
4349
4350
4351 //
4352 // WARNING: This function is untested
4353 //
4354 /* Function 36 */
4355 DWORD RChangeServiceConfig2A(
4356 SC_RPC_HANDLE hService,
4357 SC_RPC_CONFIG_INFOA Info)
4358 {
4359 SC_RPC_CONFIG_INFOW InfoW;
4360 DWORD dwRet, dwLength;
4361 PVOID ptr = NULL;
4362
4363 DPRINT("RChangeServiceConfig2A() called\n");
4364 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4365
4366 InfoW.dwInfoLevel = Info.dwInfoLevel;
4367
4368 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4369 {
4370 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4371 LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4372
4373 lpServiceDescriptonA = Info.psd;
4374
4375 ///if (lpServiceDescriptonA &&
4376 ///lpServiceDescriptonA->lpDescription)
4377 ///{
4378 dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
4379
4380 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4381 0,
4382 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4383 if (!lpServiceDescriptonW)
4384 {
4385 return ERROR_NOT_ENOUGH_MEMORY;
4386 }
4387
4388 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4389
4390 MultiByteToWideChar(CP_ACP,
4391 0,
4392 Info.lpDescription,
4393 -1,
4394 lpServiceDescriptonW->lpDescription,
4395 dwLength);
4396
4397 ptr = lpServiceDescriptonW;
4398 InfoW.psd = lpServiceDescriptonW;
4399 ///}
4400 }
4401 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4402 {
4403 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4404 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4405 DWORD dwRebootLen = 0;
4406 DWORD dwCommandLen = 0;
4407
4408 lpServiceFailureActionsA = Info.psfa;
4409
4410 if (lpServiceFailureActionsA)
4411 {
4412 if (lpServiceFailureActionsA->lpRebootMsg)
4413 {
4414 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4415 }
4416 if (lpServiceFailureActionsA->lpCommand)
4417 {
4418 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4419 }
4420 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4421
4422 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4423 0,
4424 dwLength);
4425 if (!lpServiceFailureActionsW)
4426 {
4427 return ERROR_NOT_ENOUGH_MEMORY;
4428 }
4429
4430 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4431 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4432 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4433
4434 if (lpServiceFailureActionsA->lpRebootMsg)
4435 {
4436 MultiByteToWideChar(CP_ACP,
4437 0,
4438 lpServiceFailureActionsA->lpRebootMsg,
4439 -1,
4440 lpServiceFailureActionsW->lpRebootMsg,
4441 dwRebootLen);
4442 }
4443
4444 if (lpServiceFailureActionsA->lpCommand)
4445 {
4446 MultiByteToWideChar(CP_ACP,
4447 0,
4448 lpServiceFailureActionsA->lpCommand,
4449 -1,
4450 lpServiceFailureActionsW->lpCommand,
4451 dwCommandLen);
4452 }
4453
4454 ptr = lpServiceFailureActionsW;
4455 }
4456 }
4457
4458 dwRet = RChangeServiceConfig2W(hService, InfoW);
4459
4460 HeapFree(GetProcessHeap(), 0, ptr);
4461
4462 return dwRet;
4463 }
4464
4465
4466 /* Function 37 */
4467 DWORD RChangeServiceConfig2W(
4468 SC_RPC_HANDLE hService,
4469 SC_RPC_CONFIG_INFOW Info)
4470 {
4471 DWORD dwError = ERROR_SUCCESS;
4472 PSERVICE_HANDLE hSvc;
4473 PSERVICE lpService = NULL;
4474 HKEY hServiceKey = NULL;
4475
4476 DPRINT("RChangeServiceConfig2W() called\n");
4477 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4478
4479 if (ScmShutdown)
4480 return ERROR_SHUTDOWN_IN_PROGRESS;
4481
4482 hSvc = ScmGetServiceFromHandle(hService);
4483 if (hSvc == NULL)
4484 {
4485 DPRINT1("Invalid service handle!\n");
4486 return ERROR_INVALID_HANDLE;
4487 }
4488
4489 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4490 SERVICE_CHANGE_CONFIG))
4491 {
4492 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4493 return ERROR_ACCESS_DENIED;
4494 }
4495
4496 lpService = hSvc->ServiceEntry;
4497 if (lpService == NULL)
4498 {
4499 DPRINT("lpService == NULL!\n");
4500 return ERROR_INVALID_HANDLE;
4501 }
4502
4503 /* Lock the service database exclusively */
4504 ScmLockDatabaseExclusive();
4505
4506 if (lpService->bDeleted)
4507 {
4508 DPRINT("The service has already been marked for delete!\n");
4509 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
4510 goto done;
4511 }
4512
4513 /* Open the service key */
4514 dwError = ScmOpenServiceKey(lpService->szServiceName,
4515 KEY_SET_VALUE,
4516 &hServiceKey);
4517 if (dwError != ERROR_SUCCESS)
4518 goto done;
4519
4520 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4521 {
4522 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4523
4524 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
4525 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
4526
4527 if (lpServiceDescription != NULL &&
4528 lpServiceDescription->lpDescription != NULL)
4529 {
4530 DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
4531 dwError = RegSetValueExW(hServiceKey,
4532 L"Description",
4533 0,
4534 REG_SZ,
4535 (LPBYTE)lpServiceDescription->lpDescription,
4536 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4537 if (dwError != ERROR_SUCCESS)
4538 goto done;
4539 }
4540 }
4541 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4542 {
4543 UNIMPLEMENTED;
4544 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4545 goto done;
4546 }
4547
4548 done:
4549 /* Unlock the service database */
4550 ScmUnlockDatabase();
4551
4552 if (hServiceKey != NULL)
4553 RegCloseKey(hServiceKey);
4554
4555 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4556
4557 return dwError;
4558 }
4559
4560
4561 /* Function 38 */
4562 DWORD RQueryServiceConfig2A(
4563 SC_RPC_HANDLE hService,
4564 DWORD dwInfoLevel,
4565 LPBYTE lpBuffer,
4566 DWORD cbBufSize,
4567 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4568 {
4569 DWORD dwError = ERROR_SUCCESS;
4570 PSERVICE_HANDLE hSvc;
4571 PSERVICE lpService = NULL;
4572 HKEY hServiceKey = NULL;
4573 LPWSTR lpDescriptionW = NULL;
4574 LPSTR lpDescription = NULL;
4575
4576 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
4577 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
4578
4579 if (!lpBuffer)
4580 return ERROR_INVALID_ADDRESS;
4581
4582 if (ScmShutdown)
4583 return ERROR_SHUTDOWN_IN_PROGRESS;
4584
4585 hSvc = ScmGetServiceFromHandle(hService);
4586 if (hSvc == NULL)
4587 {
4588 DPRINT1("Invalid service handle!\n");
4589 return ERROR_INVALID_HANDLE;
4590 }
4591
4592 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4593 SERVICE_QUERY_CONFIG))
4594 {
4595 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4596 return ERROR_ACCESS_DENIED;
4597 }
4598
4599 lpService = hSvc->ServiceEntry;
4600 if (lpService == NULL)
4601 {
4602 DPRINT("lpService == NULL!\n");
4603 return ERROR_INVALID_HANDLE;
4604 }
4605
4606 /* Lock the service database shared */
4607 ScmLockDatabaseShared();
4608
4609 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4610 KEY_READ,
4611 &hServiceKey);
4612 if (dwError != ERROR_SUCCESS)
4613 goto done;
4614
4615 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4616 {
4617 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4618 LPSTR lpStr;
4619
4620 dwError = ScmReadString(hServiceKey,
4621 L"Description",
4622 &lpDescriptionW);
4623 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4624 goto done;
4625
4626 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4627 if (dwError == ERROR_SUCCESS)
4628 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
4629
4630 if (cbBufSize < *pcbBytesNeeded)
4631 {
4632 dwError = ERROR_INSUFFICIENT_BUFFER;
4633 goto done;
4634 }
4635
4636 if (dwError == ERROR_SUCCESS)
4637 {
4638 lpStr = (LPSTR)(lpServiceDescription + 1);
4639
4640 WideCharToMultiByte(CP_ACP,
4641 0,
4642 lpDescriptionW,
4643 -1,
4644 lpStr,
4645 wcslen(lpDescriptionW),
4646 NULL,
4647 NULL);
4648 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4649 }
4650 else
4651 {
4652 lpServiceDescription->lpDescription = NULL;
4653 dwError = ERROR_SUCCESS;
4654 goto done;
4655 }
4656 }
4657 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4658 {
4659 UNIMPLEMENTED;
4660 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4661 goto done;
4662 }
4663
4664 done:
4665 /* Unlock the service database */
4666 ScmUnlockDatabase();
4667
4668 if (lpDescription != NULL)
4669 HeapFree(GetProcessHeap(), 0, lpDescription);
4670
4671 if (hServiceKey != NULL)
4672 RegCloseKey(hServiceKey);
4673
4674 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4675
4676 return dwError;
4677 }
4678
4679
4680 /* Function 39 */
4681 DWORD RQueryServiceConfig2W(
4682 SC_RPC_HANDLE hService,
4683 DWORD dwInfoLevel,
4684 LPBYTE lpBuffer,
4685 DWORD cbBufSize,
4686 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4687 {
4688 DWORD dwError = ERROR_SUCCESS;
4689 PSERVICE_HANDLE hSvc;
4690 PSERVICE lpService = NULL;
4691 HKEY hServiceKey = NULL;
4692 DWORD dwRequiredSize;
4693 LPWSTR lpDescription = NULL;
4694 LPWSTR lpFailureCommand = NULL;
4695 LPWSTR lpRebootMessage = NULL;
4696
4697 DPRINT("RQueryServiceConfig2W() called\n");
4698
4699 if (!lpBuffer)
4700 return ERROR_INVALID_ADDRESS;
4701
4702 if (ScmShutdown)
4703 return ERROR_SHUTDOWN_IN_PROGRESS;
4704
4705 hSvc = ScmGetServiceFromHandle(hService);
4706 if (hSvc == NULL)
4707 {
4708 DPRINT1("Invalid service handle!\n");
4709 return ERROR_INVALID_HANDLE;
4710 }
4711
4712 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4713 SERVICE_QUERY_CONFIG))
4714 {
4715 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4716 return ERROR_ACCESS_DENIED;
4717 }
4718
4719 lpService = hSvc->ServiceEntry;
4720 if (lpService == NULL)
4721 {
4722 DPRINT("lpService == NULL!\n");
4723 return ERROR_INVALID_HANDLE;
4724 }
4725
4726 /* Lock the service database shared */
4727 ScmLockDatabaseShared();
4728
4729 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4730 KEY_READ,
4731 &hServiceKey);
4732 if (dwError != ERROR_SUCCESS)
4733 goto done;
4734
4735 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4736 {
4737 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4738 LPWSTR lpStr;
4739
4740 dwError = ScmReadString(hServiceKey,
4741 L"Description",
4742 &lpDescription);
4743 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4744 goto done;
4745
4746 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
4747 if (dwError == ERROR_SUCCESS)
4748 *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4749
4750 if (cbBufSize < *pcbBytesNeeded)
4751 {
4752 dwError = ERROR_INSUFFICIENT_BUFFER;
4753 goto done;
4754 }
4755
4756 if (dwError == ERROR_SUCCESS)
4757 {
4758 lpStr = (LPWSTR)(lpServiceDescription + 1);
4759 wcscpy(lpStr, lpDescription);
4760 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4761 }
4762 else
4763 {
4764 lpServiceDescription->lpDescription = NULL;
4765 dwError = ERROR_SUCCESS;
4766 }
4767 }
4768 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4769 {
4770 LPWSTR lpStr;
4771 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
4772
4773 UNIMPLEMENTED;
4774
4775 dwError = ScmReadString(hServiceKey,
4776 L"FailureCommand",
4777 &lpFailureCommand);
4778
4779 dwError = ScmReadString(hServiceKey,
4780 L"RebootMessage",
4781 &lpRebootMessage);
4782
4783 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
4784
4785 if (lpFailureCommand)
4786 dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
4787
4788 if (lpRebootMessage)
4789 dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
4790
4791 if (cbBufSize < dwRequiredSize)
4792 {
4793 *pcbBytesNeeded = dwRequiredSize;
4794 dwError = ERROR_INSUFFICIENT_BUFFER;
4795 goto done;
4796 }
4797
4798 lpFailureActions->cActions = 0;
4799 lpFailureActions->dwResetPeriod = 0;
4800 lpFailureActions->lpCommand = NULL;
4801 lpFailureActions->lpRebootMsg = NULL;
4802 lpFailureActions->lpsaActions = NULL;
4803
4804 lpStr = (LPWSTR)(lpFailureActions + 1);
4805 if (lpRebootMessage)
4806 {
4807 wcscpy(lpStr, lpRebootMessage);
4808 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
4809 lpStr += wcslen(lpRebootMessage) + 1;
4810 }
4811
4812 if (lpFailureCommand)
4813 {
4814 wcscpy(lpStr, lpFailureCommand);
4815 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
4816 lpStr += wcslen(lpRebootMessage) + 1;
4817 }
4818 dwError = STATUS_SUCCESS;
4819 goto done;
4820 }
4821
4822 done:
4823 /* Unlock the service database */
4824 ScmUnlockDatabase();
4825
4826 if (lpDescription != NULL)
4827 HeapFree(GetProcessHeap(), 0, lpDescription);
4828
4829 if (lpRebootMessage != NULL)
4830 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
4831
4832 if (lpFailureCommand != NULL)
4833 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
4834
4835 if (hServiceKey != NULL)
4836 RegCloseKey(hServiceKey);
4837
4838 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4839
4840 return dwError;
4841 }
4842
4843
4844 /* Function 40 */
4845 DWORD RQueryServiceStatusEx(
4846 SC_RPC_HANDLE hService,
4847 SC_STATUS_TYPE InfoLevel,
4848 LPBYTE lpBuffer,
4849 DWORD cbBufSize,
4850 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4851 {
4852 LPSERVICE_STATUS_PROCESS lpStatus;
4853 PSERVICE_HANDLE hSvc;
4854 PSERVICE lpService;
4855
4856 DPRINT("RQueryServiceStatusEx() called\n");
4857
4858 if (ScmShutdown)
4859 return ERROR_SHUTDOWN_IN_PROGRESS;
4860
4861 if (InfoLevel != SC_STATUS_PROCESS_INFO)
4862 return ERROR_INVALID_LEVEL;
4863
4864 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
4865
4866 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
4867 return ERROR_INSUFFICIENT_BUFFER;
4868
4869 hSvc = ScmGetServiceFromHandle(hService);
4870 if (hSvc == NULL)
4871 {
4872 DPRINT1("Invalid service handle!\n");
4873 return ERROR_INVALID_HANDLE;
4874 }
4875
4876 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4877 SERVICE_QUERY_STATUS))
4878 {
4879 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4880 return ERROR_ACCESS_DENIED;
4881 }
4882
4883 lpService = hSvc->ServiceEntry;
4884 if (lpService == NULL)
4885 {
4886 DPRINT("lpService == NULL!\n");
4887 return ERROR_INVALID_HANDLE;
4888 }
4889
4890 /* Lock the service database shared */
4891 ScmLockDatabaseShared();
4892
4893 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
4894
4895 /* Return service status information */
4896 RtlCopyMemory(lpStatus,
4897 &lpService->Status,
4898 sizeof(SERVICE_STATUS));
4899
4900 lpStatus->dwProcessId = lpService->ProcessId; /* FIXME */
4901 lpStatus->dwServiceFlags = 0; /* FIXME */
4902
4903 /* Unlock the service database */
4904 ScmUnlockDatabase();
4905
4906 return ERROR_SUCCESS;
4907 }
4908
4909
4910 /* Function 41 */
4911 DWORD REnumServicesStatusExA(
4912 SC_RPC_HANDLE hSCManager,
4913 SC_ENUM_TYPE InfoLevel,
4914 DWORD dwServiceType,
4915 DWORD dwServiceState,
4916 LPBYTE lpBuffer,
4917 DWORD cbBufSize,
4918 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4919 LPBOUNDED_DWORD_256K lpServicesReturned,
4920 LPBOUNDED_DWORD_256K lpResumeIndex,
4921 LPCSTR pszGroupName)
4922 {
4923 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
4924 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
4925 LPWSTR lpStringPtrW;
4926 LPSTR lpStringPtrA;
4927 LPWSTR pszGroupNameW = NULL;
4928 DWORD dwError;
4929 DWORD dwServiceCount;
4930
4931 DPRINT("REnumServicesStatusExA() called\n");
4932
4933 if (pszGroupName)
4934 {
4935 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
4936 if (!pszGroupNameW)
4937 {
4938 DPRINT("Failed to allocate buffer!\n");
4939 return ERROR_NOT_ENOUGH_MEMORY;
4940 }
4941
4942 MultiByteToWideChar(CP_ACP,
4943 0,
4944 pszGroupName,
4945 -1,
4946 pszGroupNameW,
4947 strlen(pszGroupName) + 1);
4948 }
4949
4950 if ((cbBufSize > 0) && (lpBuffer))
4951 {
4952 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
4953 if (!lpStatusPtrW)
4954 {
4955 DPRINT("Failed to allocate buffer!\n");
4956 return ERROR_NOT_ENOUGH_MEMORY;
4957 }
4958 }
4959
4960 dwError = REnumServicesStatusExW(hSCManager,
4961 InfoLevel,
4962 dwServiceType,
4963 dwServiceState,
4964 (LPBYTE)lpStatusPtrW,
4965 cbBufSize,
4966 pcbBytesNeeded,
4967 lpServicesReturned,
4968 lpResumeIndex,
4969 pszGroupNameW);
4970
4971 /* if no services were returned then we are Done */
4972 if (*lpServicesReturned == 0)
4973 goto Done;
4974
4975 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
4976 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
4977 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
4978 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
4979 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
4980
4981 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
4982 {
4983 /* Copy the service name */
4984 WideCharToMultiByte(CP_ACP,
4985 0,
4986 lpStringPtrW,
4987 -1,
4988 lpStringPtrA,
4989 wcslen(lpStringPtrW),
4990 0,
4991 0);
4992
4993 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
4994 lpStringPtrA += wcslen(lpStringPtrW) + 1;
4995 lpStringPtrW += wcslen(lpStringPtrW) + 1;
4996
4997 /* Copy the display name */
4998 WideCharToMultiByte(CP_ACP,
4999 0,
5000 lpStringPtrW,
5001 -1,
5002 lpStringPtrA,
5003 wcslen(lpStringPtrW),
5004 0,
5005 0);
5006
5007 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5008 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5009 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5010
5011 /* Copy the status information */
5012 memcpy(&lpStatusPtrA->ServiceStatusProcess,
5013 &lpStatusPtrW->ServiceStatusProcess,
5014 sizeof(SERVICE_STATUS));
5015
5016 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
5017 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5018 lpStatusPtrA++;
5019 }
5020
5021 Done:;
5022 if (pszGroupNameW)
5023 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
5024
5025 if (lpStatusPtrW)
5026 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
5027
5028 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
5029
5030 return dwError;
5031 }
5032
5033
5034 /* Function 42 */
5035 DWORD REnumServicesStatusExW(
5036 SC_RPC_HANDLE hSCManager,
5037 SC_ENUM_TYPE InfoLevel,
5038 DWORD dwServiceType,
5039 DWORD dwServiceState,
5040 LPBYTE lpBuffer,
5041 DWORD cbBufSize,
5042 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5043 LPBOUNDED_DWORD_256K lpServicesReturned,
5044 LPBOUNDED_DWORD_256K lpResumeIndex,
5045 LPCWSTR pszGroupName)
5046 {
5047 PMANAGER_HANDLE hManager;
5048 PSERVICE lpService;
5049 DWORD dwError = ERROR_SUCCESS;
5050 PLIST_ENTRY ServiceEntry;
5051 PSERVICE CurrentService;
5052 DWORD dwState;
5053 DWORD dwRequiredSize;
5054 DWORD dwServiceCount;
5055 DWORD dwSize;
5056 DWORD dwLastResumeCount = 0;
5057 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
5058 LPWSTR lpStringPtr;
5059
5060 DPRINT("REnumServicesStatusExW() called\n");
5061
5062 if (ScmShutdown)
5063 return ERROR_SHUTDOWN_IN_PROGRESS;
5064
5065 if (InfoLevel != SC_ENUM_PROCESS_INFO)
5066 return ERROR_INVALID_LEVEL;
5067
5068 hManager = ScmGetServiceManagerFromHandle(hSCManager);
5069 if (hManager == NULL)
5070 {
5071 DPRINT1("Invalid service manager handle!\n");
5072 return ERROR_INVALID_HANDLE;
5073 }
5074
5075 *pcbBytesNeeded = 0;
5076 *lpServicesReturned = 0;
5077
5078 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
5079 {
5080 DPRINT("Not a valid Service Type!\n");
5081 return ERROR_INVALID_PARAMETER;
5082 }
5083
5084 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
5085 {
5086 DPRINT("Not a valid Service State!\n");
5087 return ERROR_INVALID_PARAMETER;
5088 }
5089
5090 /* Check access rights */
5091 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
5092 SC_MANAGER_ENUMERATE_SERVICE))
5093 {
5094 DPRINT("Insufficient access rights! 0x%lx\n",
5095 hManager->Handle.DesiredAccess);
5096 return ERROR_ACCESS_DENIED;
5097 }
5098
5099 if (lpResumeIndex)
5100 dwLastResumeCount = *lpResumeIndex;
5101
5102 /* Lock the service database shared */
5103 ScmLockDatabaseShared();
5104
5105 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
5106 if (lpService == NULL)
5107 {
5108 dwError = ERROR_SUCCESS;
5109 goto Done;
5110 }
5111
5112 dwRequiredSize = 0;
5113 dwServiceCount = 0;
5114
5115 for (ServiceEntry = &lpService->ServiceListEntry;
5116 ServiceEntry != &ServiceListHead;
5117 ServiceEntry = ServiceEntry->Flink)
5118 {
5119 CurrentService = CONTAINING_RECORD(ServiceEntry,
5120 SERVICE,
5121 ServiceListEntry);
5122
5123 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5124 continue;
5125
5126 dwState = SERVICE_ACTIVE;
5127 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5128 dwState = SERVICE_INACTIVE;
5129
5130 if ((dwState & dwServiceState) == 0)
5131 continue;
5132
5133 if (pszGroupName)
5134 {
5135 if (*pszGroupName == 0)
5136 {
5137 if (CurrentService->lpGroup != NULL)
5138 continue;
5139 }
5140 else
5141 {
5142 if ((CurrentService->lpGroup == NULL) ||
5143 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5144 continue;
5145 }
5146 }
5147
5148 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5149 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5150 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5151
5152 if (dwRequiredSize + dwSize <= cbBufSize)
5153 {
5154 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
5155 dwRequiredSize += dwSize;
5156 dwServiceCount++;
5157 dwLastResumeCount = CurrentService->dwResumeCount;
5158 }
5159 else
5160 {
5161 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
5162 break;
5163 }
5164
5165 }
5166
5167 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
5168 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
5169
5170 for (;
5171 ServiceEntry != &ServiceListHead;
5172 ServiceEntry = ServiceEntry->Flink)
5173 {
5174 CurrentService = CONTAINING_RECORD(ServiceEntry,
5175 SERVICE,
5176 ServiceListEntry);
5177
5178 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5179 continue;
5180
5181 dwState = SERVICE_ACTIVE;
5182 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5183 dwState = SERVICE_INACTIVE;
5184
5185 if ((dwState & dwServiceState) == 0)
5186 continue;
5187
5188 if (pszGroupName)
5189 {
5190 if (*pszGroupName == 0)
5191 {
5192 if (CurrentService->lpGroup != NULL)
5193 continue;
5194 }
5195 else
5196 {
5197 if ((CurrentService->lpGroup == NULL) ||
5198 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5199 continue;
5200 }
5201 }
5202
5203 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5204 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5205 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
5206
5207 dwError = ERROR_MORE_DATA;
5208 }
5209
5210 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
5211
5212 if (lpResumeIndex)
5213 *lpResumeIndex = dwLastResumeCount;
5214
5215 *lpServicesReturned = dwServiceCount;
5216 *pcbBytesNeeded = dwRequiredSize;
5217
5218 /* If there was no services that matched */
5219 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
5220 {
5221 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
5222 goto Done;
5223 }
5224
5225 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
5226 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
5227 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5228
5229 dwRequiredSize = 0;
5230 for (ServiceEntry = &lpService->ServiceListEntry;
5231 ServiceEntry != &ServiceListHead;
5232 ServiceEntry = ServiceEntry->Flink)
5233 {
5234 CurrentService = CONTAINING_RECORD(ServiceEntry,
5235 SERVICE,
5236 ServiceListEntry);
5237
5238 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5239 continue;
5240
5241 dwState = SERVICE_ACTIVE;
5242 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5243 dwState = SERVICE_INACTIVE;
5244
5245 if ((dwState & dwServiceState) == 0)
5246 continue;
5247
5248 if (pszGroupName)
5249 {
5250 if (*pszGroupName == 0)
5251 {
5252 if (CurrentService->lpGroup != NULL)
5253 continue;
5254 }
5255 else
5256 {
5257 if ((CurrentService->lpGroup == NULL) ||
5258 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5259 continue;
5260 }
5261 }
5262
5263 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5264 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5265 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5266
5267 if (dwRequiredSize + dwSize <= cbBufSize)
5268 {
5269 /* Copy the service name */
5270 wcscpy(lpStringPtr,
5271 CurrentService->lpServiceName);
5272 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5273 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
5274
5275 /* Copy the display name */
5276 wcscpy(lpStringPtr,
5277 CurrentService->lpDisplayName);
5278 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5279 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
5280
5281 /* Copy the status information */
5282 memcpy(&lpStatusPtr->ServiceStatusProcess,
5283 &CurrentService->Status,
5284 sizeof(SERVICE_STATUS));
5285 lpStatusPtr->ServiceStatusProcess.dwProcessId = CurrentService->ProcessId; /* FIXME */
5286 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5287
5288 lpStatusPtr++;
5289 dwRequiredSize += dwSize;
5290 }
5291 else
5292 {
5293 break;
5294 }
5295 }
5296
5297 if (dwError == 0)
5298 {
5299 *pcbBytesNeeded = 0;
5300 if (lpResumeIndex)
5301 *lpResumeIndex = 0;
5302 }
5303
5304 Done:;
5305 /* Unlock the service database */
5306 ScmUnlockDatabase();
5307
5308 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
5309
5310 return dwError;
5311 }
5312
5313
5314 /* Function 43 */
5315 DWORD RSendTSMessage(
5316 handle_t BindingHandle) /* FIXME */
5317 {
5318 UNIMPLEMENTED;
5319 return ERROR_CALL_NOT_IMPLEMENTED;
5320 }
5321
5322
5323 /* Function 44 */
5324 DWORD RCreateServiceWOW64A(
5325 handle_t BindingHandle,
5326 LPSTR lpServiceName,
5327 LPSTR lpDisplayName,
5328 DWORD dwDesiredAccess,
5329 DWORD dwServiceType,
5330 DWORD dwStartType,
5331 DWORD dwErrorControl,
5332 LPSTR lpBinaryPathName,
5333 LPSTR lpLoadOrderGroup,
5334 LPDWORD lpdwTagId,
5335 LPBYTE lpDependencies,
5336 DWORD dwDependSize,
5337 LPSTR lpServiceStartName,
5338 LPBYTE lpPassword,
5339 DWORD dwPwSize,
5340 LPSC_RPC_HANDLE lpServiceHandle)
5341 {
5342 UNIMPLEMENTED;
5343 return ERROR_CALL_NOT_IMPLEMENTED;
5344 }
5345
5346
5347 /* Function 45 */
5348 DWORD RCreateServiceWOW64W(
5349 handle_t BindingHandle,
5350 LPWSTR lpServiceName,
5351 LPWSTR lpDisplayName,
5352 DWORD dwDesiredAccess,
5353 DWORD dwServiceType,
5354 DWORD dwStartType,
5355 DWORD dwErrorControl,
5356 LPWSTR lpBinaryPathName,
5357 LPWSTR lpLoadOrderGroup,
5358 LPDWORD lpdwTagId,
5359 LPBYTE lpDependencies,
5360 DWORD dwDependSize,
5361 LPWSTR lpServiceStartName,
5362 LPBYTE lpPassword,
5363 DWORD dwPwSize,
5364 LPSC_RPC_HANDLE lpServiceHandle)
5365 {
5366 UNIMPLEMENTED;
5367 return ERROR_CALL_NOT_IMPLEMENTED;
5368 }
5369
5370
5371 /* Function 46 */
5372 DWORD RQueryServiceTagInfo(
5373 handle_t BindingHandle) /* FIXME */
5374 {
5375 UNIMPLEMENTED;
5376 return ERROR_CALL_NOT_IMPLEMENTED;
5377 }
5378
5379
5380 /* Function 47 */
5381 DWORD RNotifyServiceStatusChange(
5382 SC_RPC_HANDLE hService,
5383 SC_RPC_NOTIFY_PARAMS NotifyParams,
5384 GUID *pClientProcessGuid,
5385 GUID *pSCMProcessGuid,
5386 PBOOL pfCreateRemoteQueue,
5387 LPSC_NOTIFY_RPC_HANDLE phNotify)
5388 {
5389 UNIMPLEMENTED;
5390 return ERROR_CALL_NOT_IMPLEMENTED;
5391 }
5392
5393
5394 /* Function 48 */
5395 DWORD RGetNotifyResults(
5396 SC_NOTIFY_RPC_HANDLE hNotify,
5397 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5398 {
5399 UNIMPLEMENTED;
5400 return ERROR_CALL_NOT_IMPLEMENTED;
5401 }
5402
5403
5404 /* Function 49 */
5405 DWORD RCloseNotifyHandle(
5406 LPSC_NOTIFY_RPC_HANDLE phNotify,
5407 PBOOL pfApcFired)
5408 {
5409 UNIMPLEMENTED;
5410 return ERROR_CALL_NOT_IMPLEMENTED;
5411 }
5412
5413
5414 /* Function 50 */
5415 DWORD RControlServiceExA(
5416 SC_RPC_HANDLE hService,
5417 DWORD dwControl,
5418 DWORD dwInfoLevel)
5419 {
5420 UNIMPLEMENTED;
5421 return ERROR_CALL_NOT_IMPLEMENTED;
5422 }
5423
5424
5425 /* Function 51 */
5426 DWORD RControlServiceExW(
5427 SC_RPC_HANDLE hService,
5428 DWORD dwControl,
5429 DWORD dwInfoLevel)
5430 {
5431 UNIMPLEMENTED;
5432 return ERROR_CALL_NOT_IMPLEMENTED;
5433 }
5434
5435
5436 /* Function 52 */
5437 DWORD RSendPnPMessage(
5438 handle_t BindingHandle) /* FIXME */
5439 {
5440 UNIMPLEMENTED;
5441 return ERROR_CALL_NOT_IMPLEMENTED;
5442 }
5443
5444
5445 /* Function 53 */
5446 DWORD RValidatePnPService(
5447 handle_t BindingHandle) /* FIXME */
5448 {
5449 UNIMPLEMENTED;
5450 return ERROR_CALL_NOT_IMPLEMENTED;
5451 }
5452
5453
5454 /* Function 54 */
5455 DWORD ROpenServiceStatusHandle(
5456 handle_t BindingHandle) /* FIXME */
5457 {
5458 UNIMPLEMENTED;
5459 return ERROR_CALL_NOT_IMPLEMENTED;
5460 }
5461
5462
5463 /* Function 55 */
5464 DWORD RFunction55(
5465 handle_t BindingHandle) /* FIXME */
5466 {
5467 UNIMPLEMENTED;
5468 return ERROR_CALL_NOT_IMPLEMENTED;
5469 }
5470
5471
5472 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
5473 {
5474 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5475 }
5476
5477
5478 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5479 {
5480 HeapFree(GetProcessHeap(), 0, ptr);
5481 }
5482
5483
5484 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5485 {
5486 }
5487
5488
5489 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5490 {
5491 }
5492
5493
5494 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5495 {
5496 }
5497
5498 /* EOF */