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