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