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