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