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