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