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