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