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