[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 = (MANAGER_HANDLE*) HeapAlloc(GetProcessHeap(),
157 HEAP_ZERO_MEMORY,
158 sizeof(MANAGER_HANDLE) + (wcslen(lpDatabaseName) + 1) * sizeof(WCHAR));
159 if (Ptr == NULL)
160 return ERROR_NOT_ENOUGH_MEMORY;
161
162 Ptr->Handle.Tag = MANAGER_TAG;
163
164 wcscpy(Ptr->DatabaseName, lpDatabaseName);
165
166 *Handle = (SC_HANDLE)Ptr;
167
168 return ERROR_SUCCESS;
169 }
170
171
172 static DWORD
173 ScmCreateServiceHandle(PSERVICE lpServiceEntry,
174 SC_HANDLE *Handle)
175 {
176 PSERVICE_HANDLE Ptr;
177
178 Ptr = (SERVICE_HANDLE*) HeapAlloc(GetProcessHeap(),
179 HEAP_ZERO_MEMORY,
180 sizeof(SERVICE_HANDLE));
181 if (Ptr == NULL)
182 return ERROR_NOT_ENOUGH_MEMORY;
183
184 Ptr->Handle.Tag = SERVICE_TAG;
185
186 Ptr->ServiceEntry = lpServiceEntry;
187
188 *Handle = (SC_HANDLE)Ptr;
189
190 return ERROR_SUCCESS;
191 }
192
193
194 static PMANAGER_HANDLE
195 ScmGetServiceManagerFromHandle(SC_RPC_HANDLE Handle)
196 {
197 PMANAGER_HANDLE pManager = NULL;
198
199 _SEH2_TRY
200 {
201 if (((PMANAGER_HANDLE)Handle)->Handle.Tag == MANAGER_TAG)
202 pManager = (PMANAGER_HANDLE)Handle;
203 }
204 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
205 {
206 DPRINT1("Exception: Invalid Service Manager handle!\n");
207 }
208 _SEH2_END;
209
210 return pManager;
211 }
212
213
214 static PSERVICE_HANDLE
215 ScmGetServiceFromHandle(SC_RPC_HANDLE Handle)
216 {
217 PSERVICE_HANDLE pService = NULL;
218
219 _SEH2_TRY
220 {
221 if (((PSERVICE_HANDLE)Handle)->Handle.Tag == SERVICE_TAG)
222 pService = (PSERVICE_HANDLE)Handle;
223 }
224 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
225 {
226 DPRINT1("Exception: Invalid Service handle!\n");
227 }
228 _SEH2_END;
229
230 return pService;
231 }
232
233
234 static DWORD
235 ScmCheckAccess(SC_HANDLE Handle,
236 DWORD dwDesiredAccess)
237 {
238 PMANAGER_HANDLE hMgr;
239
240 hMgr = (PMANAGER_HANDLE)Handle;
241 if (hMgr->Handle.Tag == MANAGER_TAG)
242 {
243 RtlMapGenericMask(&dwDesiredAccess,
244 &ScmManagerMapping);
245
246 hMgr->Handle.DesiredAccess = dwDesiredAccess;
247
248 return ERROR_SUCCESS;
249 }
250 else if (hMgr->Handle.Tag == SERVICE_TAG)
251 {
252 RtlMapGenericMask(&dwDesiredAccess,
253 &ScmServiceMapping);
254
255 hMgr->Handle.DesiredAccess = dwDesiredAccess;
256
257 return ERROR_SUCCESS;
258 }
259
260 return ERROR_INVALID_HANDLE;
261 }
262
263
264 DWORD
265 ScmAssignNewTag(PSERVICE lpService)
266 {
267 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 = (LPWSTR)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 = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1582 if (*RelativeName == NULL)
1583 {
1584 DPRINT("Error allocating memory for boot driver name!\n");
1585 return ERROR_NOT_ENOUGH_MEMORY;
1586 }
1587
1588 /* Copy it */
1589 wcscpy(*RelativeName, CanonName);
1590
1591 DPRINT("Bootdriver name %S\n", *RelativeName);
1592 return ERROR_SUCCESS;
1593 }
1594
1595 /* If it has %SystemRoot% prefix, substitute it to \System*/
1596 if (ServiceNameLen > 13 &&
1597 !_wcsnicmp(L"%SystemRoot%\\", CanonName, 13))
1598 {
1599 /* There is no +sizeof(wchar_t) because the name is less by 1 wchar */
1600 *RelativeName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR));
1601
1602 if (*RelativeName == NULL)
1603 {
1604 DPRINT("Error allocating memory for boot driver name!\n");
1605 return ERROR_NOT_ENOUGH_MEMORY;
1606 }
1607
1608 /* Copy it */
1609 wcscpy(*RelativeName, L"\\SystemRoot\\");
1610 wcscat(*RelativeName, CanonName + 13);
1611
1612 DPRINT("Bootdriver name %S\n", *RelativeName);
1613 return ERROR_SUCCESS;
1614 }
1615
1616 /* Get buffer size needed for expanding env strings */
1617 BufferSize = ExpandEnvironmentStringsW(L"%SystemRoot%\\", &Dest, 1);
1618
1619 if (BufferSize <= 1)
1620 {
1621 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1622 return ERROR_INVALID_ENVIRONMENT;
1623 }
1624
1625 /* Allocate memory, since the size is known now */
1626 Expanded = LocalAlloc(LMEM_ZEROINIT, BufferSize * sizeof(WCHAR) + sizeof(WCHAR));
1627 if (!Expanded)
1628 {
1629 DPRINT("Error allocating memory for boot driver name!\n");
1630 return ERROR_NOT_ENOUGH_MEMORY;
1631 }
1632
1633 /* Expand it */
1634 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
1635 BufferSize)
1636 {
1637 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
1638 LocalFree(Expanded);
1639 return ERROR_NOT_ENOUGH_MEMORY;
1640 }
1641
1642 /* Convert to NY-style path */
1643 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
1644 {
1645 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
1646 return ERROR_INVALID_ENVIRONMENT;
1647 }
1648
1649 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
1650
1651 /* No need to keep the dos-path anymore */
1652 LocalFree(Expanded);
1653
1654 /* Copy it to the allocated place */
1655 Expanded = LocalAlloc(LMEM_ZEROINIT, NtPathName.Length + sizeof(WCHAR));
1656 if (!Expanded)
1657 {
1658 DPRINT("Error allocating memory for boot driver name!\n");
1659 return ERROR_NOT_ENOUGH_MEMORY;
1660 }
1661
1662 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
1663 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
1664 Expanded[ExpandedLen] = 0;
1665
1666 if (ServiceNameLen > ExpandedLen &&
1667 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
1668 {
1669 /* Only \SystemRoot\ is missing */
1670 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1671 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1672 if (*RelativeName == NULL)
1673 {
1674 DPRINT("Error allocating memory for boot driver name!\n");
1675 LocalFree(Expanded);
1676 return ERROR_NOT_ENOUGH_MEMORY;
1677 }
1678
1679 wcscpy(*RelativeName, L"\\SystemRoot\\");
1680 wcscat(*RelativeName, CanonName + ExpandedLen);
1681
1682 RtlFreeUnicodeString(&NtPathName);
1683 return ERROR_SUCCESS;
1684 }
1685
1686 /* The most complex case starts here */
1687 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
1688 InitializeObjectAttributes(&ObjectAttributes,
1689 &SystemRoot,
1690 OBJ_CASE_INSENSITIVE,
1691 NULL,
1692 NULL);
1693
1694 /* Open this symlink */
1695 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
1696
1697 if (NT_SUCCESS(Status))
1698 {
1699 LinkTarget.Length = 0;
1700 LinkTarget.MaximumLength = 0;
1701
1702 DPRINT("Opened symbolic link object\n");
1703
1704 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1705 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
1706 {
1707 /* Check if required buffer size is sane */
1708 if (BufferSize > 0xFFFD)
1709 {
1710 DPRINT("Too large buffer required\n");
1711 *RelativeName = 0;
1712
1713 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1714 LocalFree(Expanded);
1715 return ERROR_NOT_ENOUGH_MEMORY;
1716 }
1717
1718 /* Alloc the string */
1719 LinkTarget.Buffer = LocalAlloc(LMEM_ZEROINIT, BufferSize + sizeof(WCHAR));
1720 if (!LinkTarget.Buffer)
1721 {
1722 DPRINT("Unable to alloc buffer\n");
1723 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1724 LocalFree(Expanded);
1725 return ERROR_NOT_ENOUGH_MEMORY;
1726 }
1727
1728 /* Do a real query now */
1729 LinkTarget.Length = (USHORT)BufferSize;
1730 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(WCHAR);
1731
1732 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
1733 if (NT_SUCCESS(Status))
1734 {
1735 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
1736
1737 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
1738 if ((ServiceNameLen > ExpandedLen) &&
1739 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
1740 {
1741 *RelativeName = LocalAlloc(LMEM_ZEROINIT,
1742 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
1743
1744 if (*RelativeName == NULL)
1745 {
1746 DPRINT("Unable to alloc buffer\n");
1747 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1748 LocalFree(Expanded);
1749 RtlFreeUnicodeString(&NtPathName);
1750 return ERROR_NOT_ENOUGH_MEMORY;
1751 }
1752
1753 /* Copy it over, substituting the first part
1754 with SystemRoot */
1755 wcscpy(*RelativeName, L"\\SystemRoot\\");
1756 wcscat(*RelativeName, CanonName+ExpandedLen+1);
1757
1758 /* Cleanup */
1759 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1760 LocalFree(Expanded);
1761 RtlFreeUnicodeString(&NtPathName);
1762
1763 /* Return success */
1764 return ERROR_SUCCESS;
1765 }
1766 else
1767 {
1768 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1769 LocalFree(Expanded);
1770 RtlFreeUnicodeString(&NtPathName);
1771 return ERROR_INVALID_PARAMETER;
1772 }
1773 }
1774 else
1775 {
1776 DPRINT("Error, Status = %08X\n", Status);
1777 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1778 LocalFree(Expanded);
1779 RtlFreeUnicodeString(&NtPathName);
1780 return ERROR_INVALID_PARAMETER;
1781 }
1782 }
1783 else
1784 {
1785 DPRINT("Error, Status = %08X\n", Status);
1786 if (SymbolicLinkHandle) NtClose(SymbolicLinkHandle);
1787 LocalFree(Expanded);
1788 RtlFreeUnicodeString(&NtPathName);
1789 return ERROR_INVALID_PARAMETER;
1790 }
1791 }
1792 else
1793 {
1794 DPRINT("Error, Status = %08X\n", Status);
1795 LocalFree(Expanded);
1796 return ERROR_INVALID_PARAMETER;
1797 }
1798
1799 /* Failure */
1800 *RelativeName = NULL;
1801 return ERROR_INVALID_PARAMETER;
1802 }
1803
1804 DWORD
1805 ScmCanonDriverImagePath(DWORD dwStartType,
1806 const wchar_t *lpServiceName,
1807 wchar_t **lpCanonName)
1808 {
1809 DWORD ServiceNameLen, Result;
1810 UNICODE_STRING NtServiceName;
1811 WCHAR *RelativeName;
1812 const WCHAR *SourceName = lpServiceName;
1813
1814 /* Calculate the length of the service's name */
1815 ServiceNameLen = wcslen(lpServiceName);
1816
1817 /* 12 is wcslen(L"\\SystemRoot\\") */
1818 if (ServiceNameLen > 12 &&
1819 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
1820 {
1821 /* SystemRoot prefix is already included */
1822
1823 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1824
1825 if (*lpCanonName == NULL)
1826 {
1827 DPRINT("Error allocating memory for canonized service name!\n");
1828 return ERROR_NOT_ENOUGH_MEMORY;
1829 }
1830
1831 /* If it's a boot-time driver, it must be systemroot relative */
1832 if (dwStartType == SERVICE_BOOT_START)
1833 SourceName += 12;
1834
1835 /* Copy it */
1836 wcscpy(*lpCanonName, SourceName);
1837
1838 DPRINT("Canonicalized name %S\n", *lpCanonName);
1839 return NO_ERROR;
1840 }
1841
1842 /* Check if it has %SystemRoot% (len=13) */
1843 if (ServiceNameLen > 13 &&
1844 !_wcsnicmp(L"%%SystemRoot%%\\", lpServiceName, 13))
1845 {
1846 /* Substitute %SystemRoot% with \\SystemRoot\\ */
1847 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1848
1849 if (*lpCanonName == NULL)
1850 {
1851 DPRINT("Error allocating memory for canonized service name!\n");
1852 return ERROR_NOT_ENOUGH_MEMORY;
1853 }
1854
1855 /* If it's a boot-time driver, it must be systemroot relative */
1856 if (dwStartType == SERVICE_BOOT_START)
1857 wcscpy(*lpCanonName, L"\\SystemRoot\\");
1858
1859 wcscat(*lpCanonName, lpServiceName + 13);
1860
1861 DPRINT("Canonicalized name %S\n", *lpCanonName);
1862 return NO_ERROR;
1863 }
1864
1865 /* Check if it's a relative path name */
1866 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
1867 {
1868 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, ServiceNameLen * sizeof(WCHAR) + sizeof(WCHAR));
1869
1870 if (*lpCanonName == NULL)
1871 {
1872 DPRINT("Error allocating memory for canonized service name!\n");
1873 return ERROR_NOT_ENOUGH_MEMORY;
1874 }
1875
1876 /* Just copy it over without changing */
1877 wcscpy(*lpCanonName, lpServiceName);
1878
1879 return NO_ERROR;
1880 }
1881
1882 /* It seems to be a DOS path, convert it */
1883 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
1884 {
1885 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
1886 return ERROR_INVALID_PARAMETER;
1887 }
1888
1889 *lpCanonName = LocalAlloc(LMEM_ZEROINIT, NtServiceName.Length + sizeof(WCHAR));
1890
1891 if (*lpCanonName == NULL)
1892 {
1893 DPRINT("Error allocating memory for canonized service name!\n");
1894 RtlFreeUnicodeString(&NtServiceName);
1895 return ERROR_NOT_ENOUGH_MEMORY;
1896 }
1897
1898 /* Copy the string */
1899 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
1900
1901 /* The unicode string is not needed anymore */
1902 RtlFreeUnicodeString(&NtServiceName);
1903
1904 if (dwStartType != SERVICE_BOOT_START)
1905 {
1906 DPRINT("Canonicalized name %S\n", *lpCanonName);
1907 return NO_ERROR;
1908 }
1909
1910 /* The service is boot-started, so must be relative */
1911 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
1912 if (Result)
1913 {
1914 /* There is a problem, free name and return */
1915 LocalFree(*lpCanonName);
1916 DPRINT("Error converting named!\n");
1917 return Result;
1918 }
1919
1920 ASSERT(RelativeName);
1921
1922 /* Copy that string */
1923 wcscpy(*lpCanonName, RelativeName + 12);
1924
1925 /* Free the allocated buffer */
1926 LocalFree(RelativeName);
1927
1928 DPRINT("Canonicalized name %S\n", *lpCanonName);
1929
1930 /* Success */
1931 return NO_ERROR;
1932 }
1933
1934
1935 /* Function 12 */
1936 DWORD RCreateServiceW(
1937 SC_RPC_HANDLE hSCManager,
1938 LPCWSTR lpServiceName,
1939 LPCWSTR lpDisplayName,
1940 DWORD dwDesiredAccess,
1941 DWORD dwServiceType,
1942 DWORD dwStartType,
1943 DWORD dwErrorControl,
1944 LPCWSTR lpBinaryPathName,
1945 LPCWSTR lpLoadOrderGroup,
1946 LPDWORD lpdwTagId,
1947 LPBYTE lpDependencies,
1948 DWORD dwDependSize,
1949 LPCWSTR lpServiceStartName,
1950 LPBYTE lpPassword,
1951 DWORD dwPwSize,
1952 LPSC_RPC_HANDLE lpServiceHandle)
1953 {
1954 PMANAGER_HANDLE hManager;
1955 DWORD dwError = ERROR_SUCCESS;
1956 PSERVICE lpService = NULL;
1957 SC_HANDLE hServiceHandle = NULL;
1958 LPWSTR lpImagePath = NULL;
1959 HKEY hServiceKey = NULL;
1960 LPWSTR lpObjectName;
1961
1962 DPRINT("RCreateServiceW() called\n");
1963 DPRINT("lpServiceName = %S\n", lpServiceName);
1964 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1965 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
1966 DPRINT("dwServiceType = %lu\n", dwServiceType);
1967 DPRINT("dwStartType = %lu\n", dwStartType);
1968 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1969 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1970 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1971 DPRINT("lpdwTagId = %p\n", lpdwTagId);
1972
1973 if (ScmShutdown)
1974 return ERROR_SHUTDOWN_IN_PROGRESS;
1975
1976 hManager = ScmGetServiceManagerFromHandle(hSCManager);
1977 if (hManager == NULL)
1978 {
1979 DPRINT1("Invalid service manager handle!\n");
1980 return ERROR_INVALID_HANDLE;
1981 }
1982
1983 /* Check access rights */
1984 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
1985 SC_MANAGER_CREATE_SERVICE))
1986 {
1987 DPRINT("Insufficient access rights! 0x%lx\n",
1988 hManager->Handle.DesiredAccess);
1989 return ERROR_ACCESS_DENIED;
1990 }
1991
1992 if (wcslen(lpServiceName) == 0)
1993 {
1994 return ERROR_INVALID_NAME;
1995 }
1996
1997 if (wcslen(lpBinaryPathName) == 0)
1998 {
1999 return ERROR_INVALID_PARAMETER;
2000 }
2001
2002 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2003 (lpServiceStartName))
2004 {
2005 return ERROR_INVALID_PARAMETER;
2006 }
2007
2008 if ((dwServiceType > SERVICE_WIN32_SHARE_PROCESS) &&
2009 (dwServiceType != (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2010 (dwServiceType != (SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)))
2011 {
2012 return ERROR_INVALID_PARAMETER;
2013 }
2014
2015 if (dwStartType > SERVICE_DISABLED)
2016 {
2017 return ERROR_INVALID_PARAMETER;
2018 }
2019
2020 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2021 {
2022 return ERROR_INVALID_PARAMETER;
2023 }
2024
2025 /* Lock the service database exclusively */
2026 ScmLockDatabaseExclusive();
2027
2028 lpService = ScmGetServiceEntryByName(lpServiceName);
2029 if (lpService)
2030 {
2031 /* Unlock the service database */
2032 ScmUnlockDatabase();
2033
2034 /* check if it is marked for deletion */
2035 if (lpService->bDeleted)
2036 return ERROR_SERVICE_MARKED_FOR_DELETE;
2037 /* Return Error exist */
2038 return ERROR_SERVICE_EXISTS;
2039 }
2040
2041 if (lpDisplayName != NULL &&
2042 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2043 {
2044 /* Unlock the service database */
2045 ScmUnlockDatabase();
2046
2047 return ERROR_DUPLICATE_SERVICE_NAME;
2048 }
2049
2050 if (dwServiceType & SERVICE_DRIVER)
2051 {
2052 dwError = ScmCanonDriverImagePath(dwStartType,
2053 lpBinaryPathName,
2054 &lpImagePath);
2055 if (dwError != ERROR_SUCCESS)
2056 goto done;
2057 }
2058 else
2059 {
2060 if (dwStartType == SERVICE_BOOT_START ||
2061 dwStartType == SERVICE_SYSTEM_START)
2062 {
2063 /* Unlock the service database */
2064 ScmUnlockDatabase();
2065
2066 return ERROR_INVALID_PARAMETER;
2067 }
2068 }
2069
2070 /* Allocate a new service entry */
2071 dwError = ScmCreateNewServiceRecord(lpServiceName,
2072 &lpService);
2073 if (dwError != ERROR_SUCCESS)
2074 goto done;
2075
2076 /* Fill the new service entry */
2077 lpService->Status.dwServiceType = dwServiceType;
2078 lpService->dwStartType = dwStartType;
2079 lpService->dwErrorControl = dwErrorControl;
2080
2081 /* Fill the display name */
2082 if (lpDisplayName != NULL &&
2083 *lpDisplayName != 0 &&
2084 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2085 {
2086 lpService->lpDisplayName = (WCHAR*) HeapAlloc(GetProcessHeap(), 0,
2087 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2088 if (lpService->lpDisplayName == NULL)
2089 {
2090 dwError = ERROR_NOT_ENOUGH_MEMORY;
2091 goto done;
2092 }
2093 wcscpy(lpService->lpDisplayName, lpDisplayName);
2094 }
2095
2096 /* Assign the service to a group */
2097 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2098 {
2099 dwError = ScmSetServiceGroup(lpService,
2100 lpLoadOrderGroup);
2101 if (dwError != ERROR_SUCCESS)
2102 goto done;
2103 }
2104
2105 /* Assign a new tag */
2106 if (lpdwTagId != NULL)
2107 {
2108 dwError = ScmAssignNewTag(lpService);
2109 if (dwError != ERROR_SUCCESS)
2110 goto done;
2111 }
2112
2113 /* Write service data to the registry */
2114 /* Create the service key */
2115 dwError = ScmCreateServiceKey(lpServiceName,
2116 KEY_WRITE,
2117 &hServiceKey);
2118 if (dwError != ERROR_SUCCESS)
2119 goto done;
2120
2121 /* Set the display name */
2122 if (lpDisplayName != NULL && *lpDisplayName != 0)
2123 {
2124 RegSetValueExW(hServiceKey,
2125 L"DisplayName",
2126 0,
2127 REG_SZ,
2128 (LPBYTE)lpDisplayName,
2129 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2130 }
2131
2132 /* Set the service type */
2133 dwError = RegSetValueExW(hServiceKey,
2134 L"Type",
2135 0,
2136 REG_DWORD,
2137 (LPBYTE)&dwServiceType,
2138 sizeof(DWORD));
2139 if (dwError != ERROR_SUCCESS)
2140 goto done;
2141
2142 /* Set the start value */
2143 dwError = RegSetValueExW(hServiceKey,
2144 L"Start",
2145 0,
2146 REG_DWORD,
2147 (LPBYTE)&dwStartType,
2148 sizeof(DWORD));
2149 if (dwError != ERROR_SUCCESS)
2150 goto done;
2151
2152 /* Set the error control value */
2153 dwError = RegSetValueExW(hServiceKey,
2154 L"ErrorControl",
2155 0,
2156 REG_DWORD,
2157 (LPBYTE)&dwErrorControl,
2158 sizeof(DWORD));
2159 if (dwError != ERROR_SUCCESS)
2160 goto done;
2161
2162 /* Set the image path */
2163 if (dwServiceType & SERVICE_WIN32)
2164 {
2165 dwError = RegSetValueExW(hServiceKey,
2166 L"ImagePath",
2167 0,
2168 REG_EXPAND_SZ,
2169 (LPBYTE)lpBinaryPathName,
2170 (wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR));
2171 if (dwError != ERROR_SUCCESS)
2172 goto done;
2173 }
2174 else if (dwServiceType & SERVICE_DRIVER)
2175 {
2176 dwError = RegSetValueExW(hServiceKey,
2177 L"ImagePath",
2178 0,
2179 REG_EXPAND_SZ,
2180 (LPBYTE)lpImagePath,
2181 (wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2182 if (dwError != ERROR_SUCCESS)
2183 goto done;
2184 }
2185
2186 /* Set the group name */
2187 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2188 {
2189 dwError = RegSetValueExW(hServiceKey,
2190 L"Group",
2191 0,
2192 REG_SZ,
2193 (LPBYTE)lpLoadOrderGroup,
2194 (wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
2195 if (dwError != ERROR_SUCCESS)
2196 goto done;
2197 }
2198
2199 if (lpdwTagId != NULL)
2200 {
2201 dwError = RegSetValueExW(hServiceKey,
2202 L"Tag",
2203 0,
2204 REG_DWORD,
2205 (LPBYTE)&lpService->dwTag,
2206 sizeof(DWORD));
2207 if (dwError != ERROR_SUCCESS)
2208 goto done;
2209 }
2210
2211 /* Write dependencies */
2212 if (lpDependencies != NULL && *lpDependencies != 0)
2213 {
2214 dwError = ScmWriteDependencies(hServiceKey,
2215 (LPWSTR)lpDependencies,
2216 dwDependSize);
2217 if (dwError != ERROR_SUCCESS)
2218 goto done;
2219 }
2220
2221 /* Write service start name */
2222 if (dwServiceType & SERVICE_WIN32)
2223 {
2224 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2225 dwError = RegSetValueExW(hServiceKey,
2226 L"ObjectName",
2227 0,
2228 REG_SZ,
2229 (LPBYTE)lpObjectName,
2230 (wcslen(lpObjectName) + 1) * sizeof(WCHAR));
2231 if (dwError != ERROR_SUCCESS)
2232 goto done;
2233 }
2234
2235 if (lpPassword != NULL)
2236 {
2237 /* FIXME: Write password */
2238 }
2239
2240 dwError = ScmCreateServiceHandle(lpService,
2241 &hServiceHandle);
2242 if (dwError != ERROR_SUCCESS)
2243 goto done;
2244
2245 dwError = ScmCheckAccess(hServiceHandle,
2246 dwDesiredAccess);
2247 if (dwError != ERROR_SUCCESS)
2248 goto done;
2249
2250 lpService->dwRefCount = 1;
2251 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2252
2253 done:;
2254 /* Unlock the service database */
2255 ScmUnlockDatabase();
2256
2257 if (hServiceKey != NULL)
2258 RegCloseKey(hServiceKey);
2259
2260 if (dwError == ERROR_SUCCESS)
2261 {
2262 DPRINT("hService %p\n", hServiceHandle);
2263 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2264
2265 if (lpdwTagId != NULL)
2266 *lpdwTagId = lpService->dwTag;
2267 }
2268 else
2269 {
2270 /* Release the display name buffer */
2271 if (lpService->lpServiceName != NULL)
2272 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2273
2274 if (hServiceHandle)
2275 {
2276 /* Remove the service handle */
2277 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2278 }
2279
2280 if (lpService != NULL)
2281 {
2282 /* FIXME: remove the service entry */
2283 }
2284 }
2285
2286 if (lpImagePath != NULL)
2287 HeapFree(GetProcessHeap(), 0, lpImagePath);
2288
2289 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2290
2291 return dwError;
2292 }
2293
2294
2295 /* Function 13 */
2296 DWORD REnumDependentServicesW(
2297 SC_RPC_HANDLE hService,
2298 DWORD dwServiceState,
2299 LPBYTE lpServices,
2300 DWORD cbBufSize,
2301 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2302 LPBOUNDED_DWORD_256K lpServicesReturned)
2303 {
2304 DWORD dwError = ERROR_SUCCESS;
2305 DWORD dwServicesReturned = 0;
2306 DWORD dwServiceCount;
2307 HKEY hServicesKey = NULL;
2308 PSERVICE_HANDLE hSvc;
2309 PSERVICE lpService = NULL;
2310 PSERVICE *lpServicesArray = NULL;
2311 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2312 LPWSTR lpStr;
2313
2314 *pcbBytesNeeded = 0;
2315 *lpServicesReturned = 0;
2316
2317 DPRINT("REnumDependentServicesW() called\n");
2318
2319 hSvc = ScmGetServiceFromHandle(hService);
2320 if (hSvc == NULL)
2321 {
2322 DPRINT1("Invalid service handle!\n");
2323 return ERROR_INVALID_HANDLE;
2324 }
2325
2326 lpService = hSvc->ServiceEntry;
2327
2328 /* Check access rights */
2329 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2330 SC_MANAGER_ENUMERATE_SERVICE))
2331 {
2332 DPRINT("Insufficient access rights! 0x%lx\n",
2333 hSvc->Handle.DesiredAccess);
2334 return ERROR_ACCESS_DENIED;
2335 }
2336
2337 /* Open the Services Reg key */
2338 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2339 L"System\\CurrentControlSet\\Services",
2340 0,
2341 KEY_READ,
2342 &hServicesKey);
2343 if (dwError != ERROR_SUCCESS)
2344 return dwError;
2345
2346 /* First determine the bytes needed and get the number of dependent services */
2347 dwError = Int_EnumDependentServicesW(hServicesKey,
2348 lpService,
2349 dwServiceState,
2350 NULL,
2351 pcbBytesNeeded,
2352 &dwServicesReturned);
2353 if (dwError != ERROR_SUCCESS)
2354 goto Done;
2355
2356 /* If buffer size is less than the bytes needed or pointer is null */
2357 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2358 {
2359 dwError = ERROR_MORE_DATA;
2360 goto Done;
2361 }
2362
2363 /* Allocate memory for array of service pointers */
2364 lpServicesArray = HeapAlloc(GetProcessHeap(),
2365 0,
2366 (dwServicesReturned + 1) * sizeof(PSERVICE));
2367 if (!lpServicesArray)
2368 {
2369 DPRINT("Could not allocate a buffer!!\n");
2370 dwError = ERROR_NOT_ENOUGH_MEMORY;
2371 goto Done;
2372 }
2373
2374 dwServicesReturned = 0;
2375 *pcbBytesNeeded = 0;
2376
2377 dwError = Int_EnumDependentServicesW(hServicesKey,
2378 lpService,
2379 dwServiceState,
2380 lpServicesArray,
2381 pcbBytesNeeded,
2382 &dwServicesReturned);
2383 if (dwError != ERROR_SUCCESS)
2384 {
2385 goto Done;
2386 }
2387
2388 lpServicesPtr = (LPENUM_SERVICE_STATUSW) lpServices;
2389 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2390
2391 /* Copy EnumDepenedentService to Buffer */
2392 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2393 {
2394 lpService = lpServicesArray[dwServiceCount];
2395
2396 /* Copy status info */
2397 memcpy(&lpServicesPtr->ServiceStatus,
2398 &lpService->Status,
2399 sizeof(SERVICE_STATUS));
2400
2401 /* Copy display name */
2402 wcscpy(lpStr, lpService->lpDisplayName);
2403 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2404 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2405
2406 /* Copy service name */
2407 wcscpy(lpStr, lpService->lpServiceName);
2408 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2409 lpStr += (wcslen(lpService->lpServiceName) + 1);
2410
2411 lpServicesPtr ++;
2412 }
2413
2414 *lpServicesReturned = dwServicesReturned;
2415
2416 Done:
2417 if (lpServicesArray != NULL)
2418 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2419
2420 RegCloseKey(hServicesKey);
2421
2422 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2423
2424 return dwError;
2425 }
2426
2427
2428 /* Function 14 */
2429 DWORD REnumServicesStatusW(
2430 SC_RPC_HANDLE hSCManager,
2431 DWORD dwServiceType,
2432 DWORD dwServiceState,
2433 LPBYTE lpBuffer,
2434 DWORD dwBufSize,
2435 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2436 LPBOUNDED_DWORD_256K lpServicesReturned,
2437 LPBOUNDED_DWORD_256K lpResumeHandle)
2438 {
2439 PMANAGER_HANDLE hManager;
2440 PSERVICE lpService;
2441 DWORD dwError = ERROR_SUCCESS;
2442 PLIST_ENTRY ServiceEntry;
2443 PSERVICE CurrentService;
2444 DWORD dwState;
2445 DWORD dwRequiredSize;
2446 DWORD dwServiceCount;
2447 DWORD dwSize;
2448 DWORD dwLastResumeCount = 0;
2449 LPENUM_SERVICE_STATUSW lpStatusPtr;
2450 LPWSTR lpStringPtr;
2451
2452 DPRINT("REnumServicesStatusW() called\n");
2453
2454 if (ScmShutdown)
2455 return ERROR_SHUTDOWN_IN_PROGRESS;
2456
2457 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2458 if (hManager == NULL)
2459 {
2460 DPRINT1("Invalid service manager handle!\n");
2461 return ERROR_INVALID_HANDLE;
2462 }
2463
2464
2465 *pcbBytesNeeded = 0;
2466 *lpServicesReturned = 0;
2467
2468 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
2469 {
2470 DPRINT("Not a valid Service Type!\n");
2471 return ERROR_INVALID_PARAMETER;
2472 }
2473
2474 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
2475 {
2476 DPRINT("Not a valid Service State!\n");
2477 return ERROR_INVALID_PARAMETER;
2478 }
2479
2480 /* Check access rights */
2481 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2482 SC_MANAGER_ENUMERATE_SERVICE))
2483 {
2484 DPRINT("Insufficient access rights! 0x%lx\n",
2485 hManager->Handle.DesiredAccess);
2486 return ERROR_ACCESS_DENIED;
2487 }
2488
2489 if (lpResumeHandle)
2490 dwLastResumeCount = *lpResumeHandle;
2491
2492 /* Lock the service database shared */
2493 ScmLockDatabaseShared();
2494
2495 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
2496 if (lpService == NULL)
2497 {
2498 dwError = ERROR_SUCCESS;
2499 goto Done;
2500 }
2501
2502 dwRequiredSize = 0;
2503 dwServiceCount = 0;
2504
2505 for (ServiceEntry = &lpService->ServiceListEntry;
2506 ServiceEntry != &ServiceListHead;
2507 ServiceEntry = ServiceEntry->Flink)
2508 {
2509 CurrentService = CONTAINING_RECORD(ServiceEntry,
2510 SERVICE,
2511 ServiceListEntry);
2512
2513 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2514 continue;
2515
2516 dwState = SERVICE_ACTIVE;
2517 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2518 dwState = SERVICE_INACTIVE;
2519
2520 if ((dwState & dwServiceState) == 0)
2521 continue;
2522
2523 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2524 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2525 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2526
2527 if (dwRequiredSize + dwSize > dwBufSize)
2528 {
2529 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
2530 break;
2531 }
2532
2533 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
2534 dwRequiredSize += dwSize;
2535 dwServiceCount++;
2536 dwLastResumeCount = CurrentService->dwResumeCount;
2537 }
2538
2539 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
2540 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
2541
2542 for (;
2543 ServiceEntry != &ServiceListHead;
2544 ServiceEntry = ServiceEntry->Flink)
2545 {
2546 CurrentService = CONTAINING_RECORD(ServiceEntry,
2547 SERVICE,
2548 ServiceListEntry);
2549
2550 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2551 continue;
2552
2553 dwState = SERVICE_ACTIVE;
2554 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2555 dwState = SERVICE_INACTIVE;
2556
2557 if ((dwState & dwServiceState) == 0)
2558 continue;
2559
2560 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUSW) +
2561 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2562 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
2563
2564 dwError = ERROR_MORE_DATA;
2565 }
2566
2567 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
2568
2569 if (lpResumeHandle)
2570 *lpResumeHandle = dwLastResumeCount;
2571
2572 *lpServicesReturned = dwServiceCount;
2573 *pcbBytesNeeded = dwRequiredSize;
2574
2575 lpStatusPtr = (LPENUM_SERVICE_STATUSW)lpBuffer;
2576 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
2577 dwServiceCount * sizeof(ENUM_SERVICE_STATUSW));
2578
2579 dwRequiredSize = 0;
2580 for (ServiceEntry = &lpService->ServiceListEntry;
2581 ServiceEntry != &ServiceListHead;
2582 ServiceEntry = ServiceEntry->Flink)
2583 {
2584 CurrentService = CONTAINING_RECORD(ServiceEntry,
2585 SERVICE,
2586 ServiceListEntry);
2587
2588 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
2589 continue;
2590
2591 dwState = SERVICE_ACTIVE;
2592 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
2593 dwState = SERVICE_INACTIVE;
2594
2595 if ((dwState & dwServiceState) == 0)
2596 continue;
2597
2598 dwSize = sizeof(ENUM_SERVICE_STATUSW) +
2599 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
2600 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
2601
2602 if (dwRequiredSize + dwSize > dwBufSize)
2603 break;
2604
2605 /* Copy the service name */
2606 wcscpy(lpStringPtr, CurrentService->lpServiceName);
2607 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2608 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
2609
2610 /* Copy the display name */
2611 wcscpy(lpStringPtr, CurrentService->lpDisplayName);
2612 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
2613 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
2614
2615 /* Copy the status information */
2616 memcpy(&lpStatusPtr->ServiceStatus,
2617 &CurrentService->Status,
2618 sizeof(SERVICE_STATUS));
2619
2620 lpStatusPtr++;
2621 dwRequiredSize += dwSize;
2622 }
2623
2624 if (dwError == 0)
2625 {
2626 *pcbBytesNeeded = 0;
2627 if (lpResumeHandle) *lpResumeHandle = 0;
2628 }
2629
2630 Done:;
2631 /* Unlock the service database */
2632 ScmUnlockDatabase();
2633
2634 DPRINT("REnumServicesStatusW() done (Error %lu)\n", dwError);
2635
2636 return dwError;
2637 }
2638
2639
2640 /* Function 15 */
2641 DWORD ROpenSCManagerW(
2642 LPWSTR lpMachineName,
2643 LPWSTR lpDatabaseName,
2644 DWORD dwDesiredAccess,
2645 LPSC_RPC_HANDLE lpScHandle)
2646 {
2647 DWORD dwError;
2648 SC_HANDLE hHandle;
2649
2650 DPRINT("ROpenSCManagerW() called\n");
2651 DPRINT("lpMachineName = %p\n", lpMachineName);
2652 DPRINT("lpMachineName: %S\n", lpMachineName);
2653 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2654 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2655 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2656
2657 if (ScmShutdown)
2658 return ERROR_SHUTDOWN_IN_PROGRESS;
2659
2660 if (!lpScHandle)
2661 return ERROR_INVALID_PARAMETER;
2662
2663 dwError = ScmCreateManagerHandle(lpDatabaseName,
2664 &hHandle);
2665 if (dwError != ERROR_SUCCESS)
2666 {
2667 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2668 return dwError;
2669 }
2670
2671 /* Check the desired access */
2672 dwError = ScmCheckAccess(hHandle,
2673 dwDesiredAccess | SC_MANAGER_CONNECT);
2674 if (dwError != ERROR_SUCCESS)
2675 {
2676 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2677 HeapFree(GetProcessHeap(), 0, hHandle);
2678 return dwError;
2679 }
2680
2681 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2682 DPRINT("*hScm = %p\n", *lpScHandle);
2683
2684 DPRINT("ROpenSCManagerW() done\n");
2685
2686 return ERROR_SUCCESS;
2687 }
2688
2689
2690 /* Function 16 */
2691 DWORD ROpenServiceW(
2692 SC_RPC_HANDLE hSCManager,
2693 LPWSTR lpServiceName,
2694 DWORD dwDesiredAccess,
2695 LPSC_RPC_HANDLE lpServiceHandle)
2696 {
2697 PSERVICE lpService;
2698 PMANAGER_HANDLE hManager;
2699 SC_HANDLE hHandle;
2700 DWORD dwError = ERROR_SUCCESS;
2701
2702 DPRINT("ROpenServiceW() called\n");
2703 DPRINT("hSCManager = %p\n", hSCManager);
2704 DPRINT("lpServiceName = %p\n", lpServiceName);
2705 DPRINT("lpServiceName: %S\n", lpServiceName);
2706 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2707
2708 if (ScmShutdown)
2709 return ERROR_SHUTDOWN_IN_PROGRESS;
2710
2711 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2712 if (hManager == NULL)
2713 {
2714 DPRINT1("Invalid service manager handle!\n");
2715 return ERROR_INVALID_HANDLE;
2716 }
2717
2718 if (!lpServiceHandle)
2719 return ERROR_INVALID_PARAMETER;
2720
2721 if (!lpServiceName)
2722 return ERROR_INVALID_ADDRESS;
2723
2724 /* Lock the service database exclusive */
2725 ScmLockDatabaseExclusive();
2726
2727 /* Get service database entry */
2728 lpService = ScmGetServiceEntryByName(lpServiceName);
2729 if (lpService == NULL)
2730 {
2731 DPRINT("Could not find a service!\n");
2732 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2733 goto Done;
2734 }
2735
2736 /* Create a service handle */
2737 dwError = ScmCreateServiceHandle(lpService,
2738 &hHandle);
2739 if (dwError != ERROR_SUCCESS)
2740 {
2741 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2742 goto Done;
2743 }
2744
2745 /* Check the desired access */
2746 dwError = ScmCheckAccess(hHandle,
2747 dwDesiredAccess);
2748 if (dwError != ERROR_SUCCESS)
2749 {
2750 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2751 HeapFree(GetProcessHeap(), 0, hHandle);
2752 goto Done;
2753 }
2754
2755 lpService->dwRefCount++;
2756 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2757
2758 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2759 DPRINT("*hService = %p\n", *lpServiceHandle);
2760
2761 Done:;
2762 /* Unlock the service database */
2763 ScmUnlockDatabase();
2764
2765 DPRINT("ROpenServiceW() done\n");
2766
2767 return dwError;
2768 }
2769
2770
2771 /* Function 17 */
2772 DWORD RQueryServiceConfigW(
2773 SC_RPC_HANDLE hService,
2774 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2775 DWORD cbBufSize,
2776 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2777 {
2778 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2779 DWORD dwError = ERROR_SUCCESS;
2780 PSERVICE_HANDLE hSvc;
2781 PSERVICE lpService = NULL;
2782 HKEY hServiceKey = NULL;
2783 LPWSTR lpImagePath = NULL;
2784 LPWSTR lpServiceStartName = NULL;
2785 LPWSTR lpDependencies = NULL;
2786 DWORD dwDependenciesLength = 0;
2787 DWORD dwRequiredSize;
2788 LPQUERY_SERVICE_CONFIGW lpConfig = NULL;
2789 WCHAR lpEmptyString[] = {0,0};
2790 LPWSTR lpStr;
2791
2792 DPRINT("RQueryServiceConfigW() called\n");
2793
2794 if (ScmShutdown)
2795 return ERROR_SHUTDOWN_IN_PROGRESS;
2796
2797 hSvc = ScmGetServiceFromHandle(hService);
2798 if (hSvc == NULL)
2799 {
2800 DPRINT1("Invalid service handle!\n");
2801 return ERROR_INVALID_HANDLE;
2802 }
2803
2804 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2805 SERVICE_QUERY_CONFIG))
2806 {
2807 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2808 return ERROR_ACCESS_DENIED;
2809 }
2810
2811 lpService = hSvc->ServiceEntry;
2812 if (lpService == NULL)
2813 {
2814 DPRINT("lpService == NULL!\n");
2815 return ERROR_INVALID_HANDLE;
2816 }
2817
2818 /* Lock the service database shared */
2819 ScmLockDatabaseShared();
2820
2821 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2822 KEY_READ,
2823 &hServiceKey);
2824 if (dwError != ERROR_SUCCESS)
2825 goto Done;
2826
2827 /* Read the image path */
2828 dwError = ScmReadString(hServiceKey,
2829 L"ImagePath",
2830 &lpImagePath);
2831 if (dwError != ERROR_SUCCESS)
2832 goto Done;
2833
2834 /* Read the service start name */
2835 ScmReadString(hServiceKey,
2836 L"ObjectName",
2837 &lpServiceStartName);
2838
2839 /* Read the dependencies */
2840 ScmReadDependencies(hServiceKey,
2841 &lpDependencies,
2842 &dwDependenciesLength);
2843
2844 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2845
2846 if (lpImagePath != NULL)
2847 dwRequiredSize += ((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2848 else
2849 dwRequiredSize += 2 * sizeof(WCHAR);
2850
2851 if (lpService->lpGroup != NULL)
2852 dwRequiredSize += ((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2853 else
2854 dwRequiredSize += 2 * sizeof(WCHAR);
2855
2856 if (lpDependencies != NULL)
2857 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2858 else
2859 dwRequiredSize += 2 * sizeof(WCHAR);
2860
2861 if (lpServiceStartName != NULL)
2862 dwRequiredSize += ((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2863 else
2864 dwRequiredSize += 2 * sizeof(WCHAR);
2865
2866 if (lpService->lpDisplayName != NULL)
2867 dwRequiredSize += ((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2868 else
2869 dwRequiredSize += 2 * sizeof(WCHAR);
2870
2871 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2872 {
2873 dwError = ERROR_INSUFFICIENT_BUFFER;
2874 }
2875 else
2876 {
2877 lpConfig = (LPQUERY_SERVICE_CONFIGW)lpServiceConfig;
2878 lpConfig->dwServiceType = lpService->Status.dwServiceType;
2879 lpConfig->dwStartType = lpService->dwStartType;
2880 lpConfig->dwErrorControl = lpService->dwErrorControl;
2881 lpConfig->dwTagId = lpService->dwTag;
2882
2883 lpStr = (LPWSTR)(lpConfig + 1);
2884
2885 /* Append the image path */
2886 if (lpImagePath != NULL)
2887 {
2888 wcscpy(lpStr, lpImagePath);
2889 }
2890 else
2891 {
2892 wcscpy(lpStr, lpEmptyString);
2893 }
2894
2895 lpConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2896 lpStr += (wcslen(lpStr) + 1);
2897
2898 /* Append the group name */
2899 if (lpService->lpGroup != NULL)
2900 {
2901 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2902 }
2903 else
2904 {
2905 wcscpy(lpStr, lpEmptyString);
2906 }
2907
2908 lpConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2909 lpStr += (wcslen(lpStr) + 1);
2910
2911 /* Append Dependencies */
2912 if (lpDependencies != NULL)
2913 {
2914 memcpy(lpStr,
2915 lpDependencies,
2916 dwDependenciesLength * sizeof(WCHAR));
2917 }
2918 else
2919 {
2920 wcscpy(lpStr, lpEmptyString);
2921 }
2922
2923 lpConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2924 if (lpDependencies != NULL)
2925 lpStr += dwDependenciesLength * sizeof(WCHAR);
2926 else
2927 lpStr += (wcslen(lpStr) + 1);
2928
2929 /* Append the service start name */
2930 if (lpServiceStartName != NULL)
2931 {
2932 wcscpy(lpStr, lpServiceStartName);
2933 }
2934 else
2935 {
2936 wcscpy(lpStr, lpEmptyString);
2937 }
2938
2939 lpConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2940 lpStr += (wcslen(lpStr) + 1);
2941
2942 /* Append the display name */
2943 if (lpService->lpDisplayName != NULL)
2944 {
2945 wcscpy(lpStr, lpService->lpDisplayName);
2946 }
2947 else
2948 {
2949 wcscpy(lpStr, lpEmptyString);
2950 }
2951
2952 lpConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
2953 }
2954
2955 if (pcbBytesNeeded != NULL)
2956 *pcbBytesNeeded = dwRequiredSize;
2957
2958 Done:;
2959 /* Unlock the service database */
2960 ScmUnlockDatabase();
2961
2962 if (lpImagePath != NULL)
2963 HeapFree(GetProcessHeap(), 0, lpImagePath);
2964
2965 if (lpServiceStartName != NULL)
2966 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2967
2968 if (lpDependencies != NULL)
2969 HeapFree(GetProcessHeap(), 0, lpDependencies);
2970
2971 if (hServiceKey != NULL)
2972 RegCloseKey(hServiceKey);
2973
2974 DPRINT("RQueryServiceConfigW() done\n");
2975
2976 return dwError;
2977 }
2978
2979
2980 /* Function 18 */
2981 DWORD RQueryServiceLockStatusW(
2982 SC_RPC_HANDLE hSCManager,
2983 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2984 DWORD cbBufSize,
2985 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2986 {
2987 UNIMPLEMENTED;
2988 return ERROR_CALL_NOT_IMPLEMENTED;
2989 }
2990
2991
2992 /* Function 19 */
2993 DWORD RStartServiceW(
2994 SC_RPC_HANDLE hService,
2995 DWORD argc,
2996 LPSTRING_PTRSW argv)
2997 {
2998 DWORD dwError = ERROR_SUCCESS;
2999 PSERVICE_HANDLE hSvc;
3000 PSERVICE lpService = NULL;
3001 DWORD i;
3002
3003 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3004 DPRINT(" argc: %lu\n", argc);
3005 if (argv != NULL)
3006 {
3007 for (i = 0; i < argc; i++)
3008 {
3009 DPRINT(" argv[%lu]: %S\n", i, argv[i]);
3010 }
3011 }
3012
3013 if (ScmShutdown)
3014 return ERROR_SHUTDOWN_IN_PROGRESS;
3015
3016 hSvc = ScmGetServiceFromHandle(hService);
3017 if (hSvc == NULL)
3018 {
3019 DPRINT1("Invalid service handle!\n");
3020 return ERROR_INVALID_HANDLE;
3021 }
3022
3023 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3024 SERVICE_START))
3025 {
3026 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3027 return ERROR_ACCESS_DENIED;
3028 }
3029
3030 lpService = hSvc->ServiceEntry;
3031 if (lpService == NULL)
3032 {
3033 DPRINT("lpService == NULL!\n");
3034 return ERROR_INVALID_HANDLE;
3035 }
3036
3037 if (lpService->dwStartType == SERVICE_DISABLED)
3038 return ERROR_SERVICE_DISABLED;
3039
3040 if (lpService->bDeleted)
3041 return ERROR_SERVICE_MARKED_FOR_DELETE;
3042
3043 /* Start the service */
3044 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3045
3046 return dwError;
3047 }
3048
3049
3050 /* Function 20 */
3051 DWORD RGetServiceDisplayNameW(
3052 SC_RPC_HANDLE hSCManager,
3053 LPCWSTR lpServiceName,
3054 LPWSTR lpDisplayName,
3055 DWORD *lpcchBuffer)
3056 {
3057 // PMANAGER_HANDLE hManager;
3058 PSERVICE lpService;
3059 DWORD dwLength;
3060 DWORD dwError;
3061
3062 DPRINT("RGetServiceDisplayNameW() called\n");
3063 DPRINT("hSCManager = %p\n", hSCManager);
3064 DPRINT("lpServiceName: %S\n", lpServiceName);
3065 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3066 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3067
3068 // hManager = (PMANAGER_HANDLE)hSCManager;
3069 // if (hManager->Handle.Tag != MANAGER_TAG)
3070 // {
3071 // DPRINT("Invalid manager handle!\n");
3072 // return ERROR_INVALID_HANDLE;
3073 // }
3074
3075 /* Get service database entry */
3076 lpService = ScmGetServiceEntryByName(lpServiceName);
3077 if (lpService == NULL)
3078 {
3079 DPRINT("Could not find a service!\n");
3080
3081 /* If the service could not be found and lpcchBuffer is less than 2, windows
3082 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3083 if (*lpcchBuffer < 2)
3084 {
3085 *lpcchBuffer = 2;
3086 if (lpDisplayName != NULL)
3087 {
3088 *lpDisplayName = '\0';
3089 }
3090 }
3091
3092 return ERROR_SERVICE_DOES_NOT_EXIST;
3093 }
3094
3095 if (!lpService->lpDisplayName)
3096 {
3097 dwLength = wcslen(lpService->lpServiceName);
3098
3099 if (lpDisplayName != NULL &&
3100 *lpcchBuffer > dwLength)
3101 {
3102 wcscpy(lpDisplayName, lpService->lpServiceName);
3103 }
3104 }
3105 else
3106 {
3107 dwLength = wcslen(lpService->lpDisplayName);
3108
3109 if (lpDisplayName != NULL &&
3110 *lpcchBuffer > dwLength)
3111 {
3112 wcscpy(lpDisplayName, lpService->lpDisplayName);
3113 }
3114 }
3115
3116 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3117
3118 *lpcchBuffer = dwLength;
3119
3120 return dwError;
3121 }
3122
3123
3124 /* Function 21 */
3125 DWORD RGetServiceKeyNameW(
3126 SC_RPC_HANDLE hSCManager,
3127 LPCWSTR lpDisplayName,
3128 LPWSTR lpServiceName,
3129 DWORD *lpcchBuffer)
3130 {
3131 // PMANAGER_HANDLE hManager;
3132 PSERVICE lpService;
3133 DWORD dwLength;
3134 DWORD dwError;
3135
3136 DPRINT("RGetServiceKeyNameW() called\n");
3137 DPRINT("hSCManager = %p\n", hSCManager);
3138 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3139 DPRINT("lpServiceName: %p\n", lpServiceName);
3140 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3141
3142 // hManager = (PMANAGER_HANDLE)hSCManager;
3143 // if (hManager->Handle.Tag != MANAGER_TAG)
3144 // {
3145 // DPRINT("Invalid manager handle!\n");
3146 // return ERROR_INVALID_HANDLE;
3147 // }
3148
3149 /* Get service database entry */
3150 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3151 if (lpService == NULL)
3152 {
3153 DPRINT("Could not find a service!\n");
3154
3155 /* If the service could not be found and lpcchBuffer is less than 2, windows
3156 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3157 if (*lpcchBuffer < 2)
3158 {
3159 *lpcchBuffer = 2;
3160 if (lpServiceName != NULL)
3161 {
3162 *lpServiceName = '\0';
3163 }
3164 }
3165
3166 return ERROR_SERVICE_DOES_NOT_EXIST;
3167 }
3168
3169 dwLength = wcslen(lpService->lpServiceName);
3170
3171 if (lpServiceName != NULL &&
3172 *lpcchBuffer > dwLength)
3173 {
3174 wcscpy(lpServiceName, lpService->lpServiceName);
3175 *lpcchBuffer = dwLength;
3176 return ERROR_SUCCESS;
3177 }
3178
3179 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3180
3181 *lpcchBuffer = dwLength;
3182
3183 return dwError;
3184 }
3185
3186
3187 /* Function 22 */
3188 DWORD RI_ScSetServiceBitsA(
3189 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3190 DWORD dwServiceBits,
3191 int bSetBitsOn,
3192 int bUpdateImmediately,
3193 char *lpString)
3194 {
3195 UNIMPLEMENTED;
3196 return ERROR_CALL_NOT_IMPLEMENTED;
3197 }
3198
3199
3200 /* Function 23 */
3201 DWORD RChangeServiceConfigA(
3202 SC_RPC_HANDLE hService,
3203 DWORD dwServiceType,
3204 DWORD dwStartType,
3205 DWORD dwErrorControl,
3206 LPSTR lpBinaryPathName,
3207 LPSTR lpLoadOrderGroup,
3208 LPDWORD lpdwTagId,
3209 LPSTR lpDependencies,
3210 DWORD dwDependSize,
3211 LPSTR lpServiceStartName,
3212 LPBYTE lpPassword,
3213 DWORD dwPwSize,
3214 LPSTR lpDisplayName)
3215 {
3216 DWORD dwError = ERROR_SUCCESS;
3217 PSERVICE_HANDLE hSvc;
3218 PSERVICE lpService = NULL;
3219 HKEY hServiceKey = NULL;
3220 LPWSTR lpDisplayNameW = NULL;
3221 // LPWSTR lpBinaryPathNameW = NULL;
3222 LPWSTR lpLoadOrderGroupW = NULL;
3223 LPWSTR lpDependenciesW = NULL;
3224 // LPWSTR lpPasswordW = NULL;
3225
3226 DPRINT("RChangeServiceConfigA() called\n");
3227 DPRINT("dwServiceType = %lu\n", dwServiceType);
3228 DPRINT("dwStartType = %lu\n", dwStartType);
3229 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3230 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3231 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3232 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3233
3234 if (ScmShutdown)
3235 return ERROR_SHUTDOWN_IN_PROGRESS;
3236
3237 hSvc = ScmGetServiceFromHandle(hService);
3238 if (hSvc == NULL)
3239 {
3240 DPRINT1("Invalid service handle!\n");
3241 return ERROR_INVALID_HANDLE;
3242 }
3243
3244 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3245 SERVICE_CHANGE_CONFIG))
3246 {
3247 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3248 return ERROR_ACCESS_DENIED;
3249 }
3250
3251 lpService = hSvc->ServiceEntry;
3252 if (lpService == NULL)
3253 {
3254 DPRINT("lpService == NULL!\n");
3255 return ERROR_INVALID_HANDLE;
3256 }
3257
3258 /* Lock the service database exclusively */
3259 ScmLockDatabaseExclusive();
3260
3261 if (lpService->bDeleted)
3262 {
3263 DPRINT("The service has already been marked for delete!\n");
3264 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3265 goto done;
3266 }
3267
3268 /* Open the service key */
3269 dwError = ScmOpenServiceKey(lpService->szServiceName,
3270 KEY_SET_VALUE,
3271 &hServiceKey);
3272 if (dwError != ERROR_SUCCESS)
3273 goto done;
3274
3275 /* Write service data to the registry */
3276
3277 if (lpDisplayName != NULL && *lpDisplayName != 0)
3278 {
3279 /* Set the display name */
3280 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3281 0,
3282 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3283 if (lpDisplayNameW == NULL)
3284 {
3285 dwError = ERROR_NOT_ENOUGH_MEMORY;
3286 goto done;
3287 }
3288
3289 MultiByteToWideChar(CP_ACP,
3290 0,
3291 lpDisplayName,
3292 -1,
3293 lpDisplayNameW,
3294 strlen(lpDisplayName) + 1);
3295
3296 RegSetValueExW(hServiceKey,
3297 L"DisplayName",
3298 0,
3299 REG_SZ,
3300 (LPBYTE)lpDisplayNameW,
3301 (wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR));
3302
3303 /* Update lpService->lpDisplayName */
3304 if (lpService->lpDisplayName)
3305 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3306
3307 lpService->lpDisplayName = lpDisplayNameW;
3308 }
3309
3310 if (dwServiceType != SERVICE_NO_CHANGE)
3311 {
3312 /* Set the service type */
3313 dwError = RegSetValueExW(hServiceKey,
3314 L"Type",
3315 0,
3316 REG_DWORD,
3317 (LPBYTE)&dwServiceType,
3318 sizeof(DWORD));
3319 if (dwError != ERROR_SUCCESS)
3320 goto done;
3321
3322 lpService->Status.dwServiceType = dwServiceType;
3323 }
3324
3325 if (dwStartType != SERVICE_NO_CHANGE)
3326 {
3327 /* Set the start value */
3328 dwError = RegSetValueExW(hServiceKey,
3329 L"Start",
3330 0,
3331 REG_DWORD,
3332 (LPBYTE)&dwStartType,
3333 sizeof(DWORD));
3334 if (dwError != ERROR_SUCCESS)
3335 goto done;
3336
3337 lpService->dwStartType = dwStartType;
3338 }
3339
3340 if (dwErrorControl != SERVICE_NO_CHANGE)
3341 {
3342 /* Set the error control value */
3343 dwError = RegSetValueExW(hServiceKey,
3344 L"ErrorControl",
3345 0,
3346 REG_DWORD,
3347 (LPBYTE)&dwErrorControl,
3348 sizeof(DWORD));
3349 if (dwError != ERROR_SUCCESS)
3350 goto done;
3351
3352 lpService->dwErrorControl = dwErrorControl;
3353 }
3354
3355 #if 0
3356 /* FIXME: set the new ImagePath value */
3357
3358 /* Set the image path */
3359 if (dwServiceType & SERVICE_WIN32)
3360 {
3361 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3362 {
3363 lpBinaryPathNameW=HeapAlloc(GetProcessHeap(),0, (strlen(lpBinaryPathName)+1) * sizeof(WCHAR));
3364 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, strlen(lpBinaryPathName)+1);
3365 dwError = RegSetValueExW(hServiceKey,
3366 L"ImagePath",
3367 0,
3368 REG_EXPAND_SZ,
3369 (LPBYTE)lpBinaryPathNameW,
3370 (wcslen(lpBinaryPathNameW) + 1) * sizeof(WCHAR));
3371 if (dwError != ERROR_SUCCESS)
3372 goto done;
3373 }
3374 }
3375 else if (dwServiceType & SERVICE_DRIVER)
3376 {
3377 if (lpImagePath != NULL && *lpImagePath != 0)
3378 {
3379 dwError = RegSetValueExW(hServiceKey,
3380 L"ImagePath",
3381 0,
3382 REG_EXPAND_SZ,
3383 (LPBYTE)lpImagePath,
3384 (wcslen(lpImagePath) + 1) *sizeof(WCHAR));
3385 if (dwError != ERROR_SUCCESS)
3386 goto done;
3387 }
3388 }
3389 #endif
3390
3391 /* Set the group name */
3392 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
3393 {
3394 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(),
3395 0,
3396 (strlen(lpLoadOrderGroup) + 1) * sizeof(WCHAR));
3397 if (lpLoadOrderGroupW == NULL)
3398 {
3399 dwError = ERROR_NOT_ENOUGH_MEMORY;
3400 goto done;
3401 }
3402
3403 MultiByteToWideChar(CP_ACP,
3404 0,
3405 lpLoadOrderGroup,
3406 -1,
3407 lpLoadOrderGroupW,
3408 strlen(lpLoadOrderGroup) + 1);
3409
3410 dwError = RegSetValueExW(hServiceKey,
3411 L"Group",
3412 0,
3413 REG_SZ,
3414 (LPBYTE)lpLoadOrderGroupW,
3415 (wcslen(lpLoadOrderGroupW) + 1) * sizeof(WCHAR));
3416 if (dwError != ERROR_SUCCESS)
3417 {
3418 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3419 goto done;
3420 }
3421
3422 dwError = ScmSetServiceGroup(lpService,
3423 lpLoadOrderGroupW);
3424
3425 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3426
3427 if (dwError != ERROR_SUCCESS)
3428 goto done;
3429 }
3430
3431 if (lpdwTagId != NULL)
3432 {
3433 dwError = ScmAssignNewTag(lpService);
3434 if (dwError != ERROR_SUCCESS)
3435 goto done;
3436
3437 dwError = RegSetValueExW(hServiceKey,
3438 L"Tag",
3439 0,
3440 REG_DWORD,
3441 (LPBYTE)&lpService->dwTag,
3442 sizeof(DWORD));
3443 if (dwError != ERROR_SUCCESS)
3444 goto done;
3445
3446 *lpdwTagId = lpService->dwTag;
3447 }
3448
3449 /* Write dependencies */
3450 if (lpDependencies != NULL && *lpDependencies != 0)
3451 {
3452 lpDependenciesW = HeapAlloc(GetProcessHeap(),
3453 0,
3454 (strlen(lpDependencies) + 1) * sizeof(WCHAR));
3455 if (lpDependenciesW == NULL)
3456 {
3457 dwError = ERROR_NOT_ENOUGH_MEMORY;
3458 goto done;
3459 }
3460
3461 MultiByteToWideChar(CP_ACP,
3462 0,
3463 lpDependencies,
3464 dwDependSize,
3465 lpDependenciesW,
3466 strlen(lpDependencies) + 1);
3467
3468 dwError = ScmWriteDependencies(hServiceKey,
3469 (LPWSTR)lpDependenciesW,
3470 dwDependSize);
3471
3472 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3473 }
3474
3475 if (lpPassword != NULL)
3476 {
3477 /* FIXME: Write password */
3478 }
3479
3480 done:
3481 /* Unlock the service database */
3482 ScmUnlockDatabase();
3483
3484 if (hServiceKey != NULL)
3485 RegCloseKey(hServiceKey);
3486
3487 DPRINT("RChangeServiceConfigA() done (Error %lu)\n", dwError);
3488
3489 return dwError;
3490 }
3491
3492
3493 /* Function 24 */
3494 DWORD RCreateServiceA(
3495 SC_RPC_HANDLE hSCManager,
3496 LPSTR lpServiceName,
3497 LPSTR lpDisplayName,
3498 DWORD dwDesiredAccess,
3499 DWORD dwServiceType,
3500 DWORD dwStartType,
3501 DWORD dwErrorControl,
3502 LPSTR lpBinaryPathName,
3503 LPSTR lpLoadOrderGroup,
3504 LPDWORD lpdwTagId,
3505 LPBYTE lpDependencies,
3506 DWORD dwDependSize,
3507 LPSTR lpServiceStartName,
3508 LPBYTE lpPassword,
3509 DWORD dwPwSize,
3510 LPSC_RPC_HANDLE lpServiceHandle)
3511 {
3512 DWORD dwError = ERROR_SUCCESS;
3513 LPWSTR lpServiceNameW = NULL;
3514 LPWSTR lpDisplayNameW = NULL;
3515 LPWSTR lpBinaryPathNameW = NULL;
3516 LPWSTR lpLoadOrderGroupW = NULL;
3517 LPWSTR lpDependenciesW = NULL;
3518 LPWSTR lpServiceStartNameW = NULL;
3519 DWORD dwDependenciesLength = 0;
3520 DWORD dwLength;
3521 int len;
3522 LPSTR lpStr;
3523
3524 if (lpServiceName)
3525 {
3526 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3527 lpServiceNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3528 if (!lpServiceNameW)
3529 {
3530 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3531 goto cleanup;
3532 }
3533 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3534 }
3535
3536 if (lpDisplayName)
3537 {
3538 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3539 lpDisplayNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3540 if (!lpDisplayNameW)
3541 {
3542 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3543 goto cleanup;
3544 }
3545 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3546 }
3547
3548 if (lpBinaryPathName)
3549 {
3550 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3551 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3552 if (!lpBinaryPathNameW)
3553 {
3554 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3555 goto cleanup;
3556 }
3557 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3558 }
3559
3560 if (lpLoadOrderGroup)
3561 {
3562 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3563 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3564 if (!lpLoadOrderGroupW)
3565 {
3566 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3567 goto cleanup;
3568 }
3569 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3570 }
3571
3572 if (lpDependencies)
3573 {
3574 lpStr = (LPSTR)lpDependencies;
3575 while (*lpStr)
3576 {
3577 dwLength = strlen(lpStr) + 1;
3578 dwDependenciesLength += dwLength;
3579 lpStr = lpStr + dwLength;
3580 }
3581 dwDependenciesLength++;
3582
3583 lpDependenciesW = HeapAlloc(GetProcessHeap(), 0, dwDependenciesLength * sizeof(WCHAR));
3584 if (!lpDependenciesW)
3585 {
3586 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3587 goto cleanup;
3588 }
3589 MultiByteToWideChar(CP_ACP, 0, (LPSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3590 }
3591
3592 if (lpServiceStartName)
3593 {
3594 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3595 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR));
3596 if (!lpServiceStartNameW)
3597 {
3598 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3599 goto cleanup;
3600 }
3601 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3602 }
3603
3604 dwError = RCreateServiceW(hSCManager,
3605 lpServiceNameW,
3606 lpDisplayNameW,
3607 dwDesiredAccess,
3608 dwServiceType,
3609 dwStartType,
3610 dwErrorControl,
3611 lpBinaryPathNameW,
3612 lpLoadOrderGroupW,
3613 lpdwTagId,
3614 (LPBYTE)lpDependenciesW,
3615 dwDependenciesLength,
3616 lpServiceStartNameW,
3617 lpPassword,
3618 dwPwSize,
3619 lpServiceHandle);
3620
3621 cleanup:
3622 if (lpServiceNameW !=NULL)
3623 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3624
3625 if (lpDisplayNameW != NULL)
3626 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3627
3628 if (lpBinaryPathNameW != NULL)
3629 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3630
3631 if (lpLoadOrderGroupW != NULL)
3632 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3633
3634 if (lpDependenciesW != NULL)
3635 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3636
3637 if (lpServiceStartNameW != NULL)
3638 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3639
3640 return dwError;
3641 }
3642
3643
3644 /* Function 25 */
3645 DWORD REnumDependentServicesA(
3646 SC_RPC_HANDLE hService,
3647 DWORD dwServiceState,
3648 LPBYTE lpServices,
3649 DWORD cbBufSize,
3650 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3651 LPBOUNDED_DWORD_256K lpServicesReturned)
3652 {
3653 DWORD dwError = ERROR_SUCCESS;
3654 DWORD dwServicesReturned = 0;
3655 DWORD dwServiceCount;
3656 HKEY hServicesKey = NULL;
3657 PSERVICE_HANDLE hSvc;
3658 PSERVICE lpService = NULL;
3659 PSERVICE *lpServicesArray = NULL;
3660 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3661 LPSTR lpStr;
3662
3663 *pcbBytesNeeded = 0;
3664 *lpServicesReturned = 0;
3665
3666 DPRINT("REnumDependentServicesA() called\n");
3667
3668 hSvc = ScmGetServiceFromHandle(hService);
3669 if (hSvc == NULL)
3670 {
3671 DPRINT1("Invalid service handle!\n");
3672 return ERROR_INVALID_HANDLE;
3673 }
3674
3675 lpService = hSvc->ServiceEntry;
3676
3677 /* Check access rights */
3678 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3679 SC_MANAGER_ENUMERATE_SERVICE))
3680 {
3681 DPRINT("Insufficient access rights! 0x%lx\n",
3682 hSvc->Handle.DesiredAccess);
3683 return ERROR_ACCESS_DENIED;
3684 }
3685
3686 /* Open the Services Reg key */
3687 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3688 L"System\\CurrentControlSet\\Services",
3689 0,
3690 KEY_READ,
3691 &hServicesKey);
3692
3693 if (dwError != ERROR_SUCCESS)
3694 return dwError;
3695
3696 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3697 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3698 are the same for both. Verified in WINXP. */
3699
3700 /* First determine the bytes needed and get the number of dependent services*/
3701 dwError = Int_EnumDependentServicesW(hServicesKey,
3702 lpService,
3703 dwServiceState,
3704 NULL,
3705 pcbBytesNeeded,
3706 &dwServicesReturned);
3707 if (dwError != ERROR_SUCCESS)
3708 goto Done;
3709
3710 /* If buffer size is less than the bytes needed or pointer is null*/
3711 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3712 {
3713 dwError = ERROR_MORE_DATA;
3714 goto Done;
3715 }
3716
3717 /* Allocate memory for array of service pointers */
3718 lpServicesArray = HeapAlloc(GetProcessHeap(),
3719 0,
3720 (dwServicesReturned + 1) * sizeof(PSERVICE));
3721 if (!lpServicesArray)
3722 {
3723 DPRINT("Could not allocate a buffer!!\n");
3724 dwError = ERROR_NOT_ENOUGH_MEMORY;
3725 goto Done;
3726 }
3727
3728 dwServicesReturned = 0;
3729 *pcbBytesNeeded = 0;
3730
3731 dwError = Int_EnumDependentServicesW(hServicesKey,
3732 lpService,
3733 dwServiceState,
3734 lpServicesArray,
3735 pcbBytesNeeded,
3736 &dwServicesReturned);
3737 if (dwError != ERROR_SUCCESS)
3738 {
3739 goto Done;
3740 }
3741
3742 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3743 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3744
3745 /* Copy EnumDepenedentService to Buffer */
3746 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3747 {
3748 lpService = lpServicesArray[dwServiceCount];
3749
3750 /* Copy the status info */
3751 memcpy(&lpServicesPtr->ServiceStatus,
3752 &lpService->Status,
3753 sizeof(SERVICE_STATUS));
3754
3755 /* Copy display name */
3756 WideCharToMultiByte(CP_ACP,
3757 0,
3758 lpService->lpDisplayName,
3759 -1,
3760 lpStr,
3761 wcslen(lpService->lpDisplayName),
3762 0,
3763 0);
3764 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3765 lpStr += strlen(lpStr) + 1;
3766
3767 /* Copy service name */
3768 WideCharToMultiByte(CP_ACP,
3769 0,
3770 lpService->lpServiceName,
3771 -1,
3772 lpStr,
3773 wcslen(lpService->lpServiceName),
3774 0,
3775 0);
3776 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3777 lpStr += strlen(lpStr) + 1;
3778
3779 lpServicesPtr ++;
3780 }
3781
3782 *lpServicesReturned = dwServicesReturned;
3783
3784 Done:
3785 if (lpServicesArray)
3786 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3787
3788 RegCloseKey(hServicesKey);
3789
3790 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3791
3792 return dwError;
3793 }
3794
3795
3796 /* Function 26 */
3797 DWORD REnumServicesStatusA(
3798 SC_RPC_HANDLE hSCManager,
3799 DWORD dwServiceType,
3800 DWORD dwServiceState,
3801 LPBYTE lpBuffer,
3802 DWORD dwBufSize,
3803 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3804 LPBOUNDED_DWORD_256K lpServicesReturned,
3805 LPBOUNDED_DWORD_256K lpResumeHandle)
3806 {
3807 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3808 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3809 LPWSTR lpStringPtrW;
3810 LPSTR lpStringPtrA;
3811 DWORD dwError;
3812 DWORD dwServiceCount;
3813
3814 DPRINT("REnumServicesStatusA() called\n");
3815
3816 if ((dwBufSize > 0) && (lpBuffer))
3817 {
3818 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3819 if (!lpStatusPtrW)
3820 {
3821 DPRINT("Failed to allocate buffer!\n");
3822 return ERROR_NOT_ENOUGH_MEMORY;
3823 }
3824 }
3825
3826 dwError = REnumServicesStatusW(hSCManager,
3827 dwServiceType,
3828 dwServiceState,
3829 (LPBYTE)lpStatusPtrW,
3830 dwBufSize,
3831 pcbBytesNeeded,
3832 lpServicesReturned,
3833 lpResumeHandle);
3834
3835 /* if no services were returned then we are Done */
3836 if (*lpServicesReturned == 0)
3837 goto Done;
3838
3839 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3840 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3841 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3842 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3843 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3844
3845 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3846 {
3847 /* Copy the service name */
3848 WideCharToMultiByte(CP_ACP,
3849 0,
3850 lpStringPtrW,
3851 -1,
3852 lpStringPtrA,
3853 wcslen(lpStringPtrW),
3854 0,
3855 0);
3856
3857 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3858 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3859 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3860
3861 /* Copy the display name */
3862 WideCharToMultiByte(CP_ACP,
3863 0,
3864 lpStringPtrW,
3865 -1,
3866 lpStringPtrA,
3867 wcslen(lpStringPtrW),
3868 0,
3869 0);
3870
3871 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
3872 lpStringPtrA += wcslen(lpStringPtrW) + 1;
3873 lpStringPtrW += wcslen(lpStringPtrW) + 1;
3874
3875 /* Copy the status information */
3876 memcpy(&lpStatusPtrA->ServiceStatus,
3877 &lpStatusPtrW->ServiceStatus,
3878 sizeof(SERVICE_STATUS));
3879
3880 lpStatusPtrA++;
3881 }
3882
3883 Done:;
3884 if (lpStatusPtrW)
3885 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
3886
3887 DPRINT("REnumServicesStatusA() done (Error %lu)\n", dwError);
3888
3889 return dwError;
3890 }
3891
3892
3893 /* Function 27 */
3894 DWORD ROpenSCManagerA(
3895 LPSTR lpMachineName,
3896 LPSTR lpDatabaseName,
3897 DWORD dwDesiredAccess,
3898 LPSC_RPC_HANDLE lpScHandle)
3899 {
3900 UNICODE_STRING MachineName;
3901 UNICODE_STRING DatabaseName;
3902 DWORD dwError;
3903
3904 DPRINT("ROpenSCManagerA() called\n");
3905
3906 if (lpMachineName)
3907 RtlCreateUnicodeStringFromAsciiz(&MachineName,
3908 lpMachineName);
3909
3910 if (lpDatabaseName)
3911 RtlCreateUnicodeStringFromAsciiz(&DatabaseName,
3912 lpDatabaseName);
3913
3914 dwError = ROpenSCManagerW(lpMachineName ? MachineName.Buffer : NULL,
3915 lpDatabaseName ? DatabaseName.Buffer : NULL,
3916 dwDesiredAccess,
3917 lpScHandle);
3918
3919 if (lpMachineName)
3920 RtlFreeUnicodeString(&MachineName);
3921
3922 if (lpDatabaseName)
3923 RtlFreeUnicodeString(&DatabaseName);
3924
3925 return dwError;
3926 }
3927
3928
3929 /* Function 28 */
3930 DWORD ROpenServiceA(
3931 SC_RPC_HANDLE hSCManager,
3932 LPSTR lpServiceName,
3933 DWORD dwDesiredAccess,
3934 LPSC_RPC_HANDLE lpServiceHandle)
3935 {
3936 UNICODE_STRING ServiceName;
3937 DWORD dwError;
3938
3939 DPRINT("ROpenServiceA() called\n");
3940
3941 if (lpServiceName)
3942 RtlCreateUnicodeStringFromAsciiz(&ServiceName,
3943 lpServiceName);
3944
3945 dwError = ROpenServiceW(hSCManager,
3946 lpServiceName ? ServiceName.Buffer : NULL,
3947 dwDesiredAccess,
3948 lpServiceHandle);
3949
3950 if (lpServiceName)
3951 RtlFreeUnicodeString(&ServiceName);
3952
3953 return dwError;
3954 }
3955
3956
3957 /* Function 29 */
3958 DWORD RQueryServiceConfigA(
3959 SC_RPC_HANDLE hService,
3960 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGA lpServiceConfig,
3961 DWORD cbBufSize,
3962 LPBOUNDED_DWORD_8K pcbBytesNeeded)
3963 {
3964 LPQUERY_SERVICE_CONFIGA lpServiceConfig = (LPQUERY_SERVICE_CONFIGA)lpBuf;
3965 DWORD dwError = ERROR_SUCCESS;
3966 PSERVICE_HANDLE hSvc;
3967 PSERVICE lpService = NULL;
3968 HKEY hServiceKey = NULL;
3969 LPWSTR lpImagePath = NULL;
3970 LPWSTR lpServiceStartName = NULL;
3971 LPWSTR lpDependencies = NULL;
3972 DWORD dwDependenciesLength = 0;
3973 DWORD dwRequiredSize;
3974 LPQUERY_SERVICE_CONFIGA lpConfig = NULL;
3975 CHAR lpEmptyString[]={0,0};
3976 LPSTR lpStr;
3977
3978 DPRINT("RQueryServiceConfigA() called\n");
3979
3980 if (ScmShutdown)
3981 return ERROR_SHUTDOWN_IN_PROGRESS;
3982
3983 hSvc = ScmGetServiceFromHandle(hService);
3984 if (hSvc == NULL)
3985 {
3986 DPRINT1("Invalid service handle!\n");
3987 return ERROR_INVALID_HANDLE;
3988 }
3989
3990 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3991 SERVICE_QUERY_CONFIG))
3992 {
3993 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3994 return ERROR_ACCESS_DENIED;
3995 }
3996
3997 lpService = hSvc->ServiceEntry;
3998 if (lpService == NULL)
3999 {
4000 DPRINT("lpService == NULL!\n");
4001 return ERROR_INVALID_HANDLE;
4002 }
4003
4004 /* Lock the service database shared */
4005 ScmLockDatabaseShared();
4006
4007 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4008 KEY_READ,
4009 &hServiceKey);
4010 if (dwError != ERROR_SUCCESS)
4011 goto Done;
4012
4013 /* Read the image path */
4014 dwError = ScmReadString(hServiceKey,
4015 L"ImagePath",
4016 &lpImagePath);
4017 if (dwError != ERROR_SUCCESS)
4018 goto Done;
4019
4020 /* Read the service start name */
4021 ScmReadString(hServiceKey,
4022 L"ObjectName",
4023 &lpServiceStartName);
4024
4025 /* Read the dependencies */
4026 ScmReadDependencies(hServiceKey,
4027 &lpDependencies,
4028 &dwDependenciesLength);
4029
4030 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
4031
4032 if (lpImagePath != NULL)
4033 dwRequiredSize += wcslen(lpImagePath) + 1;
4034 else
4035 dwRequiredSize += 2;
4036
4037 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
4038 dwRequiredSize += wcslen(lpService->lpGroup->lpGroupName) + 1;
4039 else
4040 dwRequiredSize += 2;
4041
4042 /* Add Dependencies length */
4043 if (lpDependencies != NULL)
4044 dwRequiredSize += dwDependenciesLength;
4045 else
4046 dwRequiredSize += 2;
4047
4048 if (lpServiceStartName != NULL)
4049 dwRequiredSize += wcslen(lpServiceStartName) + 1;
4050 else
4051 dwRequiredSize += 2;
4052
4053 if (lpService->lpDisplayName != NULL)
4054 dwRequiredSize += wcslen(lpService->lpDisplayName) + 1;
4055 else
4056 dwRequiredSize += 2;
4057
4058 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
4059 {
4060 dwError = ERROR_INSUFFICIENT_BUFFER;
4061 }
4062 else
4063 {
4064 lpConfig = (LPQUERY_SERVICE_CONFIGA)lpServiceConfig;
4065 lpConfig->dwServiceType = lpService->Status.dwServiceType;
4066 lpConfig->dwStartType = lpService->dwStartType;
4067 lpConfig->dwErrorControl = lpService->dwErrorControl;
4068 lpConfig->dwTagId = lpService->dwTag;
4069
4070 lpStr = (LPSTR)(lpServiceConfig + 1);
4071
4072 /* NOTE: Strings that are NULL for QUERY_SERVICE_CONFIG are pointers to empty strings.
4073 Verified in WINXP*/
4074
4075 if (lpImagePath)
4076 {
4077 WideCharToMultiByte(CP_ACP,
4078 0,
4079 lpImagePath,
4080 -1,
4081 lpStr,
4082 wcslen(lpImagePath) + 1,
4083 0,
4084 0);
4085 }
4086 else
4087 {
4088 strcpy(lpStr, lpEmptyString);
4089 }
4090
4091 lpConfig->lpBinaryPathName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4092 lpStr += (strlen((LPSTR)lpStr) + 1);
4093
4094 if (lpService->lpGroup && lpService->lpGroup->lpGroupName)
4095 {
4096 WideCharToMultiByte(CP_ACP,
4097 0,
4098 lpService->lpGroup->lpGroupName,
4099 -1,
4100 lpStr,
4101 wcslen(lpService->lpGroup->lpGroupName) + 1,
4102 0,
4103 0);
4104 }
4105 else
4106 {
4107 strcpy(lpStr, lpEmptyString);
4108 }
4109
4110 lpConfig->lpLoadOrderGroup = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4111 lpStr += (strlen(lpStr) + 1);
4112
4113 /* Append Dependencies */
4114 if (lpDependencies)
4115 {
4116 WideCharToMultiByte(CP_ACP,
4117 0,
4118 lpDependencies,
4119 dwDependenciesLength,
4120 lpStr,
4121 dwDependenciesLength,
4122 0,
4123 0);
4124 }
4125 else
4126 {
4127 strcpy(lpStr, lpEmptyString);
4128 }
4129
4130 lpConfig->lpDependencies = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4131 if (lpDependencies)
4132 lpStr += dwDependenciesLength;
4133 else
4134 lpStr += (strlen(lpStr) + 1);
4135
4136 if (lpServiceStartName)
4137 {
4138 WideCharToMultiByte(CP_ACP,
4139 0,
4140 lpServiceStartName,
4141 -1,
4142 lpStr,
4143 wcslen(lpServiceStartName) + 1,
4144 0,
4145 0);
4146 }
4147 else
4148 {
4149 strcpy(lpStr, lpEmptyString);
4150 }
4151
4152 lpConfig->lpServiceStartName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4153 lpStr += (strlen(lpStr) + 1);
4154
4155 if (lpService->lpDisplayName)
4156 {
4157 WideCharToMultiByte(CP_ACP,
4158 0,
4159 lpService->lpDisplayName,
4160 -1,
4161 lpStr,
4162 wcslen(lpService->lpDisplayName) + 1,
4163 0,
4164 0);
4165 }
4166 else
4167 {
4168 strcpy(lpStr, lpEmptyString);
4169 }
4170
4171 lpConfig->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpConfig);
4172 }
4173
4174 if (pcbBytesNeeded != NULL)
4175 *pcbBytesNeeded = dwRequiredSize;
4176
4177 Done:;
4178 /* Unlock the service database */
4179 ScmUnlockDatabase();
4180
4181 if (lpImagePath != NULL)
4182 HeapFree(GetProcessHeap(), 0, lpImagePath);
4183
4184 if (lpServiceStartName != NULL)
4185 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
4186
4187 if (lpDependencies != NULL)
4188 HeapFree(GetProcessHeap(), 0, lpDependencies);
4189
4190 if (hServiceKey != NULL)
4191 RegCloseKey(hServiceKey);
4192
4193 DPRINT("RQueryServiceConfigA() done\n");
4194
4195 return dwError;
4196 }
4197
4198
4199 /* Function 30 */
4200 DWORD RQueryServiceLockStatusA(
4201 SC_RPC_HANDLE hSCManager,
4202 LPQUERY_SERVICE_LOCK_STATUSA lpLockStatus,
4203 DWORD cbBufSize,
4204 LPBOUNDED_DWORD_4K pcbBytesNeeded)
4205 {
4206 UNIMPLEMENTED;
4207 return ERROR_CALL_NOT_IMPLEMENTED;
4208 }
4209
4210
4211 /* Function 31 */
4212 DWORD RStartServiceA(
4213 SC_RPC_HANDLE hService,
4214 DWORD argc,
4215 LPSTRING_PTRSA argv)
4216 {
4217 DWORD dwError = ERROR_SUCCESS;
4218 PSERVICE_HANDLE hSvc;
4219 PSERVICE lpService = NULL;
4220 LPWSTR *lpVector = NULL;
4221 DWORD i;
4222 DWORD dwLength;
4223
4224 DPRINT("RStartServiceA() called\n");
4225
4226 if (ScmShutdown)
4227 return ERROR_SHUTDOWN_IN_PROGRESS;
4228
4229 hSvc = ScmGetServiceFromHandle(hService);
4230 if (hSvc == NULL)
4231 {
4232 DPRINT1("Invalid service handle!\n");
4233 return ERROR_INVALID_HANDLE;
4234 }
4235
4236 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4237 SERVICE_START))
4238 {
4239 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4240 return ERROR_ACCESS_DENIED;
4241 }
4242
4243 lpService = hSvc->ServiceEntry;
4244 if (lpService == NULL)
4245 {
4246 DPRINT("lpService == NULL!\n");
4247 return ERROR_INVALID_HANDLE;
4248 }
4249
4250 if (lpService->dwStartType == SERVICE_DISABLED)
4251 return ERROR_SERVICE_DISABLED;
4252
4253 if (lpService->bDeleted)
4254 return ERROR_SERVICE_MARKED_FOR_DELETE;
4255
4256 /* Build a Unicode argument vector */
4257 if (argc > 0)
4258 {
4259 lpVector = HeapAlloc(GetProcessHeap(),
4260 HEAP_ZERO_MEMORY,
4261 argc * sizeof(LPWSTR));
4262 if (lpVector == NULL)
4263 return ERROR_NOT_ENOUGH_MEMORY;
4264
4265 for (i = 0; i < argc; i++)
4266 {
4267 dwLength = MultiByteToWideChar(CP_ACP,
4268 0,
4269 ((LPSTR*)argv)[i],
4270 -1,
4271 NULL,
4272 0);
4273
4274 lpVector[i] = HeapAlloc(GetProcessHeap(),
4275 HEAP_ZERO_MEMORY,
4276 dwLength * sizeof(WCHAR));
4277 if (lpVector[i] == NULL)
4278 {
4279 dwError = ERROR_NOT_ENOUGH_MEMORY;
4280 goto done;
4281 }
4282
4283 MultiByteToWideChar(CP_ACP,
4284 0,
4285 ((LPSTR*)argv)[i],
4286 -1,
4287 lpVector[i],
4288 dwLength);
4289 }
4290 }
4291
4292 /* Start the service */
4293 dwError = ScmStartService(lpService, argc, lpVector);
4294
4295 done:
4296 /* Free the Unicode argument vector */
4297 if (lpVector != NULL)
4298 {
4299 for (i = 0; i < argc; i++)
4300 {
4301 if (lpVector[i] != NULL)
4302 HeapFree(GetProcessHeap(), 0, lpVector[i]);
4303 }
4304 HeapFree(GetProcessHeap(), 0, lpVector);
4305 }
4306
4307 return dwError;
4308 }
4309
4310
4311 /* Function 32 */
4312 DWORD RGetServiceDisplayNameA(
4313 SC_RPC_HANDLE hSCManager,
4314 LPCSTR lpServiceName,
4315 LPSTR lpDisplayName,
4316 LPBOUNDED_DWORD_4K lpcchBuffer)
4317 {
4318 // PMANAGER_HANDLE hManager;
4319 PSERVICE lpService = NULL;
4320 DWORD dwLength;
4321 DWORD dwError;
4322 LPWSTR lpServiceNameW;
4323
4324 DPRINT("RGetServiceDisplayNameA() called\n");
4325 DPRINT("hSCManager = %p\n", hSCManager);
4326 DPRINT("lpServiceName: %s\n", lpServiceName);
4327 DPRINT("lpDisplayName: %p\n", lpDisplayName);
4328 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4329
4330 // hManager = (PMANAGER_HANDLE)hSCManager;
4331 // if (hManager->Handle.Tag != MANAGER_TAG)
4332 // {
4333 // DPRINT("Invalid manager handle!\n");
4334 // return ERROR_INVALID_HANDLE;
4335 // }
4336
4337 if (lpServiceName != NULL)
4338 {
4339 dwLength = strlen(lpServiceName) + 1;
4340 lpServiceNameW = HeapAlloc(GetProcessHeap(),
4341 HEAP_ZERO_MEMORY,
4342 dwLength * sizeof(WCHAR));
4343 if (!lpServiceNameW)
4344 return ERROR_NOT_ENOUGH_MEMORY;
4345
4346 MultiByteToWideChar(CP_ACP,
4347 0,
4348 lpServiceName,
4349 -1,
4350 lpServiceNameW,
4351 dwLength);
4352
4353 lpService = ScmGetServiceEntryByName(lpServiceNameW);
4354
4355 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
4356 }
4357
4358 if (lpService == NULL)
4359 {
4360 DPRINT("Could not find a service!\n");
4361
4362 /* If the service could not be found and lpcchBuffer is 0, windows
4363 puts null in lpDisplayName and puts 1 in lpcchBuffer */
4364 if (*lpcchBuffer == 0)
4365 {
4366 *lpcchBuffer = 1;
4367 if (lpDisplayName != NULL)
4368 {
4369 *lpDisplayName = '\0';
4370 }
4371 }
4372 return ERROR_SERVICE_DOES_NOT_EXIST;
4373 }
4374
4375 if (!lpService->lpDisplayName)
4376 {
4377 dwLength = wcslen(lpService->lpServiceName);
4378 if (lpDisplayName != NULL &&
4379 *lpcchBuffer > dwLength)
4380 {
4381 WideCharToMultiByte(CP_ACP,
4382 0,
4383 lpService->lpServiceName,
4384 wcslen(lpService->lpServiceName),
4385 lpDisplayName,
4386 dwLength + 1,
4387 NULL,
4388 NULL);
4389 return ERROR_SUCCESS;
4390 }
4391 }
4392 else
4393 {
4394 dwLength = wcslen(lpService->lpDisplayName);
4395 if (lpDisplayName != NULL &&
4396 *lpcchBuffer > dwLength)
4397 {
4398 WideCharToMultiByte(CP_ACP,
4399 0,
4400 lpService->lpDisplayName,
4401 wcslen(lpService->lpDisplayName),
4402 lpDisplayName,
4403 dwLength + 1,
4404 NULL,
4405 NULL);
4406 return ERROR_SUCCESS;
4407 }
4408 }
4409
4410 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4411
4412 *lpcchBuffer = dwLength * 2;
4413
4414 return dwError;
4415 }
4416
4417
4418 /* Function 33 */
4419 DWORD RGetServiceKeyNameA(
4420 SC_RPC_HANDLE hSCManager,
4421 LPCSTR lpDisplayName,
4422 LPSTR lpServiceName,
4423 LPBOUNDED_DWORD_4K lpcchBuffer)
4424 {
4425 PSERVICE lpService;
4426 DWORD dwLength;
4427 DWORD dwError;
4428 LPWSTR lpDisplayNameW;
4429
4430 DPRINT("RGetServiceKeyNameA() called\n");
4431 DPRINT("hSCManager = %p\n", hSCManager);
4432 DPRINT("lpDisplayName: %s\n", lpDisplayName);
4433 DPRINT("lpServiceName: %p\n", lpServiceName);
4434 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
4435
4436 dwLength = strlen(lpDisplayName) + 1;
4437 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
4438 HEAP_ZERO_MEMORY,
4439 dwLength * sizeof(WCHAR));
4440 if (!lpDisplayNameW)
4441 return ERROR_NOT_ENOUGH_MEMORY;
4442
4443 MultiByteToWideChar(CP_ACP,
4444 0,
4445 lpDisplayName,
4446 -1,
4447 lpDisplayNameW,
4448 dwLength);
4449
4450 lpService = ScmGetServiceEntryByDisplayName(lpDisplayNameW);
4451
4452 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
4453
4454 if (lpService == NULL)
4455 {
4456 DPRINT("Could not find the service!\n");
4457
4458 /* If the service could not be found and lpcchBuffer is 0,
4459 put null in lpDisplayName and puts 1 in lpcchBuffer, verified WINXP. */
4460 if (*lpcchBuffer == 0)
4461 {
4462 *lpcchBuffer = 1;
4463 if (lpServiceName != NULL)
4464 {
4465 *lpServiceName = '\0';
4466 }
4467 }
4468
4469 return ERROR_SERVICE_DOES_NOT_EXIST;
4470 }
4471
4472 dwLength = wcslen(lpService->lpServiceName);
4473 if (lpServiceName != NULL &&
4474 *lpcchBuffer > dwLength)
4475 {
4476 WideCharToMultiByte(CP_ACP,
4477 0,
4478 lpService->lpServiceName,
4479 wcslen(lpService->lpServiceName),
4480 lpServiceName,
4481 dwLength + 1,
4482 NULL,
4483 NULL);
4484 return ERROR_SUCCESS;
4485 }
4486
4487 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
4488
4489 *lpcchBuffer = dwLength * 2;
4490
4491 return dwError;
4492 }
4493
4494
4495 /* Function 34 */
4496 DWORD RI_ScGetCurrentGroupStateW(
4497 SC_RPC_HANDLE hSCManager,
4498 LPWSTR lpLoadOrderGroup,
4499 LPDWORD lpState)
4500 {
4501 UNIMPLEMENTED;
4502 return ERROR_CALL_NOT_IMPLEMENTED;
4503 }
4504
4505
4506 /* Function 35 */
4507 DWORD REnumServiceGroupW(
4508 SC_RPC_HANDLE hSCManager,
4509 DWORD dwServiceType,
4510 DWORD dwServiceState,
4511 LPBYTE lpBuffer,
4512 DWORD cbBufSize,
4513 LPBOUNDED_DWORD_256K pcbBytesNeeded,
4514 LPBOUNDED_DWORD_256K lpServicesReturned,
4515 LPBOUNDED_DWORD_256K lpResumeIndex,
4516 LPCWSTR pszGroupName)
4517 {
4518 UNIMPLEMENTED;
4519 return ERROR_CALL_NOT_IMPLEMENTED;
4520 }
4521
4522
4523 //
4524 // WARNING: This function is untested
4525 //
4526 /* Function 36 */
4527 DWORD RChangeServiceConfig2A(
4528 SC_RPC_HANDLE hService,
4529 SC_RPC_CONFIG_INFOA Info)
4530 {
4531 SC_RPC_CONFIG_INFOW InfoW;
4532 DWORD dwRet, dwLength;
4533 PVOID ptr = NULL;
4534
4535 DPRINT("RChangeServiceConfig2A() called\n");
4536 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4537
4538 InfoW.dwInfoLevel = Info.dwInfoLevel;
4539
4540 if (InfoW.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4541 {
4542 LPSERVICE_DESCRIPTIONW lpServiceDescriptonW;
4543 //LPSERVICE_DESCRIPTIONA lpServiceDescriptonA;
4544
4545 //lpServiceDescriptonA = Info.psd;
4546
4547 ///if (lpServiceDescriptonA &&
4548 ///lpServiceDescriptonA->lpDescription)
4549 ///{
4550 dwLength = (strlen(Info.lpDescription) + 1) * sizeof(WCHAR);
4551
4552 lpServiceDescriptonW = HeapAlloc(GetProcessHeap(),
4553 0,
4554 dwLength + sizeof(SERVICE_DESCRIPTIONW));
4555 if (!lpServiceDescriptonW)
4556 {
4557 return ERROR_NOT_ENOUGH_MEMORY;
4558 }
4559
4560 lpServiceDescriptonW->lpDescription = (LPWSTR)(lpServiceDescriptonW + 1);
4561
4562 MultiByteToWideChar(CP_ACP,
4563 0,
4564 Info.lpDescription,
4565 -1,
4566 lpServiceDescriptonW->lpDescription,
4567 dwLength);
4568
4569 ptr = lpServiceDescriptonW;
4570 InfoW.psd = lpServiceDescriptonW;
4571 ///}
4572 }
4573 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4574 {
4575 LPSERVICE_FAILURE_ACTIONSW lpServiceFailureActionsW;
4576 LPSERVICE_FAILURE_ACTIONSA lpServiceFailureActionsA;
4577 DWORD dwRebootLen = 0;
4578 DWORD dwCommandLen = 0;
4579
4580 lpServiceFailureActionsA = Info.psfa;
4581
4582 if (lpServiceFailureActionsA)
4583 {
4584 if (lpServiceFailureActionsA->lpRebootMsg)
4585 {
4586 dwRebootLen = (strlen(lpServiceFailureActionsA->lpRebootMsg) + 1) * sizeof(WCHAR);
4587 }
4588 if (lpServiceFailureActionsA->lpCommand)
4589 {
4590 dwCommandLen = (strlen(lpServiceFailureActionsA->lpCommand) + 1) * sizeof(WCHAR);
4591 }
4592 dwLength = dwRebootLen + dwCommandLen + sizeof(SERVICE_FAILURE_ACTIONSW);
4593
4594 lpServiceFailureActionsW = HeapAlloc(GetProcessHeap(),
4595 0,
4596 dwLength);
4597 if (!lpServiceFailureActionsW)
4598 {
4599 return ERROR_NOT_ENOUGH_MEMORY;
4600 }
4601
4602 lpServiceFailureActionsW->cActions = lpServiceFailureActionsA->cActions;
4603 lpServiceFailureActionsW->dwResetPeriod = lpServiceFailureActionsA->dwResetPeriod;
4604 CopyMemory(lpServiceFailureActionsW->lpsaActions, lpServiceFailureActionsA->lpsaActions, sizeof(SC_ACTION));
4605
4606 if (lpServiceFailureActionsA->lpRebootMsg)
4607 {
4608 MultiByteToWideChar(CP_ACP,
4609 0,
4610 lpServiceFailureActionsA->lpRebootMsg,
4611 -1,
4612 lpServiceFailureActionsW->lpRebootMsg,
4613 dwRebootLen);
4614 }
4615
4616 if (lpServiceFailureActionsA->lpCommand)
4617 {
4618 MultiByteToWideChar(CP_ACP,
4619 0,
4620 lpServiceFailureActionsA->lpCommand,
4621 -1,
4622 lpServiceFailureActionsW->lpCommand,
4623 dwCommandLen);
4624 }
4625
4626 ptr = lpServiceFailureActionsW;
4627 }
4628 }
4629
4630 dwRet = RChangeServiceConfig2W(hService, InfoW);
4631
4632 HeapFree(GetProcessHeap(), 0, ptr);
4633
4634 return dwRet;
4635 }
4636
4637
4638 /* Function 37 */
4639 DWORD RChangeServiceConfig2W(
4640 SC_RPC_HANDLE hService,
4641 SC_RPC_CONFIG_INFOW Info)
4642 {
4643 DWORD dwError = ERROR_SUCCESS;
4644 PSERVICE_HANDLE hSvc;
4645 PSERVICE lpService = NULL;
4646 HKEY hServiceKey = NULL;
4647
4648 DPRINT("RChangeServiceConfig2W() called\n");
4649 DPRINT("dwInfoLevel = %lu\n", Info.dwInfoLevel);
4650
4651 if (ScmShutdown)
4652 return ERROR_SHUTDOWN_IN_PROGRESS;
4653
4654 hSvc = ScmGetServiceFromHandle(hService);
4655 if (hSvc == NULL)
4656 {
4657 DPRINT1("Invalid service handle!\n");
4658 return ERROR_INVALID_HANDLE;
4659 }
4660
4661 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4662 SERVICE_CHANGE_CONFIG))
4663 {
4664 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4665 return ERROR_ACCESS_DENIED;
4666 }
4667
4668 lpService = hSvc->ServiceEntry;
4669 if (lpService == NULL)
4670 {
4671 DPRINT("lpService == NULL!\n");
4672 return ERROR_INVALID_HANDLE;
4673 }
4674
4675 /* Lock the service database exclusively */
4676 ScmLockDatabaseExclusive();
4677
4678 if (lpService->bDeleted)
4679 {
4680 DPRINT("The service has already been marked for delete!\n");
4681 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
4682 goto done;
4683 }
4684
4685 /* Open the service key */
4686 dwError = ScmOpenServiceKey(lpService->szServiceName,
4687 KEY_SET_VALUE,
4688 &hServiceKey);
4689 if (dwError != ERROR_SUCCESS)
4690 goto done;
4691
4692 if (Info.dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4693 {
4694 LPSERVICE_DESCRIPTIONW lpServiceDescription;
4695
4696 lpServiceDescription = (LPSERVICE_DESCRIPTIONW)Info.psd;
4697 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpServiceDescription + sizeof(LPSERVICE_DESCRIPTIONW));
4698
4699 if (lpServiceDescription != NULL &&
4700 lpServiceDescription->lpDescription != NULL)
4701 {
4702 DPRINT("Setting value %S\n", lpServiceDescription->lpDescription);
4703 dwError = RegSetValueExW(hServiceKey,
4704 L"Description",
4705 0,
4706 REG_SZ,
4707 (LPBYTE)lpServiceDescription->lpDescription,
4708 (wcslen(lpServiceDescription->lpDescription) + 1) * sizeof(WCHAR));
4709 if (dwError != ERROR_SUCCESS)
4710 goto done;
4711 }
4712 }
4713 else if (Info.dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4714 {
4715 UNIMPLEMENTED;
4716 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4717 goto done;
4718 }
4719
4720 done:
4721 /* Unlock the service database */
4722 ScmUnlockDatabase();
4723
4724 if (hServiceKey != NULL)
4725 RegCloseKey(hServiceKey);
4726
4727 DPRINT("RChangeServiceConfig2W() done (Error %lu)\n", dwError);
4728
4729 return dwError;
4730 }
4731
4732
4733 /* Function 38 */
4734 DWORD RQueryServiceConfig2A(
4735 SC_RPC_HANDLE hService,
4736 DWORD dwInfoLevel,
4737 LPBYTE lpBuffer,
4738 DWORD cbBufSize,
4739 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4740 {
4741 DWORD dwError = ERROR_SUCCESS;
4742 PSERVICE_HANDLE hSvc;
4743 PSERVICE lpService = NULL;
4744 HKEY hServiceKey = NULL;
4745 LPWSTR lpDescriptionW = NULL;
4746 LPSTR lpDescription = NULL;
4747
4748 DPRINT("RQueryServiceConfig2A() called hService %p dwInfoLevel %u, lpBuffer %p cbBufSize %u pcbBytesNeeded %p\n",
4749 hService, dwInfoLevel, lpBuffer, cbBufSize, pcbBytesNeeded);
4750
4751 if (!lpBuffer)
4752 return ERROR_INVALID_ADDRESS;
4753
4754 if (ScmShutdown)
4755 return ERROR_SHUTDOWN_IN_PROGRESS;
4756
4757 hSvc = ScmGetServiceFromHandle(hService);
4758 if (hSvc == NULL)
4759 {
4760 DPRINT1("Invalid service handle!\n");
4761 return ERROR_INVALID_HANDLE;
4762 }
4763
4764 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4765 SERVICE_QUERY_CONFIG))
4766 {
4767 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4768 return ERROR_ACCESS_DENIED;
4769 }
4770
4771 lpService = hSvc->ServiceEntry;
4772 if (lpService == NULL)
4773 {
4774 DPRINT("lpService == NULL!\n");
4775 return ERROR_INVALID_HANDLE;
4776 }
4777
4778 /* Lock the service database shared */
4779 ScmLockDatabaseShared();
4780
4781 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4782 KEY_READ,
4783 &hServiceKey);
4784 if (dwError != ERROR_SUCCESS)
4785 goto done;
4786
4787 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4788 {
4789 LPSERVICE_DESCRIPTIONA lpServiceDescription = (LPSERVICE_DESCRIPTIONA)lpBuffer;
4790 LPSTR lpStr;
4791
4792 dwError = ScmReadString(hServiceKey,
4793 L"Description",
4794 &lpDescriptionW);
4795 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4796 goto done;
4797
4798 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONA);
4799 if (dwError == ERROR_SUCCESS)
4800 *pcbBytesNeeded += ((wcslen(lpDescriptionW) + 1) * sizeof(WCHAR));
4801
4802 if (cbBufSize < *pcbBytesNeeded)
4803 {
4804 dwError = ERROR_INSUFFICIENT_BUFFER;
4805 goto done;
4806 }
4807
4808 if (dwError == ERROR_SUCCESS)
4809 {
4810 lpStr = (LPSTR)(lpServiceDescription + 1);
4811
4812 WideCharToMultiByte(CP_ACP,
4813 0,
4814 lpDescriptionW,
4815 -1,
4816 lpStr,
4817 wcslen(lpDescriptionW),
4818 NULL,
4819 NULL);
4820 lpServiceDescription->lpDescription = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4821 }
4822 else
4823 {
4824 lpServiceDescription->lpDescription = NULL;
4825 dwError = ERROR_SUCCESS;
4826 goto done;
4827 }
4828 }
4829 else if (dwInfoLevel & SERVICE_CONFIG_FAILURE_ACTIONS)
4830 {
4831 UNIMPLEMENTED;
4832 dwError = ERROR_CALL_NOT_IMPLEMENTED;
4833 goto done;
4834 }
4835
4836 done:
4837 /* Unlock the service database */
4838 ScmUnlockDatabase();
4839
4840 if (lpDescription != NULL)
4841 HeapFree(GetProcessHeap(), 0, lpDescription);
4842
4843 if (hServiceKey != NULL)
4844 RegCloseKey(hServiceKey);
4845
4846 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
4847
4848 return dwError;
4849 }
4850
4851
4852 /* Function 39 */
4853 DWORD RQueryServiceConfig2W(
4854 SC_RPC_HANDLE hService,
4855 DWORD dwInfoLevel,
4856 LPBYTE lpBuffer,
4857 DWORD cbBufSize,
4858 LPBOUNDED_DWORD_8K pcbBytesNeeded)
4859 {
4860 DWORD dwError = ERROR_SUCCESS;
4861 PSERVICE_HANDLE hSvc;
4862 PSERVICE lpService = NULL;
4863 HKEY hServiceKey = NULL;
4864 DWORD dwRequiredSize;
4865 LPWSTR lpDescription = NULL;
4866 LPWSTR lpFailureCommand = NULL;
4867 LPWSTR lpRebootMessage = NULL;
4868
4869 DPRINT("RQueryServiceConfig2W() called\n");
4870
4871 if (!lpBuffer)
4872 return ERROR_INVALID_ADDRESS;
4873
4874 if (ScmShutdown)
4875 return ERROR_SHUTDOWN_IN_PROGRESS;
4876
4877 hSvc = ScmGetServiceFromHandle(hService);
4878 if (hSvc == NULL)
4879 {
4880 DPRINT1("Invalid service handle!\n");
4881 return ERROR_INVALID_HANDLE;
4882 }
4883
4884 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
4885 SERVICE_QUERY_CONFIG))
4886 {
4887 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
4888 return ERROR_ACCESS_DENIED;
4889 }
4890
4891 lpService = hSvc->ServiceEntry;
4892 if (lpService == NULL)
4893 {
4894 DPRINT("lpService == NULL!\n");
4895 return ERROR_INVALID_HANDLE;
4896 }
4897
4898 /* Lock the service database shared */
4899 ScmLockDatabaseShared();
4900
4901 dwError = ScmOpenServiceKey(lpService->lpServiceName,
4902 KEY_READ,
4903 &hServiceKey);
4904 if (dwError != ERROR_SUCCESS)
4905 goto done;
4906
4907 if (dwInfoLevel == SERVICE_CONFIG_DESCRIPTION)
4908 {
4909 LPSERVICE_DESCRIPTIONW lpServiceDescription = (LPSERVICE_DESCRIPTIONW)lpBuffer;
4910 LPWSTR lpStr;
4911
4912 dwError = ScmReadString(hServiceKey,
4913 L"Description",
4914 &lpDescription);
4915 if (dwError != ERROR_SUCCESS && dwError != ERROR_FILE_NOT_FOUND)
4916 goto done;
4917
4918 *pcbBytesNeeded = sizeof(SERVICE_DESCRIPTIONW);
4919 if (dwError == ERROR_SUCCESS)
4920 *pcbBytesNeeded += ((wcslen(lpDescription) + 1) * sizeof(WCHAR));
4921
4922 if (cbBufSize < *pcbBytesNeeded)
4923 {
4924 dwError = ERROR_INSUFFICIENT_BUFFER;
4925 goto done;
4926 }
4927
4928 if (dwError == ERROR_SUCCESS)
4929 {
4930 lpStr = (LPWSTR)(lpServiceDescription + 1);
4931 wcscpy(lpStr, lpDescription);
4932 lpServiceDescription->lpDescription = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceDescription);
4933 }
4934 else
4935 {
4936 lpServiceDescription->lpDescription = NULL;
4937 dwError = ERROR_SUCCESS;
4938 }
4939 }
4940 else if (dwInfoLevel == SERVICE_CONFIG_FAILURE_ACTIONS)
4941 {
4942 LPWSTR lpStr;
4943 LPSERVICE_FAILURE_ACTIONSW lpFailureActions = (LPSERVICE_FAILURE_ACTIONSW)lpBuffer;
4944
4945 UNIMPLEMENTED;
4946
4947 dwError = ScmReadString(hServiceKey,
4948 L"FailureCommand",
4949 &lpFailureCommand);
4950
4951 dwError = ScmReadString(hServiceKey,
4952 L"RebootMessage",
4953 &lpRebootMessage);
4954
4955 dwRequiredSize = sizeof(SERVICE_FAILURE_ACTIONSW);
4956
4957 if (lpFailureCommand)
4958 dwRequiredSize += (wcslen(lpFailureCommand) + 1) * sizeof(WCHAR);
4959
4960 if (lpRebootMessage)
4961 dwRequiredSize += (wcslen(lpRebootMessage) + 1) * sizeof(WCHAR);
4962
4963 if (cbBufSize < dwRequiredSize)
4964 {
4965 *pcbBytesNeeded = dwRequiredSize;
4966 dwError = ERROR_INSUFFICIENT_BUFFER;
4967 goto done;
4968 }
4969
4970 lpFailureActions->cActions = 0;
4971 lpFailureActions->dwResetPeriod = 0;
4972 lpFailureActions->lpCommand = NULL;
4973 lpFailureActions->lpRebootMsg = NULL;
4974 lpFailureActions->lpsaActions = NULL;
4975
4976 lpStr = (LPWSTR)(lpFailureActions + 1);
4977 if (lpRebootMessage)
4978 {
4979 wcscpy(lpStr, lpRebootMessage);
4980 lpFailureActions->lpRebootMsg = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpRebootMessage);
4981 lpStr += wcslen(lpRebootMessage) + 1;
4982 }
4983
4984 if (lpFailureCommand)
4985 {
4986 wcscpy(lpStr, lpFailureCommand);
4987 lpFailureActions->lpCommand = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpFailureCommand);
4988 lpStr += wcslen(lpRebootMessage) + 1;
4989 }
4990 dwError = STATUS_SUCCESS;
4991 goto done;
4992 }
4993
4994 done:
4995 /* Unlock the service database */
4996 ScmUnlockDatabase();
4997
4998 if (lpDescription != NULL)
4999 HeapFree(GetProcessHeap(), 0, lpDescription);
5000
5001 if (lpRebootMessage != NULL)
5002 HeapFree(GetProcessHeap(), 0, lpRebootMessage);
5003
5004 if (lpFailureCommand != NULL)
5005 HeapFree(GetProcessHeap(), 0, lpFailureCommand);
5006
5007 if (hServiceKey != NULL)
5008 RegCloseKey(hServiceKey);
5009
5010 DPRINT("RQueryServiceConfig2W() done (Error %lu)\n", dwError);
5011
5012 return dwError;
5013 }
5014
5015
5016 /* Function 40 */
5017 DWORD RQueryServiceStatusEx(
5018 SC_RPC_HANDLE hService,
5019 SC_STATUS_TYPE InfoLevel,
5020 LPBYTE lpBuffer,
5021 DWORD cbBufSize,
5022 LPBOUNDED_DWORD_8K pcbBytesNeeded)
5023 {
5024 LPSERVICE_STATUS_PROCESS lpStatus;
5025 PSERVICE_HANDLE hSvc;
5026 PSERVICE lpService;
5027
5028 DPRINT("RQueryServiceStatusEx() called\n");
5029
5030 if (ScmShutdown)
5031 return ERROR_SHUTDOWN_IN_PROGRESS;
5032
5033 if (InfoLevel != SC_STATUS_PROCESS_INFO)
5034 return ERROR_INVALID_LEVEL;
5035
5036 *pcbBytesNeeded = sizeof(SERVICE_STATUS_PROCESS);
5037
5038 if (cbBufSize < sizeof(SERVICE_STATUS_PROCESS))
5039 return ERROR_INSUFFICIENT_BUFFER;
5040
5041 hSvc = ScmGetServiceFromHandle(hService);
5042 if (hSvc == NULL)
5043 {
5044 DPRINT1("Invalid service handle!\n");
5045 return ERROR_INVALID_HANDLE;
5046 }
5047
5048 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
5049 SERVICE_QUERY_STATUS))
5050 {
5051 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
5052 return ERROR_ACCESS_DENIED;
5053 }
5054
5055 lpService = hSvc->ServiceEntry;
5056 if (lpService == NULL)
5057 {
5058 DPRINT("lpService == NULL!\n");
5059 return ERROR_INVALID_HANDLE;
5060 }
5061
5062 /* Lock the service database shared */
5063 ScmLockDatabaseShared();
5064
5065 lpStatus = (LPSERVICE_STATUS_PROCESS)lpBuffer;
5066
5067 /* Return service status information */
5068 RtlCopyMemory(lpStatus,
5069 &lpService->Status,
5070 sizeof(SERVICE_STATUS));
5071
5072 lpStatus->dwProcessId = (lpService->lpImage != NULL) ? lpService->lpImage->dwProcessId : 0; /* FIXME */
5073 lpStatus->dwServiceFlags = 0; /* FIXME */
5074
5075 /* Unlock the service database */
5076 ScmUnlockDatabase();
5077
5078 return ERROR_SUCCESS;
5079 }
5080
5081
5082 /* Function 41 */
5083 DWORD REnumServicesStatusExA(
5084 SC_RPC_HANDLE hSCManager,
5085 SC_ENUM_TYPE InfoLevel,
5086 DWORD dwServiceType,
5087 DWORD dwServiceState,
5088 LPBYTE lpBuffer,
5089 DWORD cbBufSize,
5090 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5091 LPBOUNDED_DWORD_256K lpServicesReturned,
5092 LPBOUNDED_DWORD_256K lpResumeIndex,
5093 LPCSTR pszGroupName)
5094 {
5095 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtrW = NULL;
5096 LPENUM_SERVICE_STATUS_PROCESSA lpStatusPtrA = NULL;
5097 LPWSTR lpStringPtrW;
5098 LPSTR lpStringPtrA;
5099 LPWSTR pszGroupNameW = NULL;
5100 DWORD dwError;
5101 DWORD dwServiceCount;
5102
5103 DPRINT("REnumServicesStatusExA() called\n");
5104
5105 if (pszGroupName)
5106 {
5107 pszGroupNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (strlen(pszGroupName) + 1) * sizeof(WCHAR));
5108 if (!pszGroupNameW)
5109 {
5110 DPRINT("Failed to allocate buffer!\n");
5111 return ERROR_NOT_ENOUGH_MEMORY;
5112 }
5113
5114 MultiByteToWideChar(CP_ACP,
5115 0,
5116 pszGroupName,
5117 -1,
5118 pszGroupNameW,
5119 strlen(pszGroupName) + 1);
5120 }
5121
5122 if ((cbBufSize > 0) && (lpBuffer))
5123 {
5124 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, cbBufSize);
5125 if (!lpStatusPtrW)
5126 {
5127 DPRINT("Failed to allocate buffer!\n");
5128 return ERROR_NOT_ENOUGH_MEMORY;
5129 }
5130 }
5131
5132 dwError = REnumServicesStatusExW(hSCManager,
5133 InfoLevel,
5134 dwServiceType,
5135 dwServiceState,
5136 (LPBYTE)lpStatusPtrW,
5137 cbBufSize,
5138 pcbBytesNeeded,
5139 lpServicesReturned,
5140 lpResumeIndex,
5141 pszGroupNameW);
5142
5143 /* if no services were returned then we are Done */
5144 if (*lpServicesReturned == 0)
5145 goto Done;
5146
5147 lpStatusPtrA = (LPENUM_SERVICE_STATUS_PROCESSA)lpBuffer;
5148 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
5149 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSA));
5150 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
5151 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5152
5153 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
5154 {
5155 /* Copy the service name */
5156 WideCharToMultiByte(CP_ACP,
5157 0,
5158 lpStringPtrW,
5159 -1,
5160 lpStringPtrA,
5161 wcslen(lpStringPtrW),
5162 0,
5163 0);
5164
5165 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5166 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5167 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5168
5169 /* Copy the display name */
5170 WideCharToMultiByte(CP_ACP,
5171 0,
5172 lpStringPtrW,
5173 -1,
5174 lpStringPtrA,
5175 wcslen(lpStringPtrW),
5176 0,
5177 0);
5178
5179 lpStatusPtrA->lpDisplayName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);
5180 lpStringPtrA += wcslen(lpStringPtrW) + 1;
5181 lpStringPtrW += wcslen(lpStringPtrW) + 1;
5182
5183 /* Copy the status information */
5184 memcpy(&lpStatusPtrA->ServiceStatusProcess,
5185 &lpStatusPtrW->ServiceStatusProcess,
5186 sizeof(SERVICE_STATUS));
5187
5188 lpStatusPtrA->ServiceStatusProcess.dwProcessId = lpStatusPtrW->ServiceStatusProcess.dwProcessId; /* FIXME */
5189 lpStatusPtrA->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5190 lpStatusPtrA++;
5191 }
5192
5193 Done:;
5194 if (pszGroupNameW)
5195 HeapFree(GetProcessHeap(), 0, pszGroupNameW);
5196
5197 if (lpStatusPtrW)
5198 HeapFree(GetProcessHeap(), 0, lpStatusPtrW);
5199
5200 DPRINT("REnumServicesStatusExA() done (Error %lu)\n", dwError);
5201
5202 return dwError;
5203 }
5204
5205
5206 /* Function 42 */
5207 DWORD REnumServicesStatusExW(
5208 SC_RPC_HANDLE hSCManager,
5209 SC_ENUM_TYPE InfoLevel,
5210 DWORD dwServiceType,
5211 DWORD dwServiceState,
5212 LPBYTE lpBuffer,
5213 DWORD cbBufSize,
5214 LPBOUNDED_DWORD_256K pcbBytesNeeded,
5215 LPBOUNDED_DWORD_256K lpServicesReturned,
5216 LPBOUNDED_DWORD_256K lpResumeIndex,
5217 LPCWSTR pszGroupName)
5218 {
5219 PMANAGER_HANDLE hManager;
5220 PSERVICE lpService;
5221 DWORD dwError = ERROR_SUCCESS;
5222 PLIST_ENTRY ServiceEntry;
5223 PSERVICE CurrentService;
5224 DWORD dwState;
5225 DWORD dwRequiredSize;
5226 DWORD dwServiceCount;
5227 DWORD dwSize;
5228 DWORD dwLastResumeCount = 0;
5229 LPENUM_SERVICE_STATUS_PROCESSW lpStatusPtr;
5230 LPWSTR lpStringPtr;
5231
5232 DPRINT("REnumServicesStatusExW() called\n");
5233
5234 if (ScmShutdown)
5235 return ERROR_SHUTDOWN_IN_PROGRESS;
5236
5237 if (InfoLevel != SC_ENUM_PROCESS_INFO)
5238 return ERROR_INVALID_LEVEL;
5239
5240 hManager = ScmGetServiceManagerFromHandle(hSCManager);
5241 if (hManager == NULL)
5242 {
5243 DPRINT1("Invalid service manager handle!\n");
5244 return ERROR_INVALID_HANDLE;
5245 }
5246
5247 *pcbBytesNeeded = 0;
5248 *lpServicesReturned = 0;
5249
5250 if ((dwServiceType!=SERVICE_DRIVER) && (dwServiceType!=SERVICE_WIN32))
5251 {
5252 DPRINT("Not a valid Service Type!\n");
5253 return ERROR_INVALID_PARAMETER;
5254 }
5255
5256 if ((dwServiceState<SERVICE_ACTIVE) || (dwServiceState>SERVICE_STATE_ALL))
5257 {
5258 DPRINT("Not a valid Service State!\n");
5259 return ERROR_INVALID_PARAMETER;
5260 }
5261
5262 /* Check access rights */
5263 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
5264 SC_MANAGER_ENUMERATE_SERVICE))
5265 {
5266 DPRINT("Insufficient access rights! 0x%lx\n",
5267 hManager->Handle.DesiredAccess);
5268 return ERROR_ACCESS_DENIED;
5269 }
5270
5271 if (lpResumeIndex)
5272 dwLastResumeCount = *lpResumeIndex;
5273
5274 /* Lock the service database shared */
5275 ScmLockDatabaseShared();
5276
5277 lpService = ScmGetServiceEntryByResumeCount(dwLastResumeCount);
5278 if (lpService == NULL)
5279 {
5280 dwError = ERROR_SUCCESS;
5281 goto Done;
5282 }
5283
5284 dwRequiredSize = 0;
5285 dwServiceCount = 0;
5286
5287 for (ServiceEntry = &lpService->ServiceListEntry;
5288 ServiceEntry != &ServiceListHead;
5289 ServiceEntry = ServiceEntry->Flink)
5290 {
5291 CurrentService = CONTAINING_RECORD(ServiceEntry,
5292 SERVICE,
5293 ServiceListEntry);
5294
5295 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5296 continue;
5297
5298 dwState = SERVICE_ACTIVE;
5299 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5300 dwState = SERVICE_INACTIVE;
5301
5302 if ((dwState & dwServiceState) == 0)
5303 continue;
5304
5305 if (pszGroupName)
5306 {
5307 if (*pszGroupName == 0)
5308 {
5309 if (CurrentService->lpGroup != NULL)
5310 continue;
5311 }
5312 else
5313 {
5314 if ((CurrentService->lpGroup == NULL) ||
5315 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5316 continue;
5317 }
5318 }
5319
5320 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5321 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5322 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5323
5324 if (dwRequiredSize + dwSize <= cbBufSize)
5325 {
5326 DPRINT("Service name: %S fit\n", CurrentService->lpServiceName);
5327 dwRequiredSize += dwSize;
5328 dwServiceCount++;
5329 dwLastResumeCount = CurrentService->dwResumeCount;
5330 }
5331 else
5332 {
5333 DPRINT("Service name: %S no fit\n", CurrentService->lpServiceName);
5334 break;
5335 }
5336
5337 }
5338
5339 DPRINT("dwRequiredSize: %lu\n", dwRequiredSize);
5340 DPRINT("dwServiceCount: %lu\n", dwServiceCount);
5341
5342 for (;
5343 ServiceEntry != &ServiceListHead;
5344 ServiceEntry = ServiceEntry->Flink)
5345 {
5346 CurrentService = CONTAINING_RECORD(ServiceEntry,
5347 SERVICE,
5348 ServiceListEntry);
5349
5350 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5351 continue;
5352
5353 dwState = SERVICE_ACTIVE;
5354 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5355 dwState = SERVICE_INACTIVE;
5356
5357 if ((dwState & dwServiceState) == 0)
5358 continue;
5359
5360 if (pszGroupName)
5361 {
5362 if (*pszGroupName == 0)
5363 {
5364 if (CurrentService->lpGroup != NULL)
5365 continue;
5366 }
5367 else
5368 {
5369 if ((CurrentService->lpGroup == NULL) ||
5370 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5371 continue;
5372 }
5373 }
5374
5375 dwRequiredSize += (sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5376 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5377 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR)));
5378
5379 dwError = ERROR_MORE_DATA;
5380 }
5381
5382 DPRINT("*pcbBytesNeeded: %lu\n", dwRequiredSize);
5383
5384 if (lpResumeIndex)
5385 *lpResumeIndex = dwLastResumeCount;
5386
5387 *lpServicesReturned = dwServiceCount;
5388 *pcbBytesNeeded = dwRequiredSize;
5389
5390 /* If there was no services that matched */
5391 if ((!dwServiceCount) && (dwError != ERROR_MORE_DATA))
5392 {
5393 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
5394 goto Done;
5395 }
5396
5397 lpStatusPtr = (LPENUM_SERVICE_STATUS_PROCESSW)lpBuffer;
5398 lpStringPtr = (LPWSTR)((ULONG_PTR)lpBuffer +
5399 dwServiceCount * sizeof(ENUM_SERVICE_STATUS_PROCESSW));
5400
5401 dwRequiredSize = 0;
5402 for (ServiceEntry = &lpService->ServiceListEntry;
5403 ServiceEntry != &ServiceListHead;
5404 ServiceEntry = ServiceEntry->Flink)
5405 {
5406 CurrentService = CONTAINING_RECORD(ServiceEntry,
5407 SERVICE,
5408 ServiceListEntry);
5409
5410 if ((CurrentService->Status.dwServiceType & dwServiceType) == 0)
5411 continue;
5412
5413 dwState = SERVICE_ACTIVE;
5414 if (CurrentService->Status.dwCurrentState == SERVICE_STOPPED)
5415 dwState = SERVICE_INACTIVE;
5416
5417 if ((dwState & dwServiceState) == 0)
5418 continue;
5419
5420 if (pszGroupName)
5421 {
5422 if (*pszGroupName == 0)
5423 {
5424 if (CurrentService->lpGroup != NULL)
5425 continue;
5426 }
5427 else
5428 {
5429 if ((CurrentService->lpGroup == NULL) ||
5430 _wcsicmp(pszGroupName, CurrentService->lpGroup->lpGroupName))
5431 continue;
5432 }
5433 }
5434
5435 dwSize = sizeof(ENUM_SERVICE_STATUS_PROCESSW) +
5436 ((wcslen(CurrentService->lpServiceName) + 1) * sizeof(WCHAR)) +
5437 ((wcslen(CurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
5438
5439 if (dwRequiredSize + dwSize <= cbBufSize)
5440 {
5441 /* Copy the service name */
5442 wcscpy(lpStringPtr,
5443 CurrentService->lpServiceName);
5444 lpStatusPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5445 lpStringPtr += (wcslen(CurrentService->lpServiceName) + 1);
5446
5447 /* Copy the display name */
5448 wcscpy(lpStringPtr,
5449 CurrentService->lpDisplayName);
5450 lpStatusPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStringPtr - (ULONG_PTR)lpBuffer);
5451 lpStringPtr += (wcslen(CurrentService->lpDisplayName) + 1);
5452
5453 /* Copy the status information */
5454 memcpy(&lpStatusPtr->ServiceStatusProcess,
5455 &CurrentService->Status,
5456 sizeof(SERVICE_STATUS));
5457 lpStatusPtr->ServiceStatusProcess.dwProcessId =
5458 (CurrentService->lpImage != NULL) ? CurrentService->lpImage->dwProcessId : 0; /* FIXME */
5459 lpStatusPtr->ServiceStatusProcess.dwServiceFlags = 0; /* FIXME */
5460
5461 lpStatusPtr++;
5462 dwRequiredSize += dwSize;
5463 }
5464 else
5465 {
5466 break;
5467 }
5468 }
5469
5470 if (dwError == 0)
5471 {
5472 *pcbBytesNeeded = 0;
5473 if (lpResumeIndex)
5474 *lpResumeIndex = 0;
5475 }
5476
5477 Done:;
5478 /* Unlock the service database */
5479 ScmUnlockDatabase();
5480
5481 DPRINT("REnumServicesStatusExW() done (Error %lu)\n", dwError);
5482
5483 return dwError;
5484 }
5485
5486
5487 /* Function 43 */
5488 DWORD RSendTSMessage(
5489 handle_t BindingHandle) /* FIXME */
5490 {
5491 UNIMPLEMENTED;
5492 return ERROR_CALL_NOT_IMPLEMENTED;
5493 }
5494
5495
5496 /* Function 44 */
5497 DWORD RCreateServiceWOW64A(
5498 handle_t BindingHandle,
5499 LPSTR lpServiceName,
5500 LPSTR lpDisplayName,
5501 DWORD dwDesiredAccess,
5502 DWORD dwServiceType,
5503 DWORD dwStartType,
5504 DWORD dwErrorControl,
5505 LPSTR lpBinaryPathName,
5506 LPSTR lpLoadOrderGroup,
5507 LPDWORD lpdwTagId,
5508 LPBYTE lpDependencies,
5509 DWORD dwDependSize,
5510 LPSTR lpServiceStartName,
5511 LPBYTE lpPassword,
5512 DWORD dwPwSize,
5513 LPSC_RPC_HANDLE lpServiceHandle)
5514 {
5515 UNIMPLEMENTED;
5516 return ERROR_CALL_NOT_IMPLEMENTED;
5517 }
5518
5519
5520 /* Function 45 */
5521 DWORD RCreateServiceWOW64W(
5522 handle_t BindingHandle,
5523 LPWSTR lpServiceName,
5524 LPWSTR lpDisplayName,
5525 DWORD dwDesiredAccess,
5526 DWORD dwServiceType,
5527 DWORD dwStartType,
5528 DWORD dwErrorControl,
5529 LPWSTR lpBinaryPathName,
5530 LPWSTR lpLoadOrderGroup,
5531 LPDWORD lpdwTagId,
5532 LPBYTE lpDependencies,
5533 DWORD dwDependSize,
5534 LPWSTR lpServiceStartName,
5535 LPBYTE lpPassword,
5536 DWORD dwPwSize,
5537 LPSC_RPC_HANDLE lpServiceHandle)
5538 {
5539 UNIMPLEMENTED;
5540 return ERROR_CALL_NOT_IMPLEMENTED;
5541 }
5542
5543
5544 /* Function 46 */
5545 DWORD RQueryServiceTagInfo(
5546 handle_t BindingHandle) /* FIXME */
5547 {
5548 UNIMPLEMENTED;
5549 return ERROR_CALL_NOT_IMPLEMENTED;
5550 }
5551
5552
5553 /* Function 47 */
5554 DWORD RNotifyServiceStatusChange(
5555 SC_RPC_HANDLE hService,
5556 SC_RPC_NOTIFY_PARAMS NotifyParams,
5557 GUID *pClientProcessGuid,
5558 GUID *pSCMProcessGuid,
5559 PBOOL pfCreateRemoteQueue,
5560 LPSC_NOTIFY_RPC_HANDLE phNotify)
5561 {
5562 UNIMPLEMENTED;
5563 return ERROR_CALL_NOT_IMPLEMENTED;
5564 }
5565
5566
5567 /* Function 48 */
5568 DWORD RGetNotifyResults(
5569 SC_NOTIFY_RPC_HANDLE hNotify,
5570 PSC_RPC_NOTIFY_PARAMS_LIST *ppNotifyParams)
5571 {
5572 UNIMPLEMENTED;
5573 return ERROR_CALL_NOT_IMPLEMENTED;
5574 }
5575
5576
5577 /* Function 49 */
5578 DWORD RCloseNotifyHandle(
5579 LPSC_NOTIFY_RPC_HANDLE phNotify,
5580 PBOOL pfApcFired)
5581 {
5582 UNIMPLEMENTED;
5583 return ERROR_CALL_NOT_IMPLEMENTED;
5584 }
5585
5586
5587 /* Function 50 */
5588 DWORD RControlServiceExA(
5589 SC_RPC_HANDLE hService,
5590 DWORD dwControl,
5591 DWORD dwInfoLevel)
5592 {
5593 UNIMPLEMENTED;
5594 return ERROR_CALL_NOT_IMPLEMENTED;
5595 }
5596
5597
5598 /* Function 51 */
5599 DWORD RControlServiceExW(
5600 SC_RPC_HANDLE hService,
5601 DWORD dwControl,
5602 DWORD dwInfoLevel)
5603 {
5604 UNIMPLEMENTED;
5605 return ERROR_CALL_NOT_IMPLEMENTED;
5606 }
5607
5608
5609 /* Function 52 */
5610 DWORD RSendPnPMessage(
5611 handle_t BindingHandle) /* FIXME */
5612 {
5613 UNIMPLEMENTED;
5614 return ERROR_CALL_NOT_IMPLEMENTED;
5615 }
5616
5617
5618 /* Function 53 */
5619 DWORD RValidatePnPService(
5620 handle_t BindingHandle) /* FIXME */
5621 {
5622 UNIMPLEMENTED;
5623 return ERROR_CALL_NOT_IMPLEMENTED;
5624 }
5625
5626
5627 /* Function 54 */
5628 DWORD ROpenServiceStatusHandle(
5629 handle_t BindingHandle) /* FIXME */
5630 {
5631 UNIMPLEMENTED;
5632 return ERROR_CALL_NOT_IMPLEMENTED;
5633 }
5634
5635
5636 /* Function 55 */
5637 DWORD RFunction55(
5638 handle_t BindingHandle) /* FIXME */
5639 {
5640 UNIMPLEMENTED;
5641 return ERROR_CALL_NOT_IMPLEMENTED;
5642 }
5643
5644
5645 void __RPC_FAR * __RPC_USER midl_user_allocate(SIZE_T len)
5646 {
5647 return HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len);
5648 }
5649
5650
5651 void __RPC_USER midl_user_free(void __RPC_FAR * ptr)
5652 {
5653 HeapFree(GetProcessHeap(), 0, ptr);
5654 }
5655
5656
5657 void __RPC_USER SC_RPC_HANDLE_rundown(SC_RPC_HANDLE hSCObject)
5658 {
5659 }
5660
5661
5662 void __RPC_USER SC_RPC_LOCK_rundown(SC_RPC_LOCK Lock)
5663 {
5664 }
5665
5666
5667 void __RPC_USER SC_NOTIFY_RPC_HANDLE_rundown(SC_NOTIFY_RPC_HANDLE hNotify)
5668 {
5669 }
5670
5671 /* EOF */