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