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