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