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