ae6c721410a7463e538244b02d71052922479d66
[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
467 if (BufferSize <= 1)
468 {
469 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
470 return ERROR_INVALID_ENVIRONMENT;
471 }
472
473 /* Allocate memory, since the size is known now */
474 Expanded = HeapAlloc(GetProcessHeap(),
475 HEAP_ZERO_MEMORY,
476 (BufferSize + 1) * sizeof(WCHAR));
477 if (!Expanded)
478 {
479 DPRINT("Error allocating memory for boot driver name!\n");
480 return ERROR_NOT_ENOUGH_MEMORY;
481 }
482
483 /* Expand it */
484 if (ExpandEnvironmentStringsW(L"%SystemRoot%\\", Expanded, BufferSize) >
485 BufferSize)
486 {
487 DPRINT("Error during a call to ExpandEnvironmentStringsW()\n");
488 HeapFree(GetProcessHeap(), 0, Expanded);
489 return ERROR_NOT_ENOUGH_MEMORY;
490 }
491
492 /* Convert to NT-style path */
493 if (!RtlDosPathNameToNtPathName_U(Expanded, &NtPathName, NULL, NULL))
494 {
495 DPRINT("Error during a call to RtlDosPathNameToNtPathName_U()\n");
496 return ERROR_INVALID_ENVIRONMENT;
497 }
498
499 DPRINT("Converted to NT-style %wZ\n", &NtPathName);
500
501 /* No need to keep the dos-path anymore */
502 HeapFree(GetProcessHeap(), 0, Expanded);
503
504 /* Copy it to the allocated place */
505 Expanded = HeapAlloc(GetProcessHeap(),
506 HEAP_ZERO_MEMORY,
507 NtPathName.Length + sizeof(UNICODE_NULL));
508 if (!Expanded)
509 {
510 DPRINT("Error allocating memory for boot driver name!\n");
511 RtlFreeUnicodeString(&NtPathName);
512 return ERROR_NOT_ENOUGH_MEMORY;
513 }
514
515 ExpandedLen = NtPathName.Length / sizeof(WCHAR);
516 wcsncpy(Expanded, NtPathName.Buffer, ExpandedLen);
517 Expanded[ExpandedLen] = UNICODE_NULL;
518 RtlFreeUnicodeString(&NtPathName);
519
520 if (ServiceNameLen > ExpandedLen &&
521 !_wcsnicmp(Expanded, CanonName, ExpandedLen))
522 {
523 HeapFree(GetProcessHeap(), 0, Expanded);
524
525 /* Only \SystemRoot\ is missing */
526 *RelativeName = HeapAlloc(GetProcessHeap(),
527 HEAP_ZERO_MEMORY,
528 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
529 if (*RelativeName == NULL)
530 {
531 DPRINT("Error allocating memory for boot driver name!\n");
532 return ERROR_NOT_ENOUGH_MEMORY;
533 }
534
535 wcscpy(*RelativeName, L"\\SystemRoot\\");
536 wcscat(*RelativeName, CanonName + ExpandedLen);
537
538 return ERROR_SUCCESS;
539 }
540
541 /* No longer need this */
542 HeapFree(GetProcessHeap(), 0, Expanded);
543
544 /* The most complex case starts here */
545 RtlInitUnicodeString(&SystemRoot, L"\\SystemRoot");
546 InitializeObjectAttributes(&ObjectAttributes,
547 &SystemRoot,
548 OBJ_CASE_INSENSITIVE,
549 NULL,
550 NULL);
551
552 /* Open this symlink */
553 Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, SYMBOLIC_LINK_QUERY, &ObjectAttributes);
554 if (NT_SUCCESS(Status))
555 {
556 DPRINT("Opened symbolic link object\n");
557
558 RtlInitEmptyUnicodeString(&LinkTarget, NULL, 0);
559 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
560 if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
561 {
562 /* Check if required buffer size is sane */
563 if (BufferSize > UNICODE_STRING_MAX_BYTES - sizeof(UNICODE_NULL))
564 {
565 DPRINT("Too large buffer required\n");
566
567 NtClose(SymbolicLinkHandle);
568 return ERROR_NOT_ENOUGH_MEMORY;
569 }
570
571 /* Alloc the string */
572 LinkTarget.Length = (USHORT)BufferSize;
573 LinkTarget.MaximumLength = LinkTarget.Length + sizeof(UNICODE_NULL);
574 LinkTarget.Buffer = HeapAlloc(GetProcessHeap(),
575 HEAP_ZERO_MEMORY,
576 LinkTarget.MaximumLength);
577 if (!LinkTarget.Buffer)
578 {
579 DPRINT("Unable to alloc buffer\n");
580 NtClose(SymbolicLinkHandle);
581 return ERROR_NOT_ENOUGH_MEMORY;
582 }
583
584 /* Do a real query now */
585 Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, &LinkTarget, &BufferSize);
586 NtClose(SymbolicLinkHandle);
587 if (NT_SUCCESS(Status))
588 {
589 DPRINT("LinkTarget: %wZ\n", &LinkTarget);
590
591 ExpandedLen = LinkTarget.Length / sizeof(WCHAR);
592 if ((ServiceNameLen > ExpandedLen) &&
593 !_wcsnicmp(LinkTarget.Buffer, CanonName, ExpandedLen))
594 {
595 *RelativeName = HeapAlloc(GetProcessHeap(),
596 HEAP_ZERO_MEMORY,
597 (ServiceNameLen - ExpandedLen) * sizeof(WCHAR) + 13*sizeof(WCHAR));
598
599 if (*RelativeName == NULL)
600 {
601 DPRINT("Unable to alloc buffer\n");
602 return ERROR_NOT_ENOUGH_MEMORY;
603 }
604
605 /* Copy it over, substituting the first part
606 with SystemRoot */
607 wcscpy(*RelativeName, L"\\SystemRoot\\");
608 wcscat(*RelativeName, CanonName+ExpandedLen+1);
609
610 /* Return success */
611 return ERROR_SUCCESS;
612 }
613 else
614 {
615 return ERROR_INVALID_PARAMETER;
616 }
617 }
618 else
619 {
620 DPRINT("Error, Status = %08X\n", Status);
621 return ERROR_INVALID_PARAMETER;
622 }
623 }
624 else
625 {
626 DPRINT("Error, Status = %08X\n", Status);
627 NtClose(SymbolicLinkHandle);
628 return ERROR_INVALID_PARAMETER;
629 }
630 }
631 else
632 {
633 /* Failure */
634 DPRINT("Error, Status = %08X\n", Status);
635 return ERROR_INVALID_PARAMETER;
636 }
637 }
638
639
640 DWORD
641 ScmCanonDriverImagePath(DWORD dwStartType,
642 const wchar_t *lpServiceName,
643 wchar_t **lpCanonName)
644 {
645 DWORD Result;
646 SIZE_T ServiceNameLen;
647 UNICODE_STRING NtServiceName;
648 WCHAR *RelativeName;
649 const WCHAR *SourceName = lpServiceName;
650
651 /* Calculate the length of the service's name */
652 ServiceNameLen = wcslen(lpServiceName);
653
654 /* 12 is wcslen(L"\\SystemRoot\\") */
655 if (ServiceNameLen > 12 &&
656 !_wcsnicmp(L"\\SystemRoot\\", lpServiceName, 12))
657 {
658 /* SystemRoot prefix is already included */
659 *lpCanonName = HeapAlloc(GetProcessHeap(),
660 HEAP_ZERO_MEMORY,
661 (ServiceNameLen + 1) * sizeof(WCHAR));
662
663 if (*lpCanonName == NULL)
664 {
665 DPRINT("Error allocating memory for canonized service name!\n");
666 return ERROR_NOT_ENOUGH_MEMORY;
667 }
668
669 /* If it's a boot-time driver, it must be systemroot relative */
670 if (dwStartType == SERVICE_BOOT_START)
671 SourceName += 12;
672
673 /* Copy it */
674 wcscpy(*lpCanonName, SourceName);
675
676 DPRINT("Canonicalized name %S\n", *lpCanonName);
677 return NO_ERROR;
678 }
679
680 /* Check if it has %SystemRoot% (len=13) */
681 if (ServiceNameLen > 13 &&
682 !_wcsnicmp(L"%SystemRoot%\\", lpServiceName, 13))
683 {
684 /* Substitute %SystemRoot% with \\SystemRoot\\ */
685 *lpCanonName = HeapAlloc(GetProcessHeap(),
686 HEAP_ZERO_MEMORY,
687 (ServiceNameLen + 1) * sizeof(WCHAR));
688
689 if (*lpCanonName == NULL)
690 {
691 DPRINT("Error allocating memory for canonized service name!\n");
692 return ERROR_NOT_ENOUGH_MEMORY;
693 }
694
695 /* If it's a boot-time driver, it must be systemroot relative */
696 if (dwStartType == SERVICE_BOOT_START)
697 wcscpy(*lpCanonName, L"\\SystemRoot\\");
698
699 wcscat(*lpCanonName, lpServiceName + 13);
700
701 DPRINT("Canonicalized name %S\n", *lpCanonName);
702 return NO_ERROR;
703 }
704
705 /* Check if it's a relative path name */
706 if (lpServiceName[0] != L'\\' && lpServiceName[1] != L':')
707 {
708 *lpCanonName = HeapAlloc(GetProcessHeap(),
709 HEAP_ZERO_MEMORY,
710 (ServiceNameLen + 1) * sizeof(WCHAR));
711
712 if (*lpCanonName == NULL)
713 {
714 DPRINT("Error allocating memory for canonized service name!\n");
715 return ERROR_NOT_ENOUGH_MEMORY;
716 }
717
718 /* Just copy it over without changing */
719 wcscpy(*lpCanonName, lpServiceName);
720
721 return NO_ERROR;
722 }
723
724 /* It seems to be a DOS path, convert it */
725 if (!RtlDosPathNameToNtPathName_U(lpServiceName, &NtServiceName, NULL, NULL))
726 {
727 DPRINT("RtlDosPathNameToNtPathName_U() failed!\n");
728 return ERROR_INVALID_PARAMETER;
729 }
730
731 *lpCanonName = HeapAlloc(GetProcessHeap(),
732 HEAP_ZERO_MEMORY,
733 NtServiceName.Length + sizeof(WCHAR));
734
735 if (*lpCanonName == NULL)
736 {
737 DPRINT("Error allocating memory for canonized service name!\n");
738 RtlFreeUnicodeString(&NtServiceName);
739 return ERROR_NOT_ENOUGH_MEMORY;
740 }
741
742 /* Copy the string */
743 wcsncpy(*lpCanonName, NtServiceName.Buffer, NtServiceName.Length / sizeof(WCHAR));
744
745 /* The unicode string is not needed anymore */
746 RtlFreeUnicodeString(&NtServiceName);
747
748 if (dwStartType != SERVICE_BOOT_START)
749 {
750 DPRINT("Canonicalized name %S\n", *lpCanonName);
751 return NO_ERROR;
752 }
753
754 /* The service is boot-started, so must be relative */
755 Result = ScmConvertToBootPathName(*lpCanonName, &RelativeName);
756 if (Result)
757 {
758 /* There is a problem, free name and return */
759 HeapFree(GetProcessHeap(), 0, *lpCanonName);
760 DPRINT("Error converting named!\n");
761 return Result;
762 }
763
764 ASSERT(RelativeName);
765
766 /* Copy that string */
767 wcscpy(*lpCanonName, RelativeName + 12);
768
769 /* Free the allocated buffer */
770 HeapFree(GetProcessHeap(), 0, RelativeName);
771
772 DPRINT("Canonicalized name %S\n", *lpCanonName);
773
774 /* Success */
775 return NO_ERROR;
776 }
777
778
779 /* Internal recursive function */
780 /* Need to search for every dependency on every service */
781 static DWORD
782 Int_EnumDependentServicesW(HKEY hServicesKey,
783 PSERVICE lpService,
784 DWORD dwServiceState,
785 PSERVICE *lpServices,
786 LPDWORD pcbBytesNeeded,
787 LPDWORD lpServicesReturned)
788 {
789 DWORD dwError = ERROR_SUCCESS;
790 WCHAR szNameBuf[MAX_PATH];
791 WCHAR szValueBuf[MAX_PATH];
792 WCHAR *lpszNameBuf = szNameBuf;
793 WCHAR *lpszValueBuf = szValueBuf;
794 DWORD dwSize;
795 DWORD dwNumSubKeys;
796 DWORD dwIteration;
797 PSERVICE lpCurrentService;
798 HKEY hServiceEnumKey;
799 DWORD dwCurrentServiceState = SERVICE_ACTIVE;
800 DWORD dwDependServiceStrPtr = 0;
801 DWORD dwRequiredSize = 0;
802
803 /* Get the number of service keys */
804 dwError = RegQueryInfoKeyW(hServicesKey,
805 NULL,
806 NULL,
807 NULL,
808 &dwNumSubKeys,
809 NULL,
810 NULL,
811 NULL,
812 NULL,
813 NULL,
814 NULL,
815 NULL);
816 if (dwError != ERROR_SUCCESS)
817 {
818 DPRINT("ERROR! Unable to get number of services keys.\n");
819 return dwError;
820 }
821
822 /* Iterate the service keys to see if another service depends on the this service */
823 for (dwIteration = 0; dwIteration < dwNumSubKeys; dwIteration++)
824 {
825 dwSize = MAX_PATH;
826 dwError = RegEnumKeyExW(hServicesKey,
827 dwIteration,
828 lpszNameBuf,
829 &dwSize,
830 NULL,
831 NULL,
832 NULL,
833 NULL);
834 if (dwError != ERROR_SUCCESS)
835 return dwError;
836
837 /* Open the Service key */
838 dwError = RegOpenKeyExW(hServicesKey,
839 lpszNameBuf,
840 0,
841 KEY_READ,
842 &hServiceEnumKey);
843 if (dwError != ERROR_SUCCESS)
844 return dwError;
845
846 dwSize = MAX_PATH * sizeof(WCHAR);
847
848 /* Check for the DependOnService Value */
849 dwError = RegQueryValueExW(hServiceEnumKey,
850 L"DependOnService",
851 NULL,
852 NULL,
853 (LPBYTE)lpszValueBuf,
854 &dwSize);
855
856 /* FIXME: Handle load order. */
857
858 /* If the service found has a DependOnService value */
859 if (dwError == ERROR_SUCCESS)
860 {
861 dwDependServiceStrPtr = 0;
862
863 /* Can be more than one Dependencies in the DependOnService string */
864 while (wcslen(lpszValueBuf + dwDependServiceStrPtr) > 0)
865 {
866 if (_wcsicmp(lpszValueBuf + dwDependServiceStrPtr, lpService->lpServiceName) == 0)
867 {
868 /* Get the current enumed service pointer */
869 lpCurrentService = ScmGetServiceEntryByName(lpszNameBuf);
870
871 /* Check for valid Service */
872 if (!lpCurrentService)
873 {
874 /* This should never happen! */
875 DPRINT("This should not happen at this point, report to Developer\n");
876 return ERROR_NOT_FOUND;
877 }
878
879 /* Determine state the service is in */
880 if (lpCurrentService->Status.dwCurrentState == SERVICE_STOPPED)
881 dwCurrentServiceState = SERVICE_INACTIVE;
882
883 /* If the ServiceState matches that requested or searching for SERVICE_STATE_ALL */
884 if ((dwCurrentServiceState == dwServiceState) ||
885 (dwServiceState == SERVICE_STATE_ALL))
886 {
887 /* Calculate the required size */
888 dwRequiredSize += sizeof(SERVICE_STATUS);
889 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpServiceName) + 1) * sizeof(WCHAR));
890 dwRequiredSize += (DWORD)((wcslen(lpCurrentService->lpDisplayName) + 1) * sizeof(WCHAR));
891
892 /* Add the size for service name and display name pointers */
893 dwRequiredSize += (2 * sizeof(PVOID));
894
895 /* increase the BytesNeeded size */
896 *pcbBytesNeeded = *pcbBytesNeeded + dwRequiredSize;
897
898 /* Don't fill callers buffer yet, as MSDN read that the last service with dependency
899 comes first */
900
901 /* Recursive call to check for its dependencies */
902 Int_EnumDependentServicesW(hServicesKey,
903 lpCurrentService,
904 dwServiceState,
905 lpServices,
906 pcbBytesNeeded,
907 lpServicesReturned);
908
909 /* If the lpServices is valid set the service pointer */
910 if (lpServices)
911 lpServices[*lpServicesReturned] = lpCurrentService;
912
913 *lpServicesReturned = *lpServicesReturned + 1;
914 }
915 }
916
917 dwDependServiceStrPtr += (DWORD)(wcslen(lpszValueBuf + dwDependServiceStrPtr) + 1);
918 }
919 }
920 else if (*pcbBytesNeeded)
921 {
922 dwError = ERROR_SUCCESS;
923 }
924
925 RegCloseKey(hServiceEnumKey);
926 }
927
928 return dwError;
929 }
930
931
932 /* Function 0 */
933 DWORD
934 WINAPI
935 RCloseServiceHandle(
936 LPSC_RPC_HANDLE hSCObject)
937 {
938 PMANAGER_HANDLE hManager;
939 PSERVICE_HANDLE hService;
940 PSERVICE lpService;
941 HKEY hServicesKey;
942 DWORD dwError;
943 DWORD pcbBytesNeeded = 0;
944 DWORD dwServicesReturned = 0;
945
946 DPRINT("RCloseServiceHandle() called\n");
947
948 DPRINT("hSCObject = %p\n", *hSCObject);
949
950 if (*hSCObject == 0)
951 return ERROR_INVALID_HANDLE;
952
953 hManager = ScmGetServiceManagerFromHandle(*hSCObject);
954 hService = ScmGetServiceFromHandle(*hSCObject);
955
956 if (hManager != NULL)
957 {
958 DPRINT("Found manager handle\n");
959
960 /* Make sure we don't access stale memory if someone tries to use this handle again. */
961 hManager->Handle.Tag = INVALID_TAG;
962
963 HeapFree(GetProcessHeap(), 0, hManager);
964 hManager = NULL;
965
966 *hSCObject = NULL;
967
968 DPRINT("RCloseServiceHandle() done\n");
969 return ERROR_SUCCESS;
970 }
971 else if (hService != NULL)
972 {
973 DPRINT("Found service handle\n");
974
975 /* Lock the service database exclusively */
976 ScmLockDatabaseExclusive();
977
978 /* Get the pointer to the service record */
979 lpService = hService->ServiceEntry;
980
981 /* Make sure we don't access stale memory if someone tries to use this handle again. */
982 hService->Handle.Tag = INVALID_TAG;
983
984 /* Free the handle */
985 HeapFree(GetProcessHeap(), 0, hService);
986 hService = NULL;
987
988 ASSERT(lpService->dwRefCount > 0);
989
990 lpService->dwRefCount--;
991 DPRINT("CloseServiceHandle - lpService->dwRefCount %u\n",
992 lpService->dwRefCount);
993
994 if (lpService->dwRefCount == 0)
995 {
996 /* If this service has been marked for deletion */
997 if (lpService->bDeleted &&
998 lpService->Status.dwCurrentState == SERVICE_STOPPED)
999 {
1000 /* Open the Services Reg key */
1001 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1002 L"System\\CurrentControlSet\\Services",
1003 0,
1004 KEY_SET_VALUE | KEY_READ,
1005 &hServicesKey);
1006 if (dwError != ERROR_SUCCESS)
1007 {
1008 DPRINT("Failed to open services key\n");
1009 ScmUnlockDatabase();
1010 return dwError;
1011 }
1012
1013 /* Call the internal function with NULL, just to get bytes we need */
1014 Int_EnumDependentServicesW(hServicesKey,
1015 lpService,
1016 SERVICE_ACTIVE,
1017 NULL,
1018 &pcbBytesNeeded,
1019 &dwServicesReturned);
1020
1021 /* if pcbBytesNeeded returned a value then there are services running that are dependent on this service */
1022 if (pcbBytesNeeded)
1023 {
1024 DPRINT("Deletion failed due to running dependencies.\n");
1025 RegCloseKey(hServicesKey);
1026 ScmUnlockDatabase();
1027 return ERROR_SUCCESS;
1028 }
1029
1030 /* There are no references and no running dependencies,
1031 it is now safe to delete the service */
1032
1033 /* Delete the Service Key */
1034 dwError = ScmDeleteRegKey(hServicesKey,
1035 lpService->lpServiceName);
1036
1037 RegCloseKey(hServicesKey);
1038
1039 if (dwError != ERROR_SUCCESS)
1040 {
1041 DPRINT("Failed to Delete the Service Registry key\n");
1042 ScmUnlockDatabase();
1043 return dwError;
1044 }
1045
1046 /* Delete the Service */
1047 ScmDeleteServiceRecord(lpService);
1048 }
1049 }
1050
1051 ScmUnlockDatabase();
1052
1053 *hSCObject = NULL;
1054
1055 DPRINT("RCloseServiceHandle() done\n");
1056 return ERROR_SUCCESS;
1057 }
1058
1059 DPRINT("Invalid handle tag (Tag %lx)\n", hManager->Handle.Tag);
1060
1061 return ERROR_INVALID_HANDLE;
1062 }
1063
1064
1065 /* Function 1 */
1066 DWORD
1067 WINAPI
1068 RControlService(
1069 SC_RPC_HANDLE hService,
1070 DWORD dwControl,
1071 LPSERVICE_STATUS lpServiceStatus)
1072 {
1073 PSERVICE_HANDLE hSvc;
1074 PSERVICE lpService;
1075 ACCESS_MASK DesiredAccess;
1076 DWORD dwError = ERROR_SUCCESS;
1077 DWORD pcbBytesNeeded = 0;
1078 DWORD dwServicesReturned = 0;
1079 DWORD dwControlsAccepted;
1080 DWORD dwCurrentState;
1081 HKEY hServicesKey = NULL;
1082 LPCWSTR lpLogStrings[2];
1083 WCHAR szLogBuffer[80];
1084 UINT uID;
1085
1086 DPRINT("RControlService() called\n");
1087
1088 if (ScmShutdown)
1089 return ERROR_SHUTDOWN_IN_PROGRESS;
1090
1091 /* Check the service handle */
1092 hSvc = ScmGetServiceFromHandle(hService);
1093 if (hSvc == NULL)
1094 {
1095 DPRINT1("Invalid service handle!\n");
1096 return ERROR_INVALID_HANDLE;
1097 }
1098
1099 /* Check the service entry point */
1100 lpService = hSvc->ServiceEntry;
1101 if (lpService == NULL)
1102 {
1103 DPRINT1("lpService == NULL!\n");
1104 return ERROR_INVALID_HANDLE;
1105 }
1106
1107 /* Check access rights */
1108 switch (dwControl)
1109 {
1110 case SERVICE_CONTROL_STOP:
1111 DesiredAccess = SERVICE_STOP;
1112 break;
1113
1114 case SERVICE_CONTROL_PAUSE:
1115 case SERVICE_CONTROL_CONTINUE:
1116 case SERVICE_CONTROL_PARAMCHANGE:
1117 case SERVICE_CONTROL_NETBINDADD:
1118 case SERVICE_CONTROL_NETBINDREMOVE:
1119 case SERVICE_CONTROL_NETBINDENABLE:
1120 case SERVICE_CONTROL_NETBINDDISABLE:
1121 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1122 break;
1123
1124 case SERVICE_CONTROL_INTERROGATE:
1125 DesiredAccess = SERVICE_INTERROGATE;
1126 break;
1127
1128 default:
1129 if (dwControl >= 128 && dwControl <= 255)
1130 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1131 else
1132 return ERROR_INVALID_PARAMETER;
1133 break;
1134 }
1135
1136 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1137 DesiredAccess))
1138 return ERROR_ACCESS_DENIED;
1139
1140 /* Return the current service status information */
1141 RtlCopyMemory(lpServiceStatus,
1142 &lpService->Status,
1143 sizeof(SERVICE_STATUS));
1144
1145 if (dwControl == SERVICE_CONTROL_STOP)
1146 {
1147 /* Check if the service has dependencies running as windows
1148 doesn't stop a service that does */
1149
1150 /* Open the Services Reg key */
1151 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1152 L"System\\CurrentControlSet\\Services",
1153 0,
1154 KEY_READ,
1155 &hServicesKey);
1156 if (dwError != ERROR_SUCCESS)
1157 {
1158 DPRINT("Failed to open services key\n");
1159 return dwError;
1160 }
1161
1162 /* Call the internal function with NULL, just to get bytes we need */
1163 Int_EnumDependentServicesW(hServicesKey,
1164 lpService,
1165 SERVICE_ACTIVE,
1166 NULL,
1167 &pcbBytesNeeded,
1168 &dwServicesReturned);
1169
1170 RegCloseKey(hServicesKey);
1171
1172 /* If pcbBytesNeeded is not zero then there are services running that
1173 are dependent on this service */
1174 if (pcbBytesNeeded != 0)
1175 {
1176 DPRINT("Service has running dependencies. Failed to stop service.\n");
1177 return ERROR_DEPENDENT_SERVICES_RUNNING;
1178 }
1179 }
1180
1181 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1182 {
1183 /* Send control code to the driver */
1184 dwError = ScmControlDriver(lpService,
1185 dwControl,
1186 lpServiceStatus);
1187 }
1188 else
1189 {
1190 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1191 dwCurrentState = lpService->Status.dwCurrentState;
1192
1193 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1194 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1195 return ERROR_SERVICE_NOT_ACTIVE;
1196
1197 /* Check the current state before sending a control request */
1198 switch (dwCurrentState)
1199 {
1200 case SERVICE_STOP_PENDING:
1201 case SERVICE_STOPPED:
1202 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1203
1204 case SERVICE_START_PENDING:
1205 switch (dwControl)
1206 {
1207 case SERVICE_CONTROL_STOP:
1208 break;
1209
1210 case SERVICE_CONTROL_INTERROGATE:
1211 RtlCopyMemory(lpServiceStatus,
1212 &lpService->Status,
1213 sizeof(SERVICE_STATUS));
1214 return ERROR_SUCCESS;
1215
1216 default:
1217 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1218 }
1219 break;
1220 }
1221
1222 /* Check if the control code is acceptable to the service */
1223 switch (dwControl)
1224 {
1225 case SERVICE_CONTROL_STOP:
1226 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1227 return ERROR_INVALID_SERVICE_CONTROL;
1228 break;
1229
1230 case SERVICE_CONTROL_PAUSE:
1231 case SERVICE_CONTROL_CONTINUE:
1232 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1233 return ERROR_INVALID_SERVICE_CONTROL;
1234 break;
1235
1236 case SERVICE_CONTROL_PARAMCHANGE:
1237 if ((dwControlsAccepted & SERVICE_ACCEPT_PARAMCHANGE) == 0)
1238 return ERROR_INVALID_SERVICE_CONTROL;
1239 break;
1240
1241 case SERVICE_CONTROL_NETBINDADD:
1242 case SERVICE_CONTROL_NETBINDREMOVE:
1243 case SERVICE_CONTROL_NETBINDENABLE:
1244 case SERVICE_CONTROL_NETBINDDISABLE:
1245 if ((dwControlsAccepted & SERVICE_ACCEPT_NETBINDCHANGE) == 0)
1246 return ERROR_INVALID_SERVICE_CONTROL;
1247 break;
1248 }
1249
1250 /* Send control code to the service */
1251 dwError = ScmControlService(lpService->lpImage->hControlPipe,
1252 lpService->lpServiceName,
1253 (SERVICE_STATUS_HANDLE)lpService,
1254 dwControl);
1255
1256 /* Return service status information */
1257 RtlCopyMemory(lpServiceStatus,
1258 &lpService->Status,
1259 sizeof(SERVICE_STATUS));
1260 }
1261
1262 if (dwError == ERROR_SUCCESS)
1263 {
1264 if (dwControl == SERVICE_CONTROL_STOP ||
1265 dwControl == SERVICE_CONTROL_PAUSE ||
1266 dwControl == SERVICE_CONTROL_CONTINUE)
1267 {
1268 /* Log a successful send control */
1269
1270 switch (dwControl)
1271 {
1272 case SERVICE_CONTROL_STOP:
1273 uID = IDS_SERVICE_STOP;
1274 break;
1275
1276 case SERVICE_CONTROL_PAUSE:
1277 uID = IDS_SERVICE_PAUSE;
1278 break;
1279
1280 case SERVICE_CONTROL_CONTINUE:
1281 uID = IDS_SERVICE_RESUME;
1282 break;
1283 }
1284 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1285
1286 lpLogStrings[0] = lpService->lpDisplayName;
1287 lpLogStrings[1] = szLogBuffer;
1288
1289 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1290 EVENTLOG_INFORMATION_TYPE,
1291 2,
1292 lpLogStrings);
1293 }
1294 }
1295
1296 return dwError;
1297 }
1298
1299
1300 /* Function 2 */
1301 DWORD
1302 WINAPI
1303 RDeleteService(
1304 SC_RPC_HANDLE hService)
1305 {
1306 PSERVICE_HANDLE hSvc;
1307 PSERVICE lpService;
1308 DWORD dwError;
1309
1310 DPRINT("RDeleteService() called\n");
1311
1312 if (ScmShutdown)
1313 return ERROR_SHUTDOWN_IN_PROGRESS;
1314
1315 hSvc = ScmGetServiceFromHandle(hService);
1316 if (hSvc == NULL)
1317 {
1318 DPRINT1("Invalid service handle!\n");
1319 return ERROR_INVALID_HANDLE;
1320 }
1321
1322 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1323 DELETE))
1324 return ERROR_ACCESS_DENIED;
1325
1326 lpService = hSvc->ServiceEntry;
1327 if (lpService == NULL)
1328 {
1329 DPRINT("lpService == NULL!\n");
1330 return ERROR_INVALID_HANDLE;
1331 }
1332
1333 /* Lock the service database exclusively */
1334 ScmLockDatabaseExclusive();
1335
1336 if (lpService->bDeleted)
1337 {
1338 DPRINT("The service has already been marked for delete!\n");
1339 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1340 goto Done;
1341 }
1342
1343 /* Mark service for delete */
1344 lpService->bDeleted = TRUE;
1345
1346 dwError = ScmMarkServiceForDelete(lpService);
1347
1348 Done:
1349 /* Unlock the service database */
1350 ScmUnlockDatabase();
1351
1352 DPRINT("RDeleteService() done\n");
1353
1354 return dwError;
1355 }
1356
1357
1358 /* Function 3 */
1359 DWORD
1360 WINAPI
1361 RLockServiceDatabase(
1362 SC_RPC_HANDLE hSCManager,
1363 LPSC_RPC_LOCK lpLock)
1364 {
1365 PMANAGER_HANDLE hMgr;
1366
1367 DPRINT("RLockServiceDatabase() called\n");
1368
1369 *lpLock = NULL;
1370
1371 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1372 if (hMgr == NULL)
1373 {
1374 DPRINT1("Invalid service manager handle!\n");
1375 return ERROR_INVALID_HANDLE;
1376 }
1377
1378 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1379 SC_MANAGER_LOCK))
1380 return ERROR_ACCESS_DENIED;
1381
1382 return ScmAcquireServiceStartLock(FALSE, lpLock);
1383 }
1384
1385
1386 /* Function 4 */
1387 DWORD
1388 WINAPI
1389 RQueryServiceObjectSecurity(
1390 SC_RPC_HANDLE hService,
1391 SECURITY_INFORMATION dwSecurityInformation,
1392 LPBYTE lpSecurityDescriptor,
1393 DWORD cbBufSize,
1394 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1395 {
1396 PSERVICE_HANDLE hSvc;
1397 PSERVICE lpService;
1398 ULONG DesiredAccess = 0;
1399 NTSTATUS Status;
1400 DWORD dwBytesNeeded;
1401 DWORD dwError;
1402
1403 DPRINT("RQueryServiceObjectSecurity() called\n");
1404
1405 hSvc = ScmGetServiceFromHandle(hService);
1406 if (hSvc == NULL)
1407 {
1408 DPRINT1("Invalid service handle!\n");
1409 return ERROR_INVALID_HANDLE;
1410 }
1411
1412 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1413 GROUP_SECURITY_INFORMATION |
1414 OWNER_SECURITY_INFORMATION))
1415 DesiredAccess |= READ_CONTROL;
1416
1417 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1418 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1419
1420 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1421 DesiredAccess))
1422 {
1423 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1424 return ERROR_ACCESS_DENIED;
1425 }
1426
1427 lpService = hSvc->ServiceEntry;
1428 if (lpService == NULL)
1429 {
1430 DPRINT("lpService == NULL!\n");
1431 return ERROR_INVALID_HANDLE;
1432 }
1433
1434 /* Lock the service database */
1435 ScmLockDatabaseShared();
1436
1437 /* Retrieve the security descriptor */
1438 Status = RtlQuerySecurityObject(lpService->pSecurityDescriptor,
1439 dwSecurityInformation,
1440 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1441 cbBufSize,
1442 &dwBytesNeeded);
1443
1444 /* Unlock the service database */
1445 ScmUnlockDatabase();
1446
1447 if (NT_SUCCESS(Status))
1448 {
1449 *pcbBytesNeeded = dwBytesNeeded;
1450 dwError = STATUS_SUCCESS;
1451 }
1452 else if (Status == STATUS_BUFFER_TOO_SMALL)
1453 {
1454 *pcbBytesNeeded = dwBytesNeeded;
1455 dwError = ERROR_INSUFFICIENT_BUFFER;
1456 }
1457 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1458 {
1459 dwError = ERROR_GEN_FAILURE;
1460 }
1461 else
1462 {
1463 dwError = RtlNtStatusToDosError(Status);
1464 }
1465
1466 return dwError;
1467 }
1468
1469
1470 /* Function 5 */
1471 DWORD
1472 WINAPI
1473 RSetServiceObjectSecurity(
1474 SC_RPC_HANDLE hService,
1475 DWORD dwSecurityInformation,
1476 LPBYTE lpSecurityDescriptor,
1477 DWORD dwSecurityDescriptorSize)
1478 {
1479 PSERVICE_HANDLE hSvc;
1480 PSERVICE lpService;
1481 ACCESS_MASK DesiredAccess = 0;
1482 HANDLE hToken = NULL;
1483 HKEY hServiceKey = NULL;
1484 BOOL bDatabaseLocked = FALSE;
1485 NTSTATUS Status;
1486 DWORD dwError;
1487
1488 DPRINT("RSetServiceObjectSecurity() called\n");
1489
1490 hSvc = ScmGetServiceFromHandle(hService);
1491 if (hSvc == NULL)
1492 {
1493 DPRINT1("Invalid service handle!\n");
1494 return ERROR_INVALID_HANDLE;
1495 }
1496
1497 if (dwSecurityInformation == 0 ||
1498 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1499 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1500 return ERROR_INVALID_PARAMETER;
1501
1502 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1503 return ERROR_INVALID_PARAMETER;
1504
1505 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1506 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1507
1508 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1509 DesiredAccess |= WRITE_DAC;
1510
1511 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1512 DesiredAccess |= WRITE_OWNER;
1513
1514 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1515 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1516 return ERROR_INVALID_PARAMETER;
1517
1518 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1519 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1520 return ERROR_INVALID_PARAMETER;
1521
1522 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1523 DesiredAccess))
1524 {
1525 DPRINT1("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1526 return ERROR_ACCESS_DENIED;
1527 }
1528
1529 lpService = hSvc->ServiceEntry;
1530 if (lpService == NULL)
1531 {
1532 DPRINT1("lpService == NULL!\n");
1533 return ERROR_INVALID_HANDLE;
1534 }
1535
1536 if (lpService->bDeleted)
1537 return ERROR_SERVICE_MARKED_FOR_DELETE;
1538
1539 #if 0
1540 RpcImpersonateClient(NULL);
1541
1542 Status = NtOpenThreadToken(NtCurrentThread(),
1543 8,
1544 TRUE,
1545 &hToken);
1546 if (!NT_SUCCESS(Status))
1547 return RtlNtStatusToDosError(Status);
1548
1549 RpcRevertToSelf();
1550 #endif
1551
1552 /* Build the new security descriptor */
1553 Status = RtlSetSecurityObject(dwSecurityInformation,
1554 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1555 &lpService->pSecurityDescriptor,
1556 &ScmServiceMapping,
1557 hToken);
1558 if (!NT_SUCCESS(Status))
1559 {
1560 dwError = RtlNtStatusToDosError(Status);
1561 goto Done;
1562 }
1563
1564 /* Lock the service database exclusive */
1565 ScmLockDatabaseExclusive();
1566 bDatabaseLocked = TRUE;
1567
1568 /* Open the service key */
1569 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1570 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1571 &hServiceKey);
1572 if (dwError != ERROR_SUCCESS)
1573 goto Done;
1574
1575 /* Store the new security descriptor */
1576 dwError = ScmWriteSecurityDescriptor(hServiceKey,
1577 lpService->pSecurityDescriptor);
1578
1579 RegFlushKey(hServiceKey);
1580
1581 Done:
1582 if (hServiceKey != NULL)
1583 RegCloseKey(hServiceKey);
1584
1585 /* Unlock service database */
1586 if (bDatabaseLocked == TRUE)
1587 ScmUnlockDatabase();
1588
1589 if (hToken != NULL)
1590 NtClose(hToken);
1591
1592 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1593
1594 return dwError;
1595 }
1596
1597
1598 /* Function 6 */
1599 DWORD
1600 WINAPI
1601 RQueryServiceStatus(
1602 SC_RPC_HANDLE hService,
1603 LPSERVICE_STATUS lpServiceStatus)
1604 {
1605 PSERVICE_HANDLE hSvc;
1606 PSERVICE lpService;
1607
1608 DPRINT("RQueryServiceStatus() called\n");
1609
1610 if (ScmShutdown)
1611 return ERROR_SHUTDOWN_IN_PROGRESS;
1612
1613 hSvc = ScmGetServiceFromHandle(hService);
1614 if (hSvc == NULL)
1615 {
1616 DPRINT1("Invalid service handle!\n");
1617 return ERROR_INVALID_HANDLE;
1618 }
1619
1620 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1621 SERVICE_QUERY_STATUS))
1622 {
1623 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1624 return ERROR_ACCESS_DENIED;
1625 }
1626
1627 lpService = hSvc->ServiceEntry;
1628 if (lpService == NULL)
1629 {
1630 DPRINT("lpService == NULL!\n");
1631 return ERROR_INVALID_HANDLE;
1632 }
1633
1634 /* Lock the service database shared */
1635 ScmLockDatabaseShared();
1636
1637 /* Return service status information */
1638 RtlCopyMemory(lpServiceStatus,
1639 &lpService->Status,
1640 sizeof(SERVICE_STATUS));
1641
1642 /* Unlock the service database */
1643 ScmUnlockDatabase();
1644
1645 return ERROR_SUCCESS;
1646 }
1647
1648
1649 static BOOL
1650 ScmIsValidServiceState(DWORD dwCurrentState)
1651 {
1652 switch (dwCurrentState)
1653 {
1654 case SERVICE_STOPPED:
1655 case SERVICE_START_PENDING:
1656 case SERVICE_STOP_PENDING:
1657 case SERVICE_RUNNING:
1658 case SERVICE_CONTINUE_PENDING:
1659 case SERVICE_PAUSE_PENDING:
1660 case SERVICE_PAUSED:
1661 return TRUE;
1662
1663 default:
1664 return FALSE;
1665 }
1666 }
1667
1668
1669 /* Function 7 */
1670 DWORD
1671 WINAPI
1672 RSetServiceStatus(
1673 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1674 LPSERVICE_STATUS lpServiceStatus)
1675 {
1676 PSERVICE lpService;
1677 DWORD dwPreviousState;
1678 DWORD dwPreviousType;
1679 LPCWSTR lpLogStrings[2];
1680 WCHAR szLogBuffer[80];
1681 UINT uID;
1682
1683 DPRINT("RSetServiceStatus() called\n");
1684 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1685 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1686 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1687 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1688 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1689 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1690 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1691 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1692
1693 if (hServiceStatus == 0)
1694 {
1695 DPRINT("hServiceStatus == NULL!\n");
1696 return ERROR_INVALID_HANDLE;
1697 }
1698
1699 lpService = (PSERVICE)hServiceStatus;
1700
1701 /* Check current state */
1702 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1703 {
1704 DPRINT("Invalid service state!\n");
1705 return ERROR_INVALID_DATA;
1706 }
1707
1708 /* Check service type */
1709 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1710 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1711 {
1712 DPRINT("Invalid service type!\n");
1713 return ERROR_INVALID_DATA;
1714 }
1715
1716 /* Check accepted controls */
1717 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1718 {
1719 DPRINT("Invalid controls accepted!\n");
1720 return ERROR_INVALID_DATA;
1721 }
1722
1723 /* Set the wait hint and check point only if the service is in a pending state,
1724 otherwise they should be 0 */
1725 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1726 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1727 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1728 {
1729 lpServiceStatus->dwWaitHint = 0;
1730 lpServiceStatus->dwCheckPoint = 0;
1731 }
1732
1733 /* Lock the service database exclusively */
1734 ScmLockDatabaseExclusive();
1735
1736 /* Save the current service state */
1737 dwPreviousState = lpService->Status.dwCurrentState;
1738
1739 /* Save the current service type */
1740 dwPreviousType = lpService->Status.dwServiceType;
1741
1742 /* Update the service status */
1743 RtlCopyMemory(&lpService->Status,
1744 lpServiceStatus,
1745 sizeof(SERVICE_STATUS));
1746
1747 /* Restore the previous service type */
1748 lpService->Status.dwServiceType = dwPreviousType;
1749
1750 /* Dereference a stopped service */
1751 if ((lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1752 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED))
1753 {
1754 /* Decrement the image run counter */
1755 lpService->lpImage->dwImageRunCount--;
1756
1757 /* If we just stopped the last running service... */
1758 if (lpService->lpImage->dwImageRunCount == 0)
1759 {
1760 /* Stop the dispatcher thread */
1761 ScmControlService(lpService->lpImage->hControlPipe,
1762 L"",
1763 (SERVICE_STATUS_HANDLE)lpService,
1764 SERVICE_CONTROL_STOP);
1765
1766 /* Remove the service image */
1767 ScmRemoveServiceImage(lpService->lpImage);
1768 lpService->lpImage = NULL;
1769 }
1770 }
1771
1772 /* Unlock the service database */
1773 ScmUnlockDatabase();
1774
1775 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1776 (dwPreviousState != SERVICE_STOPPED) &&
1777 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1778 {
1779 /* Log a failed service stop */
1780 StringCchPrintfW(szLogBuffer, ARRAYSIZE(szLogBuffer),
1781 L"%lu", lpServiceStatus->dwWin32ExitCode);
1782 lpLogStrings[0] = lpService->lpDisplayName;
1783 lpLogStrings[1] = szLogBuffer;
1784
1785 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1786 EVENTLOG_ERROR_TYPE,
1787 2,
1788 lpLogStrings);
1789 }
1790 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1791 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1792 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1793 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1794 {
1795 /* Log a successful service status change */
1796 switch(lpServiceStatus->dwCurrentState)
1797 {
1798 case SERVICE_STOPPED:
1799 uID = IDS_SERVICE_STOPPED;
1800 break;
1801
1802 case SERVICE_RUNNING:
1803 uID = IDS_SERVICE_RUNNING;
1804 break;
1805
1806 case SERVICE_PAUSED:
1807 uID = IDS_SERVICE_PAUSED;
1808 break;
1809 }
1810
1811 LoadStringW(GetModuleHandle(NULL), uID, szLogBuffer, ARRAYSIZE(szLogBuffer));
1812 lpLogStrings[0] = lpService->lpDisplayName;
1813 lpLogStrings[1] = szLogBuffer;
1814
1815 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1816 EVENTLOG_INFORMATION_TYPE,
1817 2,
1818 lpLogStrings);
1819 }
1820
1821 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1822 DPRINT("RSetServiceStatus() done\n");
1823
1824 return ERROR_SUCCESS;
1825 }
1826
1827
1828 /* Function 8 */
1829 DWORD
1830 WINAPI
1831 RUnlockServiceDatabase(
1832 LPSC_RPC_LOCK Lock)
1833 {
1834 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1835 return ScmReleaseServiceStartLock(Lock);
1836 }
1837
1838
1839 /* Function 9 */
1840 DWORD
1841 WINAPI
1842 RNotifyBootConfigStatus(
1843 SVCCTL_HANDLEW lpMachineName,
1844 DWORD BootAcceptable)
1845 {
1846 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1847 return ERROR_SUCCESS;
1848
1849 // UNIMPLEMENTED;
1850 // return ERROR_CALL_NOT_IMPLEMENTED;
1851 }
1852
1853
1854 /* Function 10 */
1855 DWORD
1856 WINAPI
1857 RI_ScSetServiceBitsW(
1858 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1859 DWORD dwServiceBits,
1860 int bSetBitsOn,
1861 int bUpdateImmediately,
1862 wchar_t *lpString)
1863 {
1864 PSERVICE pService;
1865
1866 DPRINT("RI_ScSetServiceBitsW(%p %lx %d %d %S)\n",
1867 hServiceStatus, dwServiceBits, bSetBitsOn,
1868 bUpdateImmediately, lpString);
1869
1870 if (ScmShutdown)
1871 return ERROR_SHUTDOWN_IN_PROGRESS;
1872
1873 if (lpString != NULL)
1874 return ERROR_INVALID_PARAMETER;
1875
1876 if (hServiceStatus == 0)
1877 {
1878 DPRINT("hServiceStatus == NULL!\n");
1879 return ERROR_INVALID_HANDLE;
1880 }
1881
1882 // FIXME: Validate the status handle
1883 pService = (PSERVICE)hServiceStatus;
1884
1885 if (bSetBitsOn)
1886 {
1887 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1888 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1889 pService->dwServiceBits |= dwServiceBits;
1890 g_dwServiceBits |= dwServiceBits;
1891 DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1892 DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1893 }
1894 else
1895 {
1896 DPRINT("Old service bits: %08lx\n", pService->dwServiceBits);
1897 DPRINT("Old global service bits: %08lx\n", g_dwServiceBits);
1898 pService->dwServiceBits &= ~dwServiceBits;
1899 g_dwServiceBits &= ~dwServiceBits;
1900 DPRINT("New service bits: %08lx\n", pService->dwServiceBits);
1901 DPRINT("New global service bits: %08lx\n", g_dwServiceBits);
1902 }
1903
1904 return ERROR_SUCCESS;
1905 }
1906
1907
1908 /* Function 11 */
1909 DWORD
1910 WINAPI
1911 RChangeServiceConfigW(
1912 SC_RPC_HANDLE hService,
1913 DWORD dwServiceType,
1914 DWORD dwStartType,
1915 DWORD dwErrorControl,
1916 LPWSTR lpBinaryPathName,
1917 LPWSTR lpLoadOrderGroup,
1918 LPDWORD lpdwTagId,
1919 LPBYTE lpDependencies,
1920 DWORD dwDependSize,
1921 LPWSTR lpServiceStartName,
1922 LPBYTE lpPassword,
1923 DWORD dwPwSize,
1924 LPWSTR lpDisplayName)
1925 {
1926 DWORD dwError = ERROR_SUCCESS;
1927 PSERVICE_HANDLE hSvc;
1928 PSERVICE lpService = NULL;
1929 HKEY hServiceKey = NULL;
1930 LPWSTR lpDisplayNameW = NULL;
1931 LPWSTR lpImagePathW = NULL;
1932
1933 DPRINT("RChangeServiceConfigW() called\n");
1934 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1935 DPRINT("dwStartType = %lu\n", dwStartType);
1936 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1937 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1938 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1939 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1940
1941 if (ScmShutdown)
1942 return ERROR_SHUTDOWN_IN_PROGRESS;
1943
1944 hSvc = ScmGetServiceFromHandle(hService);
1945 if (hSvc == NULL)
1946 {
1947 DPRINT1("Invalid service handle!\n");
1948 return ERROR_INVALID_HANDLE;
1949 }
1950
1951 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1952 SERVICE_CHANGE_CONFIG))
1953 {
1954 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1955 return ERROR_ACCESS_DENIED;
1956 }
1957
1958 /* Check for invalid service type value */
1959 if ((dwServiceType != SERVICE_NO_CHANGE) &&
1960 (dwServiceType != SERVICE_KERNEL_DRIVER) &&
1961 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
1962 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
1963 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
1964 return ERROR_INVALID_PARAMETER;
1965
1966 /* Check for invalid start type value */
1967 if ((dwStartType != SERVICE_NO_CHANGE) &&
1968 (dwStartType != SERVICE_BOOT_START) &&
1969 (dwStartType != SERVICE_SYSTEM_START) &&
1970 (dwStartType != SERVICE_AUTO_START) &&
1971 (dwStartType != SERVICE_DEMAND_START) &&
1972 (dwStartType != SERVICE_DISABLED))
1973 return ERROR_INVALID_PARAMETER;
1974
1975 /* Only drivers can be boot start or system start services */
1976 if ((dwStartType == SERVICE_BOOT_START) ||
1977 (dwStartType == SERVICE_SYSTEM_START))
1978 {
1979 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
1980 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
1981 return ERROR_INVALID_PARAMETER;
1982 }
1983
1984 /* Check for invalid error control value */
1985 if ((dwErrorControl != SERVICE_NO_CHANGE) &&
1986 (dwErrorControl != SERVICE_ERROR_IGNORE) &&
1987 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
1988 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
1989 (dwErrorControl != SERVICE_ERROR_CRITICAL))
1990 return ERROR_INVALID_PARAMETER;
1991
1992 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
1993 {
1994 return ERROR_INVALID_PARAMETER;
1995 }
1996
1997 lpService = hSvc->ServiceEntry;
1998 if (lpService == NULL)
1999 {
2000 DPRINT("lpService == NULL!\n");
2001 return ERROR_INVALID_HANDLE;
2002 }
2003
2004 /* Lock the service database exclusively */
2005 ScmLockDatabaseExclusive();
2006
2007 if (lpService->bDeleted)
2008 {
2009 DPRINT("The service has already been marked for delete!\n");
2010 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
2011 goto done;
2012 }
2013
2014 /* Open the service key */
2015 dwError = ScmOpenServiceKey(lpService->szServiceName,
2016 KEY_SET_VALUE,
2017 &hServiceKey);
2018 if (dwError != ERROR_SUCCESS)
2019 goto done;
2020
2021 /* Write service data to the registry */
2022
2023 /* Set the display name */
2024 if (lpDisplayName != NULL && *lpDisplayName != 0)
2025 {
2026 RegSetValueExW(hServiceKey,
2027 L"DisplayName",
2028 0,
2029 REG_SZ,
2030 (LPBYTE)lpDisplayName,
2031 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2032
2033 /* Update the display name */
2034 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
2035 HEAP_ZERO_MEMORY,
2036 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2037 if (lpDisplayNameW == NULL)
2038 {
2039 dwError = ERROR_NOT_ENOUGH_MEMORY;
2040 goto done;
2041 }
2042
2043 wcscpy(lpDisplayNameW, lpDisplayName);
2044 if (lpService->lpDisplayName != lpService->lpServiceName)
2045 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2046
2047 lpService->lpDisplayName = lpDisplayNameW;
2048 }
2049
2050 if (dwServiceType != SERVICE_NO_CHANGE)
2051 {
2052 /* Set the service type */
2053 dwError = RegSetValueExW(hServiceKey,
2054 L"Type",
2055 0,
2056 REG_DWORD,
2057 (LPBYTE)&dwServiceType,
2058 sizeof(DWORD));
2059 if (dwError != ERROR_SUCCESS)
2060 goto done;
2061
2062 lpService->Status.dwServiceType = dwServiceType;
2063 }
2064
2065 if (dwStartType != SERVICE_NO_CHANGE)
2066 {
2067 /* Set the start value */
2068 dwError = RegSetValueExW(hServiceKey,
2069 L"Start",
2070 0,
2071 REG_DWORD,
2072 (LPBYTE)&dwStartType,
2073 sizeof(DWORD));
2074 if (dwError != ERROR_SUCCESS)
2075 goto done;
2076
2077 lpService->dwStartType = dwStartType;
2078 }
2079
2080 if (dwErrorControl != SERVICE_NO_CHANGE)
2081 {
2082 /* Set the error control value */
2083 dwError = RegSetValueExW(hServiceKey,
2084 L"ErrorControl",
2085 0,
2086 REG_DWORD,
2087 (LPBYTE)&dwErrorControl,
2088 sizeof(DWORD));
2089 if (dwError != ERROR_SUCCESS)
2090 goto done;
2091
2092 lpService->dwErrorControl = dwErrorControl;
2093 }
2094
2095 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
2096 {
2097 /* Set the image path */
2098 lpImagePathW = lpBinaryPathName;
2099
2100 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
2101 {
2102 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
2103 lpBinaryPathName,
2104 &lpImagePathW);
2105
2106 if (dwError != ERROR_SUCCESS)
2107 goto done;
2108 }
2109
2110 dwError = RegSetValueExW(hServiceKey,
2111 L"ImagePath",
2112 0,
2113 REG_EXPAND_SZ,
2114 (LPBYTE)lpImagePathW,
2115 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
2116
2117 if (lpImagePathW != lpBinaryPathName)
2118 HeapFree(GetProcessHeap(), 0, lpImagePathW);
2119
2120 if (dwError != ERROR_SUCCESS)
2121 goto done;
2122 }
2123
2124 /* Set the group name */
2125 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2126 {
2127 dwError = RegSetValueExW(hServiceKey,
2128 L"Group",
2129 0,
2130 REG_SZ,
2131 (LPBYTE)lpLoadOrderGroup,
2132 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2133 if (dwError != ERROR_SUCCESS)
2134 goto done;
2135
2136 dwError = ScmSetServiceGroup(lpService,
2137 lpLoadOrderGroup);
2138 if (dwError != ERROR_SUCCESS)
2139 goto done;
2140 }
2141
2142 /* Set the tag */
2143 if (lpdwTagId != NULL)
2144 {
2145 dwError = ScmAssignNewTag(lpService);
2146 if (dwError != ERROR_SUCCESS)
2147 goto done;
2148
2149 dwError = RegSetValueExW(hServiceKey,
2150 L"Tag",
2151 0,
2152 REG_DWORD,
2153 (LPBYTE)&lpService->dwTag,
2154 sizeof(DWORD));
2155 if (dwError != ERROR_SUCCESS)
2156 goto done;
2157
2158 *lpdwTagId = lpService->dwTag;
2159 }
2160
2161 /* Write dependencies */
2162 if (lpDependencies != NULL && *lpDependencies != 0)
2163 {
2164 dwError = ScmWriteDependencies(hServiceKey,
2165 (LPWSTR)lpDependencies,
2166 dwDependSize);
2167 if (dwError != ERROR_SUCCESS)
2168 goto done;
2169 }
2170
2171 if (lpPassword != NULL)
2172 {
2173 if (wcslen((LPWSTR)lpPassword) != 0)
2174 {
2175 /* FIXME: Decrypt the password */
2176
2177 /* Write the password */
2178 dwError = ScmSetServicePassword(lpService->szServiceName,
2179 (LPCWSTR)lpPassword);
2180 if (dwError != ERROR_SUCCESS)
2181 goto done;
2182 }
2183 else
2184 {
2185 /* Delete the password */
2186 dwError = ScmSetServicePassword(lpService->szServiceName,
2187 NULL);
2188 if (dwError == ERROR_FILE_NOT_FOUND)
2189 dwError = ERROR_SUCCESS;
2190
2191 if (dwError != ERROR_SUCCESS)
2192 goto done;
2193 }
2194 }
2195
2196 done:
2197 if (hServiceKey != NULL)
2198 RegCloseKey(hServiceKey);
2199
2200 /* Unlock the service database */
2201 ScmUnlockDatabase();
2202
2203 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2204
2205 return dwError;
2206 }
2207
2208
2209 /* Function 12 */
2210 DWORD
2211 WINAPI
2212 RCreateServiceW(
2213 SC_RPC_HANDLE hSCManager,
2214 LPCWSTR lpServiceName,
2215 LPCWSTR lpDisplayName,
2216 DWORD dwDesiredAccess,
2217 DWORD dwServiceType,
2218 DWORD dwStartType,
2219 DWORD dwErrorControl,
2220 LPCWSTR lpBinaryPathName,
2221 LPCWSTR lpLoadOrderGroup,
2222 LPDWORD lpdwTagId,
2223 LPBYTE lpDependencies,
2224 DWORD dwDependSize,
2225 LPCWSTR lpServiceStartName,
2226 LPBYTE lpPassword,
2227 DWORD dwPwSize,
2228 LPSC_RPC_HANDLE lpServiceHandle)
2229 {
2230 PMANAGER_HANDLE hManager;
2231 DWORD dwError = ERROR_SUCCESS;
2232 PSERVICE lpService = NULL;
2233 SC_HANDLE hServiceHandle = NULL;
2234 LPWSTR lpImagePath = NULL;
2235 HKEY hServiceKey = NULL;
2236 LPWSTR lpObjectName;
2237
2238 DPRINT("RCreateServiceW() called\n");
2239 DPRINT("lpServiceName = %S\n", lpServiceName);
2240 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2241 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2242 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2243 DPRINT("dwStartType = %lu\n", dwStartType);
2244 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2245 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2246 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2247 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2248
2249 if (ScmShutdown)
2250 return ERROR_SHUTDOWN_IN_PROGRESS;
2251
2252 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2253 if (hManager == NULL)
2254 {
2255 DPRINT1("Invalid service manager handle!\n");
2256 return ERROR_INVALID_HANDLE;
2257 }
2258
2259 /* Check access rights */
2260 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2261 SC_MANAGER_CREATE_SERVICE))
2262 {
2263 DPRINT("Insufficient access rights! 0x%lx\n",
2264 hManager->Handle.DesiredAccess);
2265 return ERROR_ACCESS_DENIED;
2266 }
2267
2268 if (wcslen(lpServiceName) == 0)
2269 {
2270 return ERROR_INVALID_NAME;
2271 }
2272
2273 if (wcslen(lpBinaryPathName) == 0)
2274 {
2275 return ERROR_INVALID_PARAMETER;
2276 }
2277
2278 /* Check for invalid service type value */
2279 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2280 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2281 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2282 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2283 return ERROR_INVALID_PARAMETER;
2284
2285 /* Check for invalid start type value */
2286 if ((dwStartType != SERVICE_BOOT_START) &&
2287 (dwStartType != SERVICE_SYSTEM_START) &&
2288 (dwStartType != SERVICE_AUTO_START) &&
2289 (dwStartType != SERVICE_DEMAND_START) &&
2290 (dwStartType != SERVICE_DISABLED))
2291 return ERROR_INVALID_PARAMETER;
2292
2293 /* Only drivers can be boot start or system start services */
2294 if ((dwStartType == SERVICE_BOOT_START) ||
2295 (dwStartType == SERVICE_SYSTEM_START))
2296 {
2297 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2298 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2299 return ERROR_INVALID_PARAMETER;
2300 }
2301
2302 /* Check for invalid error control value */
2303 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2304 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2305 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2306 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2307 return ERROR_INVALID_PARAMETER;
2308
2309 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2310 (lpServiceStartName))
2311 {
2312 /* We allow LocalSystem to run interactive. */
2313 if (wcsicmp(lpServiceStartName, L"LocalSystem"))
2314 {
2315 return ERROR_INVALID_PARAMETER;
2316 }
2317 }
2318
2319 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2320 {
2321 return ERROR_INVALID_PARAMETER;
2322 }
2323
2324 /* Lock the service database exclusively */
2325 ScmLockDatabaseExclusive();
2326
2327 lpService = ScmGetServiceEntryByName(lpServiceName);
2328 if (lpService)
2329 {
2330 /* Unlock the service database */
2331 ScmUnlockDatabase();
2332
2333 /* Check if it is marked for deletion */
2334 if (lpService->bDeleted)
2335 return ERROR_SERVICE_MARKED_FOR_DELETE;
2336
2337 /* Return Error exist */
2338 return ERROR_SERVICE_EXISTS;
2339 }
2340
2341 if (lpDisplayName != NULL &&
2342 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2343 {
2344 /* Unlock the service database */
2345 ScmUnlockDatabase();
2346
2347 return ERROR_DUPLICATE_SERVICE_NAME;
2348 }
2349
2350 if (dwServiceType & SERVICE_DRIVER)
2351 {
2352 dwError = ScmCanonDriverImagePath(dwStartType,
2353 lpBinaryPathName,
2354 &lpImagePath);
2355 if (dwError != ERROR_SUCCESS)
2356 goto done;
2357 }
2358 else
2359 {
2360 if (dwStartType == SERVICE_BOOT_START ||
2361 dwStartType == SERVICE_SYSTEM_START)
2362 {
2363 /* Unlock the service database */
2364 ScmUnlockDatabase();
2365
2366 return ERROR_INVALID_PARAMETER;
2367 }
2368 }
2369
2370 /* Allocate a new service entry */
2371 dwError = ScmCreateNewServiceRecord(lpServiceName,
2372 &lpService,
2373 dwServiceType,
2374 dwStartType);
2375 if (dwError != ERROR_SUCCESS)
2376 goto done;
2377
2378 /* Fill the new service entry */
2379 lpService->dwErrorControl = dwErrorControl;
2380
2381 /* Fill the display name */
2382 if (lpDisplayName != NULL &&
2383 *lpDisplayName != 0 &&
2384 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2385 {
2386 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2387 HEAP_ZERO_MEMORY,
2388 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2389 if (lpService->lpDisplayName == NULL)
2390 {
2391 dwError = ERROR_NOT_ENOUGH_MEMORY;
2392 goto done;
2393 }
2394 wcscpy(lpService->lpDisplayName, lpDisplayName);
2395 }
2396
2397 /* Assign the service to a group */
2398 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2399 {
2400 dwError = ScmSetServiceGroup(lpService,
2401 lpLoadOrderGroup);
2402 if (dwError != ERROR_SUCCESS)
2403 goto done;
2404 }
2405
2406 /* Assign a new tag */
2407 if (lpdwTagId != NULL)
2408 {
2409 dwError = ScmAssignNewTag(lpService);
2410 if (dwError != ERROR_SUCCESS)
2411 goto done;
2412 }
2413
2414 /* Assign the default security descriptor */
2415 if (dwServiceType & SERVICE_WIN32)
2416 {
2417 dwError = ScmCreateDefaultServiceSD(&lpService->pSecurityDescriptor);
2418 if (dwError != ERROR_SUCCESS)
2419 goto done;
2420 }
2421
2422 /* Write service data to the registry */
2423 /* Create the service key */
2424 dwError = ScmCreateServiceKey(lpServiceName,
2425 KEY_WRITE,
2426 &hServiceKey);
2427 if (dwError != ERROR_SUCCESS)
2428 goto done;
2429
2430 /* Set the display name */
2431 if (lpDisplayName != NULL && *lpDisplayName != 0)
2432 {
2433 RegSetValueExW(hServiceKey,
2434 L"DisplayName",
2435 0,
2436 REG_SZ,
2437 (LPBYTE)lpDisplayName,
2438 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2439 }
2440
2441 /* Set the service type */
2442 dwError = RegSetValueExW(hServiceKey,
2443 L"Type",
2444 0,
2445 REG_DWORD,
2446 (LPBYTE)&dwServiceType,
2447 sizeof(DWORD));
2448 if (dwError != ERROR_SUCCESS)
2449 goto done;
2450
2451 /* Set the start value */
2452 dwError = RegSetValueExW(hServiceKey,
2453 L"Start",
2454 0,
2455 REG_DWORD,
2456 (LPBYTE)&dwStartType,
2457 sizeof(DWORD));
2458 if (dwError != ERROR_SUCCESS)
2459 goto done;
2460
2461 /* Set the error control value */
2462 dwError = RegSetValueExW(hServiceKey,
2463 L"ErrorControl",
2464 0,
2465 REG_DWORD,
2466 (LPBYTE)&dwErrorControl,
2467 sizeof(DWORD));
2468 if (dwError != ERROR_SUCCESS)
2469 goto done;
2470
2471 /* Set the image path */
2472 if (dwServiceType & SERVICE_WIN32)
2473 {
2474 dwError = RegSetValueExW(hServiceKey,
2475 L"ImagePath",
2476 0,
2477 REG_EXPAND_SZ,
2478 (LPBYTE)lpBinaryPathName,
2479 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2480 if (dwError != ERROR_SUCCESS)
2481 goto done;
2482 }
2483 else if (dwServiceType & SERVICE_DRIVER)
2484 {
2485 dwError = RegSetValueExW(hServiceKey,
2486 L"ImagePath",
2487 0,
2488 REG_EXPAND_SZ,
2489 (LPBYTE)lpImagePath,
2490 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2491 if (dwError != ERROR_SUCCESS)
2492 goto done;
2493 }
2494
2495 /* Set the group name */
2496 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2497 {
2498 dwError = RegSetValueExW(hServiceKey,
2499 L"Group",
2500 0,
2501 REG_SZ,
2502 (LPBYTE)lpLoadOrderGroup,
2503 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2504 if (dwError != ERROR_SUCCESS)
2505 goto done;
2506 }
2507
2508 /* Set the service tag */
2509 if (lpdwTagId != NULL)
2510 {
2511 dwError = RegSetValueExW(hServiceKey,
2512 L"Tag",
2513 0,
2514 REG_DWORD,
2515 (LPBYTE)&lpService->dwTag,
2516 sizeof(DWORD));
2517 if (dwError != ERROR_SUCCESS)
2518 goto done;
2519 }
2520
2521 /* Write dependencies */
2522 if (lpDependencies != NULL && *lpDependencies != 0)
2523 {
2524 dwError = ScmWriteDependencies(hServiceKey,
2525 (LPCWSTR)lpDependencies,
2526 dwDependSize);
2527 if (dwError != ERROR_SUCCESS)
2528 goto done;
2529 }
2530
2531 /* Start name and password are only used by Win32 services */
2532 if (dwServiceType & SERVICE_WIN32)
2533 {
2534 /* Write service start name */
2535 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2536 dwError = RegSetValueExW(hServiceKey,
2537 L"ObjectName",
2538 0,
2539 REG_SZ,
2540 (LPBYTE)lpObjectName,
2541 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2542 if (dwError != ERROR_SUCCESS)
2543 goto done;
2544
2545 if (lpPassword != NULL && wcslen((LPWSTR)lpPassword) != 0)
2546 {
2547 /* FIXME: Decrypt the password */
2548
2549 /* Write the password */
2550 dwError = ScmSetServicePassword(lpServiceName,
2551 (LPCWSTR)lpPassword);
2552 if (dwError != ERROR_SUCCESS)
2553 goto done;
2554 }
2555
2556 /* Write the security descriptor */
2557 dwError = ScmWriteSecurityDescriptor(hServiceKey,
2558 lpService->pSecurityDescriptor);
2559 if (dwError != ERROR_SUCCESS)
2560 goto done;
2561 }
2562
2563 dwError = ScmCreateServiceHandle(lpService,
2564 &hServiceHandle);
2565 if (dwError != ERROR_SUCCESS)
2566 goto done;
2567
2568 dwError = ScmCheckAccess(hServiceHandle,
2569 dwDesiredAccess);
2570 if (dwError != ERROR_SUCCESS)
2571 goto done;
2572
2573 lpService->dwRefCount = 1;
2574 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2575
2576 done:
2577 /* Unlock the service database */
2578 ScmUnlockDatabase();
2579
2580 if (hServiceKey != NULL)
2581 RegCloseKey(hServiceKey);
2582
2583 if (dwError == ERROR_SUCCESS)
2584 {
2585 DPRINT("hService %p\n", hServiceHandle);
2586 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2587
2588 if (lpdwTagId != NULL)
2589 *lpdwTagId = lpService->dwTag;
2590 }
2591 else
2592 {
2593 if (lpService != NULL &&
2594 lpService->lpServiceName != NULL)
2595 {
2596 /* Release the display name buffer */
2597 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2598 }
2599
2600 if (hServiceHandle)
2601 {
2602 /* Remove the service handle */
2603 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2604 }
2605
2606 if (lpService != NULL)
2607 {
2608 /* FIXME: remove the service entry */
2609 }
2610 }
2611
2612 if (lpImagePath != NULL)
2613 HeapFree(GetProcessHeap(), 0, lpImagePath);
2614
2615 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2616
2617 return dwError;
2618 }
2619
2620
2621 /* Function 13 */
2622 DWORD
2623 WINAPI
2624 REnumDependentServicesW(
2625 SC_RPC_HANDLE hService,
2626 DWORD dwServiceState,
2627 LPBYTE lpServices,
2628 DWORD cbBufSize,
2629 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2630 LPBOUNDED_DWORD_256K lpServicesReturned)
2631 {
2632 DWORD dwError = ERROR_SUCCESS;
2633 DWORD dwServicesReturned = 0;
2634 DWORD dwServiceCount;
2635 HKEY hServicesKey = NULL;
2636 PSERVICE_HANDLE hSvc;
2637 PSERVICE lpService = NULL;
2638 PSERVICE *lpServicesArray = NULL;
2639 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2640 LPWSTR lpStr;
2641
2642 *pcbBytesNeeded = 0;
2643 *lpServicesReturned = 0;
2644
2645 DPRINT("REnumDependentServicesW() called\n");
2646
2647 hSvc = ScmGetServiceFromHandle(hService);
2648 if (hSvc == NULL)
2649 {
2650 DPRINT1("Invalid service handle!\n");
2651 return ERROR_INVALID_HANDLE;
2652 }
2653
2654 lpService = hSvc->ServiceEntry;
2655
2656 /* Check access rights */
2657 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2658 SC_MANAGER_ENUMERATE_SERVICE))
2659 {
2660 DPRINT("Insufficient access rights! 0x%lx\n",
2661 hSvc->Handle.DesiredAccess);
2662 return ERROR_ACCESS_DENIED;
2663 }
2664
2665 /* Open the Services Reg key */
2666 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2667 L"System\\CurrentControlSet\\Services",
2668 0,
2669 KEY_READ,
2670 &hServicesKey);
2671 if (dwError != ERROR_SUCCESS)
2672 return dwError;
2673
2674 /* First determine the bytes needed and get the number of dependent services */
2675 dwError = Int_EnumDependentServicesW(hServicesKey,
2676 lpService,
2677 dwServiceState,
2678 NULL,
2679 pcbBytesNeeded,
2680 &dwServicesReturned);
2681 if (dwError != ERROR_SUCCESS)
2682 goto Done;
2683
2684 /* If buffer size is less than the bytes needed or pointer is null */
2685 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2686 {
2687 dwError = ERROR_MORE_DATA;
2688 goto Done;
2689 }
2690
2691 /* Allocate memory for array of service pointers */
2692 lpServicesArray = HeapAlloc(GetProcessHeap(),
2693 HEAP_ZERO_MEMORY,
2694 (dwServicesReturned + 1) * sizeof(PSERVICE));
2695 if (!lpServicesArray)
2696 {
2697 DPRINT1("Could not allocate a buffer!!\n");
2698 dwError = ERROR_NOT_ENOUGH_MEMORY;
2699 goto Done;
2700 }
2701
2702 dwServicesReturned = 0;
2703 *pcbBytesNeeded = 0;
2704
2705 dwError = Int_EnumDependentServicesW(hServicesKey,
2706 lpService,
2707 dwServiceState,
2708 lpServicesArray,
2709 pcbBytesNeeded,
2710 &dwServicesReturned);
2711 if (dwError != ERROR_SUCCESS)
2712 {
2713 goto Done;
2714 }
2715
2716 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2717 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2718
2719 /* Copy EnumDepenedentService to Buffer */
2720 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2721 {
2722 lpService = lpServicesArray[dwServiceCount];
2723
2724 /* Copy status info */
2725 memcpy(&lpServicesPtr->ServiceStatus,
2726 &lpService->Status,
2727 sizeof(SERVICE_STATUS));
2728
2729 /* Copy display name */
2730 wcscpy(lpStr, lpService->lpDisplayName);
2731 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2732 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2733
2734 /* Copy service name */
2735 wcscpy(lpStr, lpService->lpServiceName);
2736 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2737 lpStr += (wcslen(lpService->lpServiceName) + 1);
2738
2739 lpServicesPtr++;
2740 }
2741
2742 *lpServicesReturned = dwServicesReturned;
2743
2744 Done:
2745 if (lpServicesArray != NULL)
2746 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2747
2748 RegCloseKey(hServicesKey);
2749
2750 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2751
2752 return dwError;
2753 }
2754
2755
2756 /* Function 14 */
2757 DWORD
2758 WINAPI
2759 REnumServicesStatusW(
2760 SC_RPC_HANDLE hSCManager,
2761 DWORD dwServiceType,
2762 DWORD dwServiceState,
2763 LPBYTE lpBuffer,
2764 DWORD dwBufSize,
2765 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2766 LPBOUNDED_DWORD_256K lpServicesReturned,
2767 LPBOUNDED_DWORD_256K lpResumeHandle)
2768 {
2769 /* Enumerate all the services, not regarding of their group */
2770 return REnumServiceGroupW(hSCManager,
2771 dwServiceType,
2772 dwServiceState,
2773 lpBuffer,
2774 dwBufSize,
2775 pcbBytesNeeded,
2776 lpServicesReturned,
2777 lpResumeHandle,
2778 NULL);
2779 }
2780
2781
2782 /* Function 15 */
2783 DWORD
2784 WINAPI
2785 ROpenSCManagerW(
2786 LPWSTR lpMachineName,
2787 LPWSTR lpDatabaseName,
2788 DWORD dwDesiredAccess,
2789 LPSC_RPC_HANDLE lpScHandle)
2790 {
2791 DWORD dwError;
2792 SC_HANDLE hHandle;
2793
2794 DPRINT("ROpenSCManagerW() called\n");
2795 DPRINT("lpMachineName = %p\n", lpMachineName);
2796 DPRINT("lpMachineName: %S\n", lpMachineName);
2797 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2798 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2799 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2800
2801 if (ScmShutdown)
2802 return ERROR_SHUTDOWN_IN_PROGRESS;
2803
2804 if (!lpScHandle)
2805 return ERROR_INVALID_PARAMETER;
2806
2807 dwError = ScmCreateManagerHandle(lpDatabaseName,
2808 &hHandle);
2809 if (dwError != ERROR_SUCCESS)
2810 {
2811 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2812 return dwError;
2813 }
2814
2815 /* Check the desired access */
2816 dwError = ScmCheckAccess(hHandle,
2817 dwDesiredAccess | SC_MANAGER_CONNECT);
2818 if (dwError != ERROR_SUCCESS)
2819 {
2820 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2821 HeapFree(GetProcessHeap(), 0, hHandle);
2822 return dwError;
2823 }
2824
2825 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2826 DPRINT("*hScm = %p\n", *lpScHandle);
2827
2828 DPRINT("ROpenSCManagerW() done\n");
2829
2830 return ERROR_SUCCESS;
2831 }
2832
2833
2834 /* Function 16 */
2835 DWORD
2836 WINAPI
2837 ROpenServiceW(
2838 SC_RPC_HANDLE hSCManager,
2839 LPWSTR lpServiceName,
2840 DWORD dwDesiredAccess,
2841 LPSC_RPC_HANDLE lpServiceHandle)
2842 {
2843 PSERVICE lpService;
2844 PMANAGER_HANDLE hManager;
2845 SC_HANDLE hHandle;
2846 DWORD dwError = ERROR_SUCCESS;
2847
2848 DPRINT("ROpenServiceW() called\n");
2849 DPRINT("hSCManager = %p\n", hSCManager);
2850 DPRINT("lpServiceName = %p\n", lpServiceName);
2851 DPRINT("lpServiceName: %S\n", lpServiceName);
2852 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2853
2854 if (ScmShutdown)
2855 return ERROR_SHUTDOWN_IN_PROGRESS;
2856
2857 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2858 if (hManager == NULL)
2859 {
2860 DPRINT1("Invalid service manager handle!\n");
2861 return ERROR_INVALID_HANDLE;
2862 }
2863
2864 if (!lpServiceHandle)
2865 return ERROR_INVALID_PARAMETER;
2866
2867 if (!lpServiceName)
2868 return ERROR_INVALID_ADDRESS;
2869
2870 /* Lock the service database exclusive */
2871 ScmLockDatabaseExclusive();
2872
2873 /* Get service database entry */
2874 lpService = ScmGetServiceEntryByName(lpServiceName);
2875 if (lpService == NULL)
2876 {
2877 DPRINT("Could not find a service!\n");
2878 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2879 goto Done;
2880 }
2881
2882 /* Create a service handle */
2883 dwError = ScmCreateServiceHandle(lpService,
2884 &hHandle);
2885 if (dwError != ERROR_SUCCESS)
2886 {
2887 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2888 goto Done;
2889 }
2890
2891 /* Check the desired access */
2892 dwError = ScmCheckAccess(hHandle,
2893 dwDesiredAccess);
2894 if (dwError != ERROR_SUCCESS)
2895 {
2896 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2897 HeapFree(GetProcessHeap(), 0, hHandle);
2898 goto Done;
2899 }
2900
2901 lpService->dwRefCount++;
2902 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2903
2904 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2905 DPRINT("*hService = %p\n", *lpServiceHandle);
2906
2907 Done:
2908 /* Unlock the service database */
2909 ScmUnlockDatabase();
2910
2911 DPRINT("ROpenServiceW() done\n");
2912
2913 return dwError;
2914 }
2915
2916
2917 /* Function 17 */
2918 DWORD
2919 WINAPI
2920 RQueryServiceConfigW(
2921 SC_RPC_HANDLE hService,
2922 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2923 DWORD cbBufSize,
2924 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2925 {
2926 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2927 DWORD dwError = ERROR_SUCCESS;
2928 PSERVICE_HANDLE hSvc;
2929 PSERVICE lpService = NULL;
2930 HKEY hServiceKey = NULL;
2931 LPWSTR lpImagePath = NULL;
2932 LPWSTR lpServiceStartName = NULL;
2933 LPWSTR lpDependencies = NULL;
2934 DWORD dwDependenciesLength = 0;
2935 DWORD dwRequiredSize;
2936 WCHAR lpEmptyString[] = {0,0};
2937 LPWSTR lpStr;
2938
2939 DPRINT("RQueryServiceConfigW() called\n");
2940
2941 if (ScmShutdown)
2942 return ERROR_SHUTDOWN_IN_PROGRESS;
2943
2944 hSvc = ScmGetServiceFromHandle(hService);
2945 if (hSvc == NULL)
2946 {
2947 DPRINT1("Invalid service handle!\n");
2948 return ERROR_INVALID_HANDLE;
2949 }
2950
2951 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2952 SERVICE_QUERY_CONFIG))
2953 {
2954 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2955 return ERROR_ACCESS_DENIED;
2956 }
2957
2958 lpService = hSvc->ServiceEntry;
2959 if (lpService == NULL)
2960 {
2961 DPRINT("lpService == NULL!\n");
2962 return ERROR_INVALID_HANDLE;
2963 }
2964
2965 /* Lock the service database shared */
2966 ScmLockDatabaseShared();
2967
2968 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2969 KEY_READ,
2970 &hServiceKey);
2971 if (dwError != ERROR_SUCCESS)
2972 goto Done;
2973
2974 /* Read the image path */
2975 dwError = ScmReadString(hServiceKey,
2976 L"ImagePath",
2977 &lpImagePath);
2978 if (dwError != ERROR_SUCCESS)
2979 goto Done;
2980
2981 /* Read the service start name */
2982 ScmReadString(hServiceKey,
2983 L"ObjectName",
2984 &lpServiceStartName);
2985
2986 /* Read the dependencies */
2987 ScmReadDependencies(hServiceKey,
2988 &lpDependencies,
2989 &dwDependenciesLength);
2990
2991 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2992
2993 if (lpImagePath != NULL)
2994 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2995 else
2996 dwRequiredSize += 2 * sizeof(WCHAR);
2997
2998 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2999 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
3000 else
3001 dwRequiredSize += 2 * sizeof(WCHAR);
3002
3003 if (lpDependencies != NULL)
3004 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
3005 else
3006 dwRequiredSize += 2 * sizeof(WCHAR);
3007
3008 if (lpServiceStartName != NULL)
3009 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
3010 else
3011 dwRequiredSize += 2 * sizeof(WCHAR);
3012
3013 if (lpService->lpDisplayName != NULL)
3014 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
3015 else
3016 dwRequiredSize += 2 * sizeof(WCHAR);
3017
3018 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
3019 {
3020 dwError = ERROR_INSUFFICIENT_BUFFER;
3021 }
3022 else
3023 {
3024 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
3025 lpServiceConfig->dwStartType = lpService->dwStartType;
3026 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
3027 lpServiceConfig->dwTagId = lpService->dwTag;
3028
3029 lpStr = (LPWSTR)(lpServiceConfig + 1);
3030
3031 /* Append the image path */
3032 if (lpImagePath != NULL)
3033 {
3034 wcscpy(lpStr, lpImagePath);
3035 }
3036 else
3037 {
3038 wcscpy(lpStr, lpEmptyString);
3039 }
3040
3041 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3042 lpStr += (wcslen(lpStr) + 1);
3043
3044 /* Append the group name */
3045 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
3046 {
3047 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
3048 }
3049 else
3050 {
3051 wcscpy(lpStr, lpEmptyString);
3052 }
3053
3054 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3055 lpStr += (wcslen(lpStr) + 1);
3056
3057 /* Append Dependencies */
3058 if (lpDependencies != NULL)
3059 {
3060 memcpy(lpStr,
3061 lpDependencies,
3062 dwDependenciesLength * sizeof(WCHAR));
3063 }
3064 else
3065 {
3066 wcscpy(lpStr, lpEmptyString);
3067 }
3068
3069 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3070 if (lpDependencies != NULL)
3071 lpStr += dwDependenciesLength;
3072 else
3073 lpStr += (wcslen(lpStr) + 1);
3074
3075 /* Append the service start name */
3076 if (lpServiceStartName != NULL)
3077 {
3078 wcscpy(lpStr, lpServiceStartName);
3079 }
3080 else
3081 {
3082 wcscpy(lpStr, lpEmptyString);
3083 }
3084
3085 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3086 lpStr += (wcslen(lpStr) + 1);
3087
3088 /* Append the display name */
3089 if (lpService->lpDisplayName != NULL)
3090 {
3091 wcscpy(lpStr, lpService->lpDisplayName);
3092 }
3093 else
3094 {
3095 wcscpy(lpStr, lpEmptyString);
3096 }
3097
3098 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
3099 }
3100
3101 if (pcbBytesNeeded != NULL)
3102 *pcbBytesNeeded = dwRequiredSize;
3103
3104 Done:
3105 /* Unlock the service database */
3106 ScmUnlockDatabase();
3107
3108 if (lpImagePath != NULL)
3109 HeapFree(GetProcessHeap(), 0, lpImagePath);
3110
3111 if (lpServiceStartName != NULL)
3112 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
3113
3114 if (lpDependencies != NULL)
3115 HeapFree(GetProcessHeap(), 0, lpDependencies);
3116
3117 if (hServiceKey != NULL)
3118 RegCloseKey(hServiceKey);
3119
3120 DPRINT("RQueryServiceConfigW() done\n");
3121
3122 return dwError;
3123 }
3124
3125
3126 /* Function 18 */
3127 DWORD
3128 WINAPI
3129 RQueryServiceLockStatusW(
3130 SC_RPC_HANDLE hSCManager,
3131 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
3132 DWORD cbBufSize,
3133 LPBOUNDED_DWORD_4K pcbBytesNeeded)
3134 {
3135 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
3136 PMANAGER_HANDLE hMgr;
3137 DWORD dwRequiredSize;
3138
3139 if (!lpLockStatus || !pcbBytesNeeded)
3140 return ERROR_INVALID_PARAMETER;
3141
3142 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
3143 if (hMgr == NULL)
3144 {
3145 DPRINT1("Invalid service manager handle!\n");
3146 return ERROR_INVALID_HANDLE;
3147 }
3148
3149 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
3150 SC_MANAGER_QUERY_LOCK_STATUS))
3151 {
3152 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
3153 return ERROR_ACCESS_DENIED;
3154 }
3155
3156 /* FIXME: we need to compute instead the real length of the owner name */
3157 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
3158 *pcbBytesNeeded = dwRequiredSize;
3159
3160 if (cbBufSize < dwRequiredSize)
3161 return ERROR_INSUFFICIENT_BUFFER;
3162
3163 ScmQueryServiceLockStatusW(lpLockStatus);
3164
3165 return ERROR_SUCCESS;
3166 }
3167
3168
3169 /* Function 19 */
3170 DWORD
3171 WINAPI
3172 RStartServiceW(
3173 SC_RPC_HANDLE hService,
3174 DWORD argc,
3175 LPSTRING_PTRSW argv)
3176 {
3177 DWORD dwError = ERROR_SUCCESS;
3178 PSERVICE_HANDLE hSvc;
3179 PSERVICE lpService = NULL;
3180
3181 #ifndef NDEBUG
3182 DWORD i;
3183
3184 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
3185 DPRINT(" argc: %lu\n", argc);
3186 if (argv != NULL)
3187 {
3188 for (i = 0; i < argc; i++)
3189 {
3190 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
3191 }
3192 }
3193 #endif
3194
3195 if (ScmShutdown)
3196 return ERROR_SHUTDOWN_IN_PROGRESS;
3197
3198 hSvc = ScmGetServiceFromHandle(hService);
3199 if (hSvc == NULL)
3200 {
3201 DPRINT1("Invalid service handle!\n");
3202 return ERROR_INVALID_HANDLE;
3203 }
3204
3205 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3206 SERVICE_START))
3207 {
3208 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3209 return ERROR_ACCESS_DENIED;
3210 }
3211
3212 lpService = hSvc->ServiceEntry;
3213 if (lpService == NULL)
3214 {
3215 DPRINT("lpService == NULL!\n");
3216 return ERROR_INVALID_HANDLE;
3217 }
3218
3219 if (lpService->dwStartType == SERVICE_DISABLED)
3220 return ERROR_SERVICE_DISABLED;
3221
3222 if (lpService->bDeleted)
3223 return ERROR_SERVICE_MARKED_FOR_DELETE;
3224
3225 /* Start the service */
3226 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3227
3228 return dwError;
3229 }
3230
3231
3232 /* Function 20 */
3233 DWORD
3234 WINAPI
3235 RGetServiceDisplayNameW(
3236 SC_RPC_HANDLE hSCManager,
3237 LPCWSTR lpServiceName,
3238 LPWSTR lpDisplayName,
3239 DWORD *lpcchBuffer)
3240 {
3241 // PMANAGER_HANDLE hManager;
3242 PSERVICE lpService;
3243 DWORD dwLength;
3244 DWORD dwError;
3245
3246 DPRINT("RGetServiceDisplayNameW() called\n");
3247 DPRINT("hSCManager = %p\n", hSCManager);
3248 DPRINT("lpServiceName: %S\n", lpServiceName);
3249 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3250 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3251
3252 // hManager = (PMANAGER_HANDLE)hSCManager;
3253 // if (hManager->Handle.Tag != MANAGER_TAG)
3254 // {
3255 // DPRINT("Invalid manager handle!\n");
3256 // return ERROR_INVALID_HANDLE;
3257 // }
3258
3259 /* Get service database entry */
3260 lpService = ScmGetServiceEntryByName(lpServiceName);
3261 if (lpService == NULL)
3262 {
3263 DPRINT("Could not find a service!\n");
3264
3265 /* If the service could not be found and lpcchBuffer is less than 2, windows
3266 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3267 if (*lpcchBuffer < 2)
3268 {
3269 *lpcchBuffer = 2;
3270 if (lpDisplayName != NULL)
3271 {
3272 *lpDisplayName = 0;
3273 }
3274 }
3275
3276 return ERROR_SERVICE_DOES_NOT_EXIST;
3277 }
3278
3279 if (!lpService->lpDisplayName)
3280 {
3281 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3282
3283 if (lpDisplayName != NULL &&
3284 *lpcchBuffer > dwLength)
3285 {
3286 wcscpy(lpDisplayName, lpService->lpServiceName);
3287 }
3288 }
3289 else
3290 {
3291 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3292
3293 if (lpDisplayName != NULL &&
3294 *lpcchBuffer > dwLength)
3295 {
3296 wcscpy(lpDisplayName, lpService->lpDisplayName);
3297 }
3298 }
3299
3300 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3301
3302 *lpcchBuffer = dwLength;
3303
3304 return dwError;
3305 }
3306
3307
3308 /* Function 21 */
3309 DWORD
3310 WINAPI
3311 RGetServiceKeyNameW(
3312 SC_RPC_HANDLE hSCManager,
3313 LPCWSTR lpDisplayName,
3314 LPWSTR lpServiceName,
3315 DWORD *lpcchBuffer)
3316 {
3317 // PMANAGER_HANDLE hManager;
3318 PSERVICE lpService;
3319 DWORD dwLength;
3320 DWORD dwError;
3321
3322 DPRINT("RGetServiceKeyNameW() called\n");
3323 DPRINT("hSCManager = %p\n", hSCManager);
3324 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3325 DPRINT("lpServiceName: %p\n", lpServiceName);
3326 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3327
3328 // hManager = (PMANAGER_HANDLE)hSCManager;
3329 // if (hManager->Handle.Tag != MANAGER_TAG)
3330 // {
3331 // DPRINT("Invalid manager handle!\n");
3332 // return ERROR_INVALID_HANDLE;
3333 // }
3334
3335 /* Get service database entry */
3336 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3337 if (lpService == NULL)
3338 {
3339 DPRINT("Could not find a service!\n");
3340
3341 /* If the service could not be found and lpcchBuffer is less than 2, windows
3342 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3343 if (*lpcchBuffer < 2)
3344 {
3345 *lpcchBuffer = 2;
3346 if (lpServiceName != NULL)
3347 {
3348 *lpServiceName = 0;
3349 }
3350 }
3351
3352 return ERROR_SERVICE_DOES_NOT_EXIST;
3353 }
3354
3355 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3356
3357 if (lpServiceName != NULL &&
3358 *lpcchBuffer > dwLength)
3359 {
3360 wcscpy(lpServiceName, lpService->lpServiceName);
3361 *lpcchBuffer = dwLength;
3362 return ERROR_SUCCESS;
3363 }
3364
3365 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3366
3367 *lpcchBuffer = dwLength;
3368
3369 return dwError;
3370 }
3371
3372
3373 /* Function 22 */
3374 DWORD
3375 WINAPI
3376 RI_ScSetServiceBitsA(
3377 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3378 DWORD dwServiceBits,
3379 int bSetBitsOn,
3380 int bUpdateImmediately,
3381 char *lpString)
3382 {
3383 if (ScmShutdown)
3384 return ERROR_SHUTDOWN_IN_PROGRESS;
3385
3386 if (lpString != NULL)
3387 return ERROR_INVALID_PARAMETER;
3388
3389 return RI_ScSetServiceBitsW(hServiceStatus,
3390 dwServiceBits,
3391 bSetBitsOn,
3392 bUpdateImmediately,
3393 NULL);
3394 }
3395
3396
3397 /* Function 23 */
3398 DWORD
3399 WINAPI
3400 RChangeServiceConfigA(
3401 SC_RPC_HANDLE hService,
3402 DWORD dwServiceType,
3403 DWORD dwStartType,
3404 DWORD dwErrorControl,
3405 LPSTR lpBinaryPathName,
3406 LPSTR lpLoadOrderGroup,
3407 LPDWORD lpdwTagId,
3408 LPBYTE lpDependencies,
3409 DWORD dwDependSize,
3410 LPSTR lpServiceStartName,
3411 LPBYTE lpPassword,
3412 DWORD dwPwSize,
3413 LPSTR lpDisplayName)
3414 {
3415 DWORD dwError = ERROR_SUCCESS;
3416 LPWSTR lpBinaryPathNameW = NULL;
3417 LPWSTR lpLoadOrderGroupW = NULL;
3418 LPWSTR lpDependenciesW = NULL;
3419 LPWSTR lpServiceStartNameW = NULL;
3420 LPWSTR lpDisplayNameW = NULL;
3421 DWORD dwDependenciesLength = 0;
3422 SIZE_T cchLength;
3423 int len;
3424 LPCSTR lpStr;
3425
3426 if (lpBinaryPathName)
3427 {
3428 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3429 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3430 if (!lpBinaryPathNameW)
3431 {
3432 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3433 goto cleanup;
3434 }
3435 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3436 }
3437
3438 if (lpLoadOrderGroup)
3439 {
3440 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3441 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3442 if (!lpLoadOrderGroupW)
3443 {
3444 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3445 goto cleanup;
3446 }
3447 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3448 }
3449
3450 if (lpDependencies)
3451 {
3452 lpStr = (LPCSTR)lpDependencies;
3453 while (*lpStr)
3454 {
3455 cchLength = strlen(lpStr) + 1;
3456 dwDependenciesLength += (DWORD)cchLength;
3457 lpStr = lpStr + cchLength;
3458 }
3459 dwDependenciesLength++;
3460
3461 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3462 if (!lpDependenciesW)
3463 {
3464 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3465 goto cleanup;
3466 }
3467 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3468 }
3469
3470 if (lpServiceStartName)
3471 {
3472 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3473 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3474 if (!lpServiceStartNameW)
3475 {
3476 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3477 goto cleanup;
3478 }
3479 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3480 }
3481
3482 if (lpDisplayName)
3483 {
3484 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3485 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3486 if (!lpDisplayNameW)
3487 {
3488 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3489 goto cleanup;
3490 }
3491 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3492 }
3493
3494 dwError = RChangeServiceConfigW(hService,
3495 dwServiceType,
3496 dwStartType,
3497 dwErrorControl,
3498 lpBinaryPathNameW,
3499 lpLoadOrderGroupW,
3500 lpdwTagId,
3501 (LPBYTE)lpDependenciesW,
3502 dwDependenciesLength,
3503 lpServiceStartNameW,
3504 lpPassword,
3505 dwPwSize,
3506 lpDisplayNameW);
3507
3508 cleanup:
3509 if (lpBinaryPathNameW != NULL)
3510 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3511
3512 if (lpLoadOrderGroupW != NULL)
3513 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3514
3515 if (lpDependenciesW != NULL)
3516 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3517
3518 if (lpServiceStartNameW != NULL)
3519 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3520
3521 if (lpDisplayNameW != NULL)
3522 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3523
3524 return dwError;
3525 }
3526
3527
3528 /* Function 24 */
3529 DWORD
3530 WINAPI
3531 RCreateServiceA(
3532 SC_RPC_HANDLE hSCManager,
3533 LPSTR lpServiceName,
3534 LPSTR lpDisplayName,
3535 DWORD dwDesiredAccess,
3536 DWORD dwServiceType,
3537 DWORD dwStartType,
3538 DWORD dwErrorControl,
3539 LPSTR lpBinaryPathName,
3540 LPSTR lpLoadOrderGroup,
3541 LPDWORD lpdwTagId,
3542 LPBYTE lpDependencies,
3543 DWORD dwDependSize,
3544 LPSTR lpServiceStartName,
3545 LPBYTE lpPassword,
3546 DWORD dwPwSize,
3547 LPSC_RPC_HANDLE lpServiceHandle)
3548 {
3549 DWORD dwError = ERROR_SUCCESS;
3550 LPWSTR lpServiceNameW = NULL;
3551 LPWSTR lpDisplayNameW = NULL;
3552 LPWSTR lpBinaryPathNameW = NULL;
3553 LPWSTR lpLoadOrderGroupW = NULL;
3554 LPWSTR lpDependenciesW = NULL;
3555 LPWSTR lpServiceStartNameW = NULL;
3556 DWORD dwDependenciesLength = 0;
3557 SIZE_T cchLength;
3558 int len;
3559 LPCSTR lpStr;
3560
3561 if (lpServiceName)
3562 {
3563 len = MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, NULL, 0);
3564 lpServiceNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3565 if (!lpServiceNameW)
3566 {
3567 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3568 goto cleanup;
3569 }
3570 MultiByteToWideChar(CP_ACP, 0, lpServiceName, -1, lpServiceNameW, len);
3571 }
3572
3573 if (lpDisplayName)
3574 {
3575 len = MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, NULL, 0);
3576 lpDisplayNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3577 if (!lpDisplayNameW)
3578 {
3579 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3580 goto cleanup;
3581 }
3582 MultiByteToWideChar(CP_ACP, 0, lpDisplayName, -1, lpDisplayNameW, len);
3583 }
3584
3585 if (lpBinaryPathName)
3586 {
3587 len = MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, NULL, 0);
3588 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3589 if (!lpBinaryPathNameW)
3590 {
3591 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3592 goto cleanup;
3593 }
3594 MultiByteToWideChar(CP_ACP, 0, lpBinaryPathName, -1, lpBinaryPathNameW, len);
3595 }
3596
3597 if (lpLoadOrderGroup)
3598 {
3599 len = MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, NULL, 0);
3600 lpLoadOrderGroupW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3601 if (!lpLoadOrderGroupW)
3602 {
3603 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3604 goto cleanup;
3605 }
3606 MultiByteToWideChar(CP_ACP, 0, lpLoadOrderGroup, -1, lpLoadOrderGroupW, len);
3607 }
3608
3609 if (lpDependencies)
3610 {
3611 lpStr = (LPCSTR)lpDependencies;
3612 while (*lpStr)
3613 {
3614 cchLength = strlen(lpStr) + 1;
3615 dwDependenciesLength += (DWORD)cchLength;
3616 lpStr = lpStr + cchLength;
3617 }
3618 dwDependenciesLength++;
3619
3620 lpDependenciesW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwDependenciesLength * sizeof(WCHAR));
3621 if (!lpDependenciesW)
3622 {
3623 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3624 goto cleanup;
3625 }
3626 MultiByteToWideChar(CP_ACP, 0, (LPCSTR)lpDependencies, dwDependenciesLength, lpDependenciesW, dwDependenciesLength);
3627 }
3628
3629 if (lpServiceStartName)
3630 {
3631 len = MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, NULL, 0);
3632 lpServiceStartNameW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, len * sizeof(WCHAR));
3633 if (!lpServiceStartNameW)
3634 {
3635 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
3636 goto cleanup;
3637 }
3638 MultiByteToWideChar(CP_ACP, 0, lpServiceStartName, -1, lpServiceStartNameW, len);
3639 }
3640
3641 dwError = RCreateServiceW(hSCManager,
3642 lpServiceNameW,
3643 lpDisplayNameW,
3644 dwDesiredAccess,
3645 dwServiceType,
3646 dwStartType,
3647 dwErrorControl,
3648 lpBinaryPathNameW,
3649 lpLoadOrderGroupW,
3650 lpdwTagId,
3651 (LPBYTE)lpDependenciesW,
3652 dwDependenciesLength,
3653 lpServiceStartNameW,
3654 lpPassword,
3655 dwPwSize,
3656 lpServiceHandle);
3657
3658 cleanup:
3659 if (lpServiceNameW !=NULL)
3660 HeapFree(GetProcessHeap(), 0, lpServiceNameW);
3661
3662 if (lpDisplayNameW != NULL)
3663 HeapFree(GetProcessHeap(), 0, lpDisplayNameW);
3664
3665 if (lpBinaryPathNameW != NULL)
3666 HeapFree(GetProcessHeap(), 0, lpBinaryPathNameW);
3667
3668 if (lpLoadOrderGroupW != NULL)
3669 HeapFree(GetProcessHeap(), 0, lpLoadOrderGroupW);
3670
3671 if (lpDependenciesW != NULL)
3672 HeapFree(GetProcessHeap(), 0, lpDependenciesW);
3673
3674 if (lpServiceStartNameW != NULL)
3675 HeapFree(GetProcessHeap(), 0, lpServiceStartNameW);
3676
3677 return dwError;
3678 }
3679
3680
3681 /* Function 25 */
3682 DWORD
3683 WINAPI
3684 REnumDependentServicesA(
3685 SC_RPC_HANDLE hService,
3686 DWORD dwServiceState,
3687 LPBYTE lpServices,
3688 DWORD cbBufSize,
3689 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3690 LPBOUNDED_DWORD_256K lpServicesReturned)
3691 {
3692 DWORD dwError = ERROR_SUCCESS;
3693 DWORD dwServicesReturned = 0;
3694 DWORD dwServiceCount;
3695 HKEY hServicesKey = NULL;
3696 PSERVICE_HANDLE hSvc;
3697 PSERVICE lpService = NULL;
3698 PSERVICE *lpServicesArray = NULL;
3699 LPENUM_SERVICE_STATUSA lpServicesPtr = NULL;
3700 LPSTR lpStr;
3701
3702 *pcbBytesNeeded = 0;
3703 *lpServicesReturned = 0;
3704
3705 DPRINT("REnumDependentServicesA() called\n");
3706
3707 hSvc = ScmGetServiceFromHandle(hService);
3708 if (hSvc == NULL)
3709 {
3710 DPRINT1("Invalid service handle!\n");
3711 return ERROR_INVALID_HANDLE;
3712 }
3713
3714 lpService = hSvc->ServiceEntry;
3715
3716 /* Check access rights */
3717 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3718 SC_MANAGER_ENUMERATE_SERVICE))
3719 {
3720 DPRINT("Insufficient access rights! 0x%lx\n",
3721 hSvc->Handle.DesiredAccess);
3722 return ERROR_ACCESS_DENIED;
3723 }
3724
3725 /* Open the Services Reg key */
3726 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
3727 L"System\\CurrentControlSet\\Services",
3728 0,
3729 KEY_READ,
3730 &hServicesKey);
3731
3732 if (dwError != ERROR_SUCCESS)
3733 return dwError;
3734
3735 /* NOTE: Windows calculates the pcbBytesNeeded based on WCHAR strings for
3736 both EnumDependentServicesA and EnumDependentServicesW. So returned pcbBytesNeeded
3737 are the same for both. Verified in WINXP. */
3738
3739 /* First determine the bytes needed and get the number of dependent services*/
3740 dwError = Int_EnumDependentServicesW(hServicesKey,
3741 lpService,
3742 dwServiceState,
3743 NULL,
3744 pcbBytesNeeded,
3745 &dwServicesReturned);
3746 if (dwError != ERROR_SUCCESS)
3747 goto Done;
3748
3749 /* If buffer size is less than the bytes needed or pointer is null*/
3750 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
3751 {
3752 dwError = ERROR_MORE_DATA;
3753 goto Done;
3754 }
3755
3756 /* Allocate memory for array of service pointers */
3757 lpServicesArray = HeapAlloc(GetProcessHeap(),
3758 HEAP_ZERO_MEMORY,
3759 (dwServicesReturned + 1) * sizeof(PSERVICE));
3760 if (!lpServicesArray)
3761 {
3762 DPRINT("Could not allocate a buffer!!\n");
3763 dwError = ERROR_NOT_ENOUGH_MEMORY;
3764 goto Done;
3765 }
3766
3767 dwServicesReturned = 0;
3768 *pcbBytesNeeded = 0;
3769
3770 dwError = Int_EnumDependentServicesW(hServicesKey,
3771 lpService,
3772 dwServiceState,
3773 lpServicesArray,
3774 pcbBytesNeeded,
3775 &dwServicesReturned);
3776 if (dwError != ERROR_SUCCESS)
3777 {
3778 goto Done;
3779 }
3780
3781 lpServicesPtr = (LPENUM_SERVICE_STATUSA)lpServices;
3782 lpStr = (LPSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSA)));
3783
3784 /* Copy EnumDepenedentService to Buffer */
3785 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
3786 {
3787 lpService = lpServicesArray[dwServiceCount];
3788
3789 /* Copy the status info */
3790 memcpy(&lpServicesPtr->ServiceStatus,
3791 &lpService->Status,
3792 sizeof(SERVICE_STATUS));
3793
3794 /* Copy display name */
3795 WideCharToMultiByte(CP_ACP,
3796 0,
3797 lpService->lpDisplayName,
3798 -1,
3799 lpStr,
3800 (int)wcslen(lpService->lpDisplayName),
3801 0,
3802 0);
3803 lpServicesPtr->lpDisplayName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3804 lpStr += strlen(lpStr) + 1;
3805
3806 /* Copy service name */
3807 WideCharToMultiByte(CP_ACP,
3808 0,
3809 lpService->lpServiceName,
3810 -1,
3811 lpStr,
3812 (int)wcslen(lpService->lpServiceName),
3813 0,
3814 0);
3815 lpServicesPtr->lpServiceName = (LPSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
3816 lpStr += strlen(lpStr) + 1;
3817
3818 lpServicesPtr++;
3819 }
3820
3821 *lpServicesReturned = dwServicesReturned;
3822
3823 Done:
3824 if (lpServicesArray)
3825 HeapFree(GetProcessHeap(), 0, lpServicesArray);
3826
3827 RegCloseKey(hServicesKey);
3828
3829 DPRINT("REnumDependentServicesA() done (Error %lu)\n", dwError);
3830
3831 return dwError;
3832 }
3833
3834
3835 /* Function 26 */
3836 DWORD
3837 WINAPI
3838 REnumServicesStatusA(
3839 SC_RPC_HANDLE hSCManager,
3840 DWORD dwServiceType,
3841 DWORD dwServiceState,
3842 LPBYTE lpBuffer,
3843 DWORD dwBufSize,
3844 LPBOUNDED_DWORD_256K pcbBytesNeeded,
3845 LPBOUNDED_DWORD_256K lpServicesReturned,
3846 LPBOUNDED_DWORD_256K lpResumeHandle)
3847 {
3848 LPENUM_SERVICE_STATUSW lpStatusPtrW = NULL;
3849 LPENUM_SERVICE_STATUSW lpStatusPtrIncrW;
3850 LPENUM_SERVICE_STATUSA lpStatusPtrA = NULL;
3851 LPWSTR lpStringPtrW;
3852 LPSTR lpStringPtrA;
3853 DWORD dwError;
3854 DWORD dwServiceCount;
3855
3856 DPRINT("REnumServicesStatusA() called\n");
3857
3858 if (pcbBytesNeeded == NULL || lpServicesReturned == NULL)
3859 {
3860 return ERROR_INVALID_ADDRESS;
3861 }
3862
3863 if ((dwBufSize > 0) && (lpBuffer))
3864 {
3865 lpStatusPtrW = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwBufSize);
3866 if (!lpStatusPtrW)
3867 {
3868 DPRINT("Failed to allocate buffer!\n");
3869 return ERROR_NOT_ENOUGH_MEMORY;
3870 }
3871 }
3872
3873 dwError = REnumServicesStatusW(hSCManager,
3874 dwServiceType,
3875 dwServiceState,
3876 (LPBYTE)lpStatusPtrW,
3877 dwBufSize,
3878 pcbBytesNeeded,
3879 lpServicesReturned,
3880 lpResumeHandle);
3881
3882 /* if no services were returned then we are Done */
3883 if (*lpServicesReturned == 0)
3884 goto Done;
3885
3886 lpStatusPtrIncrW = lpStatusPtrW;
3887 lpStatusPtrA = (LPENUM_SERVICE_STATUSA)lpBuffer;
3888 lpStringPtrA = (LPSTR)((ULONG_PTR)lpBuffer +
3889 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSA));
3890 lpStringPtrW = (LPWSTR)((ULONG_PTR)lpStatusPtrW +
3891 *lpServicesReturned * sizeof(ENUM_SERVICE_STATUSW));
3892
3893 for (dwServiceCount = 0; dwServiceCount < *lpServicesReturned; dwServiceCount++)
3894 {
3895 /* Copy the service name */
3896 WideCharToMultiByte(CP_ACP,
3897 0,
3898 lpStringPtrW,
3899 -1,
3900 lpStringPtrA,
3901 (int)wcslen(lpStringPtrW),
3902 0,
3903 0);
3904
3905 lpStatusPtrA->lpServiceName = (LPSTR)((ULONG_PTR)lpStringPtrA - (ULONG_PTR)lpBuffer);