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