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