[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 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 LPCWSTR lpErrorStrings[2];
1089
1090 DPRINT("RControlService() called\n");
1091
1092 if (ScmShutdown)
1093 return ERROR_SHUTDOWN_IN_PROGRESS;
1094
1095 /* Check the service handle */
1096 hSvc = ScmGetServiceFromHandle(hService);
1097 if (hSvc == NULL)
1098 {
1099 DPRINT1("Invalid service handle!\n");
1100 return ERROR_INVALID_HANDLE;
1101 }
1102
1103 /* Check the service entry point */
1104 lpService = hSvc->ServiceEntry;
1105 if (lpService == NULL)
1106 {
1107 DPRINT1("lpService == NULL!\n");
1108 return ERROR_INVALID_HANDLE;
1109 }
1110
1111 /* Check access rights */
1112 switch (dwControl)
1113 {
1114 case SERVICE_CONTROL_STOP:
1115 DesiredAccess = SERVICE_STOP;
1116 break;
1117
1118 case SERVICE_CONTROL_PAUSE:
1119 case SERVICE_CONTROL_CONTINUE:
1120 DesiredAccess = SERVICE_PAUSE_CONTINUE;
1121 break;
1122
1123 case SERVICE_CONTROL_INTERROGATE:
1124 DesiredAccess = SERVICE_INTERROGATE;
1125 break;
1126
1127 default:
1128 if (dwControl >= 128 && dwControl <= 255)
1129 DesiredAccess = SERVICE_USER_DEFINED_CONTROL;
1130 else
1131 return ERROR_INVALID_PARAMETER;
1132 break;
1133 }
1134
1135 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1136 DesiredAccess))
1137 return ERROR_ACCESS_DENIED;
1138
1139 /* Return the current service status information */
1140 RtlCopyMemory(lpServiceStatus,
1141 &lpService->Status,
1142 sizeof(SERVICE_STATUS));
1143
1144 if (dwControl == SERVICE_CONTROL_STOP)
1145 {
1146 /* Check if the service has dependencies running as windows
1147 doesn't stop a service that does */
1148
1149 /* Open the Services Reg key */
1150 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1151 L"System\\CurrentControlSet\\Services",
1152 0,
1153 KEY_READ,
1154 &hServicesKey);
1155 if (dwError != ERROR_SUCCESS)
1156 {
1157 DPRINT("Failed to open services key\n");
1158 return dwError;
1159 }
1160
1161 /* Call the internal function with NULL, just to get bytes we need */
1162 Int_EnumDependentServicesW(hServicesKey,
1163 lpService,
1164 SERVICE_ACTIVE,
1165 NULL,
1166 &pcbBytesNeeded,
1167 &dwServicesReturned);
1168
1169 RegCloseKey(hServicesKey);
1170
1171 /* If pcbBytesNeeded is not zero then there are services running that
1172 are dependent on this service */
1173 if (pcbBytesNeeded != 0)
1174 {
1175 DPRINT("Service has running dependencies. Failed to stop service.\n");
1176 return ERROR_DEPENDENT_SERVICES_RUNNING;
1177 }
1178 }
1179
1180 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1181 {
1182 /* Send control code to the driver */
1183 dwError = ScmControlDriver(lpService,
1184 dwControl,
1185 lpServiceStatus);
1186 }
1187 else
1188 {
1189 dwControlsAccepted = lpService->Status.dwControlsAccepted;
1190 dwCurrentState = lpService->Status.dwCurrentState;
1191
1192 /* Return ERROR_SERVICE_NOT_ACTIVE if the service has not been started */
1193 if (lpService->lpImage == NULL || dwCurrentState == SERVICE_STOPPED)
1194 return ERROR_SERVICE_NOT_ACTIVE;
1195
1196 /* Check the current state before sending a control request */
1197 switch (dwCurrentState)
1198 {
1199 case SERVICE_STOP_PENDING:
1200 case SERVICE_STOPPED:
1201 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1202
1203 case SERVICE_START_PENDING:
1204 switch (dwControl)
1205 {
1206 case SERVICE_CONTROL_STOP:
1207 break;
1208
1209 case SERVICE_CONTROL_INTERROGATE:
1210 RtlCopyMemory(lpServiceStatus,
1211 &lpService->Status,
1212 sizeof(SERVICE_STATUS));
1213 return ERROR_SUCCESS;
1214
1215 default:
1216 return ERROR_SERVICE_CANNOT_ACCEPT_CTRL;
1217 }
1218 break;
1219 }
1220
1221 /* Check if the control code is acceptable to the service */
1222 switch (dwControl)
1223 {
1224 case SERVICE_CONTROL_STOP:
1225 if ((dwControlsAccepted & SERVICE_ACCEPT_STOP) == 0)
1226 return ERROR_INVALID_SERVICE_CONTROL;
1227 break;
1228
1229 case SERVICE_CONTROL_PAUSE:
1230 case SERVICE_CONTROL_CONTINUE:
1231 if ((dwControlsAccepted & SERVICE_ACCEPT_PAUSE_CONTINUE) == 0)
1232 return ERROR_INVALID_SERVICE_CONTROL;
1233 break;
1234 }
1235
1236 /* Send control code to the service */
1237 dwError = ScmControlService(lpService,
1238 dwControl);
1239
1240 /* Return service status information */
1241 RtlCopyMemory(lpServiceStatus,
1242 &lpService->Status,
1243 sizeof(SERVICE_STATUS));
1244 }
1245
1246 if (dwError == ERROR_SUCCESS)
1247 {
1248 if (dwControl != SERVICE_CONTROL_INTERROGATE)
1249 {
1250 /* Log a sucessful send control */
1251 lpErrorStrings[0] = lpService->lpDisplayName;
1252
1253 switch(dwControl)
1254 {
1255 case SERVICE_CONTROL_STOP:
1256 lpErrorStrings[1] = L"stop";
1257 break;
1258
1259 case SERVICE_CONTROL_PAUSE:
1260 lpErrorStrings[1] = L"pause";
1261 break;
1262
1263 case SERVICE_CONTROL_CONTINUE:
1264 lpErrorStrings[1] = L"continue";
1265 break;
1266
1267 default:
1268 lpErrorStrings[1] = L"other";
1269 break;
1270 }
1271
1272 ScmLogEvent(EVENT_SERVICE_CONTROL_SUCCESS,
1273 EVENTLOG_INFORMATION_TYPE,
1274 2,
1275 lpErrorStrings);
1276 }
1277 }
1278
1279 return dwError;
1280 }
1281
1282
1283 /* Function 2 */
1284 DWORD RDeleteService(
1285 SC_RPC_HANDLE hService)
1286 {
1287 PSERVICE_HANDLE hSvc;
1288 PSERVICE lpService;
1289 DWORD dwError;
1290
1291 DPRINT("RDeleteService() called\n");
1292
1293 if (ScmShutdown)
1294 return ERROR_SHUTDOWN_IN_PROGRESS;
1295
1296 hSvc = ScmGetServiceFromHandle(hService);
1297 if (hSvc == NULL)
1298 {
1299 DPRINT1("Invalid service handle!\n");
1300 return ERROR_INVALID_HANDLE;
1301 }
1302
1303 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1304 DELETE))
1305 return ERROR_ACCESS_DENIED;
1306
1307 lpService = hSvc->ServiceEntry;
1308 if (lpService == NULL)
1309 {
1310 DPRINT("lpService == NULL!\n");
1311 return ERROR_INVALID_HANDLE;
1312 }
1313
1314 /* Lock the service database exclusively */
1315 ScmLockDatabaseExclusive();
1316
1317 if (lpService->bDeleted)
1318 {
1319 DPRINT("The service has already been marked for delete!\n");
1320 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1321 goto Done;
1322 }
1323
1324 /* Mark service for delete */
1325 lpService->bDeleted = TRUE;
1326
1327 dwError = ScmMarkServiceForDelete(lpService);
1328
1329 Done:
1330 /* Unlock the service database */
1331 ScmUnlockDatabase();
1332
1333 DPRINT("RDeleteService() done\n");
1334
1335 return dwError;
1336 }
1337
1338
1339 /* Function 3 */
1340 DWORD RLockServiceDatabase(
1341 SC_RPC_HANDLE hSCManager,
1342 LPSC_RPC_LOCK lpLock)
1343 {
1344 PMANAGER_HANDLE hMgr;
1345
1346 DPRINT("RLockServiceDatabase() called\n");
1347
1348 *lpLock = NULL;
1349
1350 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
1351 if (hMgr == NULL)
1352 {
1353 DPRINT1("Invalid service manager handle!\n");
1354 return ERROR_INVALID_HANDLE;
1355 }
1356
1357 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
1358 SC_MANAGER_LOCK))
1359 return ERROR_ACCESS_DENIED;
1360
1361 return ScmAcquireServiceStartLock(FALSE, lpLock);
1362 }
1363
1364
1365 /* Function 4 */
1366 DWORD RQueryServiceObjectSecurity(
1367 SC_RPC_HANDLE hService,
1368 SECURITY_INFORMATION dwSecurityInformation,
1369 LPBYTE lpSecurityDescriptor,
1370 DWORD cbBufSize,
1371 LPBOUNDED_DWORD_256K pcbBytesNeeded)
1372 {
1373 PSERVICE_HANDLE hSvc;
1374 PSERVICE lpService;
1375 ULONG DesiredAccess = 0;
1376 NTSTATUS Status;
1377 DWORD dwBytesNeeded;
1378 DWORD dwError;
1379
1380
1381 SECURITY_DESCRIPTOR ObjectDescriptor;
1382
1383 DPRINT("RQueryServiceObjectSecurity() called\n");
1384
1385 hSvc = ScmGetServiceFromHandle(hService);
1386 if (hSvc == NULL)
1387 {
1388 DPRINT1("Invalid service handle!\n");
1389 return ERROR_INVALID_HANDLE;
1390 }
1391
1392 if (dwSecurityInformation & (DACL_SECURITY_INFORMATION |
1393 GROUP_SECURITY_INFORMATION |
1394 OWNER_SECURITY_INFORMATION))
1395 DesiredAccess |= READ_CONTROL;
1396
1397 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1398 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1399
1400 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1401 DesiredAccess))
1402 {
1403 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1404 return ERROR_ACCESS_DENIED;
1405 }
1406
1407 lpService = hSvc->ServiceEntry;
1408 if (lpService == NULL)
1409 {
1410 DPRINT("lpService == NULL!\n");
1411 return ERROR_INVALID_HANDLE;
1412 }
1413
1414 /* Lock the service database */
1415 ScmLockDatabaseShared();
1416
1417
1418 /* hack */
1419 Status = RtlCreateSecurityDescriptor(&ObjectDescriptor, SECURITY_DESCRIPTOR_REVISION);
1420
1421 Status = RtlQuerySecurityObject(&ObjectDescriptor /* lpService->lpSecurityDescriptor */,
1422 dwSecurityInformation,
1423 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1424 cbBufSize,
1425 &dwBytesNeeded);
1426
1427 /* Unlock the service database */
1428 ScmUnlockDatabase();
1429
1430 if (NT_SUCCESS(Status))
1431 {
1432 *pcbBytesNeeded = dwBytesNeeded;
1433 dwError = STATUS_SUCCESS;
1434 }
1435 else if (Status == STATUS_BUFFER_TOO_SMALL)
1436 {
1437 *pcbBytesNeeded = dwBytesNeeded;
1438 dwError = ERROR_INSUFFICIENT_BUFFER;
1439 }
1440 else if (Status == STATUS_BAD_DESCRIPTOR_FORMAT)
1441 {
1442 dwError = ERROR_GEN_FAILURE;
1443 }
1444 else
1445 {
1446 dwError = RtlNtStatusToDosError(Status);
1447 }
1448
1449 return dwError;
1450 }
1451
1452
1453 /* Function 5 */
1454 DWORD RSetServiceObjectSecurity(
1455 SC_RPC_HANDLE hService,
1456 DWORD dwSecurityInformation,
1457 LPBYTE lpSecurityDescriptor,
1458 DWORD dwSecuityDescriptorSize)
1459 {
1460 PSERVICE_HANDLE hSvc;
1461 PSERVICE lpService;
1462 ULONG DesiredAccess = 0;
1463 /* HANDLE hToken = NULL; */
1464 HKEY hServiceKey;
1465 /* NTSTATUS Status; */
1466 DWORD dwError;
1467
1468 DPRINT("RSetServiceObjectSecurity() called\n");
1469
1470 hSvc = ScmGetServiceFromHandle(hService);
1471 if (hSvc == NULL)
1472 {
1473 DPRINT1("Invalid service handle!\n");
1474 return ERROR_INVALID_HANDLE;
1475 }
1476
1477 if (dwSecurityInformation == 0 ||
1478 dwSecurityInformation & ~(OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION
1479 | DACL_SECURITY_INFORMATION | SACL_SECURITY_INFORMATION))
1480 return ERROR_INVALID_PARAMETER;
1481
1482 if (!RtlValidSecurityDescriptor((PSECURITY_DESCRIPTOR)lpSecurityDescriptor))
1483 return ERROR_INVALID_PARAMETER;
1484
1485 if (dwSecurityInformation & SACL_SECURITY_INFORMATION)
1486 DesiredAccess |= ACCESS_SYSTEM_SECURITY;
1487
1488 if (dwSecurityInformation & DACL_SECURITY_INFORMATION)
1489 DesiredAccess |= WRITE_DAC;
1490
1491 if (dwSecurityInformation & (OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION))
1492 DesiredAccess |= WRITE_OWNER;
1493
1494 if ((dwSecurityInformation & OWNER_SECURITY_INFORMATION) &&
1495 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Owner == NULL))
1496 return ERROR_INVALID_PARAMETER;
1497
1498 if ((dwSecurityInformation & GROUP_SECURITY_INFORMATION) &&
1499 (((PISECURITY_DESCRIPTOR)lpSecurityDescriptor)->Group == NULL))
1500 return ERROR_INVALID_PARAMETER;
1501
1502 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1503 DesiredAccess))
1504 {
1505 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1506 return ERROR_ACCESS_DENIED;
1507 }
1508
1509 lpService = hSvc->ServiceEntry;
1510 if (lpService == NULL)
1511 {
1512 DPRINT("lpService == NULL!\n");
1513 return ERROR_INVALID_HANDLE;
1514 }
1515
1516 if (lpService->bDeleted)
1517 return ERROR_SERVICE_MARKED_FOR_DELETE;
1518
1519 #if 0
1520 RpcImpersonateClient(NULL);
1521
1522 Status = NtOpenThreadToken(NtCurrentThread(),
1523 8,
1524 TRUE,
1525 &hToken);
1526 if (!NT_SUCCESS(Status))
1527 return RtlNtStatusToDosError(Status);
1528
1529 RpcRevertToSelf();
1530 #endif
1531
1532 /* Lock the service database exclusive */
1533 ScmLockDatabaseExclusive();
1534
1535 #if 0
1536 Status = RtlSetSecurityObject(dwSecurityInformation,
1537 (PSECURITY_DESCRIPTOR)lpSecurityDescriptor,
1538 &lpService->lpSecurityDescriptor,
1539 &ScmServiceMapping,
1540 hToken);
1541 if (!NT_SUCCESS(Status))
1542 {
1543 dwError = RtlNtStatusToDosError(Status);
1544 goto Done;
1545 }
1546 #endif
1547
1548 dwError = ScmOpenServiceKey(lpService->lpServiceName,
1549 READ_CONTROL | KEY_CREATE_SUB_KEY | KEY_SET_VALUE,
1550 &hServiceKey);
1551 if (dwError != ERROR_SUCCESS)
1552 goto Done;
1553
1554 UNIMPLEMENTED;
1555 dwError = ERROR_SUCCESS;
1556 // dwError = ScmWriteSecurityDescriptor(hServiceKey,
1557 // lpService->lpSecurityDescriptor);
1558
1559 RegFlushKey(hServiceKey);
1560 RegCloseKey(hServiceKey);
1561
1562 Done:
1563
1564 #if 0
1565 if (hToken != NULL)
1566 NtClose(hToken);
1567 #endif
1568
1569 /* Unlock service database */
1570 ScmUnlockDatabase();
1571
1572 DPRINT("RSetServiceObjectSecurity() done (Error %lu)\n", dwError);
1573
1574 return dwError;
1575 }
1576
1577
1578 /* Function 6 */
1579 DWORD RQueryServiceStatus(
1580 SC_RPC_HANDLE hService,
1581 LPSERVICE_STATUS lpServiceStatus)
1582 {
1583 PSERVICE_HANDLE hSvc;
1584 PSERVICE lpService;
1585
1586 DPRINT("RQueryServiceStatus() called\n");
1587
1588 if (ScmShutdown)
1589 return ERROR_SHUTDOWN_IN_PROGRESS;
1590
1591 hSvc = ScmGetServiceFromHandle(hService);
1592 if (hSvc == NULL)
1593 {
1594 DPRINT1("Invalid service handle!\n");
1595 return ERROR_INVALID_HANDLE;
1596 }
1597
1598 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1599 SERVICE_QUERY_STATUS))
1600 {
1601 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1602 return ERROR_ACCESS_DENIED;
1603 }
1604
1605 lpService = hSvc->ServiceEntry;
1606 if (lpService == NULL)
1607 {
1608 DPRINT("lpService == NULL!\n");
1609 return ERROR_INVALID_HANDLE;
1610 }
1611
1612 /* Lock the service database shared */
1613 ScmLockDatabaseShared();
1614
1615 /* Return service status information */
1616 RtlCopyMemory(lpServiceStatus,
1617 &lpService->Status,
1618 sizeof(SERVICE_STATUS));
1619
1620 /* Unlock the service database */
1621 ScmUnlockDatabase();
1622
1623 return ERROR_SUCCESS;
1624 }
1625
1626
1627 static BOOL
1628 ScmIsValidServiceState(DWORD dwCurrentState)
1629 {
1630 switch (dwCurrentState)
1631 {
1632 case SERVICE_STOPPED:
1633 case SERVICE_START_PENDING:
1634 case SERVICE_STOP_PENDING:
1635 case SERVICE_RUNNING:
1636 case SERVICE_CONTINUE_PENDING:
1637 case SERVICE_PAUSE_PENDING:
1638 case SERVICE_PAUSED:
1639 return TRUE;
1640
1641 default:
1642 return FALSE;
1643 }
1644 }
1645
1646
1647 /* Function 7 */
1648 DWORD RSetServiceStatus(
1649 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1650 LPSERVICE_STATUS lpServiceStatus)
1651 {
1652 PSERVICE lpService;
1653 DWORD dwPreviousState;
1654 DWORD dwPreviousType;
1655 LPCWSTR lpErrorStrings[2];
1656 WCHAR szErrorBuffer[32];
1657
1658 DPRINT("RSetServiceStatus() called\n");
1659 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1660 DPRINT("dwServiceType = 0x%lx\n", lpServiceStatus->dwServiceType);
1661 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1662 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1663 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1664 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1665 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1666 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1667
1668 if (hServiceStatus == 0)
1669 {
1670 DPRINT("hServiceStatus == NULL!\n");
1671 return ERROR_INVALID_HANDLE;
1672 }
1673
1674 lpService = (PSERVICE)hServiceStatus;
1675
1676 /* Check current state */
1677 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1678 {
1679 DPRINT("Invalid service state!\n");
1680 return ERROR_INVALID_DATA;
1681 }
1682
1683 /* Check service type */
1684 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1685 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1686 {
1687 DPRINT("Invalid service type!\n");
1688 return ERROR_INVALID_DATA;
1689 }
1690
1691 /* Check accepted controls */
1692 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1693 {
1694 DPRINT("Invalid controls accepted!\n");
1695 return ERROR_INVALID_DATA;
1696 }
1697
1698 /* Set the wait hint and check point only if the service is in a pending state,
1699 otherwise they should be 0 */
1700 if (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1701 lpServiceStatus->dwCurrentState == SERVICE_PAUSED ||
1702 lpServiceStatus->dwCurrentState == SERVICE_RUNNING)
1703 {
1704 lpServiceStatus->dwWaitHint = 0;
1705 lpServiceStatus->dwCheckPoint = 0;
1706 }
1707
1708 /* Lock the service database exclusively */
1709 ScmLockDatabaseExclusive();
1710
1711 /* Save the current service state */
1712 dwPreviousState = lpService->Status.dwCurrentState;
1713
1714 /* Save the current service type */
1715 dwPreviousType = lpService->Status.dwServiceType;
1716
1717 /* Update the service status */
1718 RtlCopyMemory(&lpService->Status,
1719 lpServiceStatus,
1720 sizeof(SERVICE_STATUS));
1721
1722 /* Restore the previous service type */
1723 lpService->Status.dwServiceType = dwPreviousType;
1724
1725 /* Unlock the service database */
1726 ScmUnlockDatabase();
1727
1728 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1729 (dwPreviousState != SERVICE_STOPPED) &&
1730 (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS))
1731 {
1732 /* Log a failed service stop */
1733 swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
1734 lpErrorStrings[0] = lpService->lpDisplayName;
1735 lpErrorStrings[1] = szErrorBuffer;
1736
1737 ScmLogEvent(EVENT_SERVICE_EXIT_FAILED,
1738 EVENTLOG_ERROR_TYPE,
1739 2,
1740 lpErrorStrings);
1741 }
1742 else if (lpServiceStatus->dwCurrentState != dwPreviousState &&
1743 (lpServiceStatus->dwCurrentState == SERVICE_STOPPED ||
1744 lpServiceStatus->dwCurrentState == SERVICE_RUNNING ||
1745 lpServiceStatus->dwCurrentState == SERVICE_PAUSED))
1746 {
1747 /* Log a successful service status change */
1748 lpErrorStrings[0] = lpService->lpDisplayName;
1749
1750 switch(lpServiceStatus->dwCurrentState)
1751 {
1752 case SERVICE_STOPPED:
1753 lpErrorStrings[1] = L"stopped";
1754 break;
1755
1756 case SERVICE_RUNNING:
1757 lpErrorStrings[1] = L"running";
1758 break;
1759
1760 case SERVICE_PAUSED:
1761 lpErrorStrings[1] = L"paused";
1762 break;
1763 }
1764
1765 ScmLogEvent(EVENT_SERVICE_STATUS_SUCCESS,
1766 EVENTLOG_INFORMATION_TYPE,
1767 2,
1768 lpErrorStrings);
1769 }
1770
1771 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1772 DPRINT("RSetServiceStatus() done\n");
1773
1774 return ERROR_SUCCESS;
1775 }
1776
1777
1778 /* Function 8 */
1779 DWORD RUnlockServiceDatabase(
1780 LPSC_RPC_LOCK Lock)
1781 {
1782 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1783 return ScmReleaseServiceStartLock(Lock);
1784 }
1785
1786
1787 /* Function 9 */
1788 DWORD RNotifyBootConfigStatus(
1789 SVCCTL_HANDLEW lpMachineName,
1790 DWORD BootAcceptable)
1791 {
1792 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1793 return ERROR_SUCCESS;
1794
1795 // UNIMPLEMENTED;
1796 // return ERROR_CALL_NOT_IMPLEMENTED;
1797 }
1798
1799
1800 /* Function 10 */
1801 DWORD RI_ScSetServiceBitsW(
1802 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1803 DWORD dwServiceBits,
1804 int bSetBitsOn,
1805 int bUpdateImmediately,
1806 wchar_t *lpString)
1807 {
1808 UNIMPLEMENTED;
1809 return ERROR_CALL_NOT_IMPLEMENTED;
1810 }
1811
1812
1813 /* Function 11 */
1814 DWORD RChangeServiceConfigW(
1815 SC_RPC_HANDLE hService,
1816 DWORD dwServiceType,
1817 DWORD dwStartType,
1818 DWORD dwErrorControl,
1819 LPWSTR lpBinaryPathName,
1820 LPWSTR lpLoadOrderGroup,
1821 LPDWORD lpdwTagId,
1822 LPBYTE lpDependencies,
1823 DWORD dwDependSize,
1824 LPWSTR lpServiceStartName,
1825 LPBYTE lpPassword,
1826 DWORD dwPwSize,
1827 LPWSTR lpDisplayName)
1828 {
1829 DWORD dwError = ERROR_SUCCESS;
1830 PSERVICE_HANDLE hSvc;
1831 PSERVICE lpService = NULL;
1832 HKEY hServiceKey = NULL;
1833 LPWSTR lpDisplayNameW = NULL;
1834 LPWSTR lpImagePathW = NULL;
1835
1836 DPRINT("RChangeServiceConfigW() called\n");
1837 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
1838 DPRINT("dwStartType = %lu\n", dwStartType);
1839 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1840 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1841 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1842 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1843
1844 if (ScmShutdown)
1845 return ERROR_SHUTDOWN_IN_PROGRESS;
1846
1847 hSvc = ScmGetServiceFromHandle(hService);
1848 if (hSvc == NULL)
1849 {
1850 DPRINT1("Invalid service handle!\n");
1851 return ERROR_INVALID_HANDLE;
1852 }
1853
1854 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1855 SERVICE_CHANGE_CONFIG))
1856 {
1857 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1858 return ERROR_ACCESS_DENIED;
1859 }
1860
1861 lpService = hSvc->ServiceEntry;
1862 if (lpService == NULL)
1863 {
1864 DPRINT("lpService == NULL!\n");
1865 return ERROR_INVALID_HANDLE;
1866 }
1867
1868 /* Lock the service database exclusively */
1869 ScmLockDatabaseExclusive();
1870
1871 if (lpService->bDeleted)
1872 {
1873 DPRINT("The service has already been marked for delete!\n");
1874 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1875 goto done;
1876 }
1877
1878 /* Open the service key */
1879 dwError = ScmOpenServiceKey(lpService->szServiceName,
1880 KEY_SET_VALUE,
1881 &hServiceKey);
1882 if (dwError != ERROR_SUCCESS)
1883 goto done;
1884
1885 /* Write service data to the registry */
1886 /* Set the display name */
1887 if (lpDisplayName != NULL && *lpDisplayName != 0)
1888 {
1889 RegSetValueExW(hServiceKey,
1890 L"DisplayName",
1891 0,
1892 REG_SZ,
1893 (LPBYTE)lpDisplayName,
1894 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
1895
1896 /* Update the display name */
1897 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1898 HEAP_ZERO_MEMORY,
1899 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1900 if (lpDisplayNameW == NULL)
1901 {
1902 dwError = ERROR_NOT_ENOUGH_MEMORY;
1903 goto done;
1904 }
1905
1906 if (lpService->lpDisplayName != lpService->lpServiceName)
1907 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1908
1909 lpService->lpDisplayName = lpDisplayNameW;
1910 }
1911
1912 if (dwServiceType != SERVICE_NO_CHANGE)
1913 {
1914 /* Set the service type */
1915 dwError = RegSetValueExW(hServiceKey,
1916 L"Type",
1917 0,
1918 REG_DWORD,
1919 (LPBYTE)&dwServiceType,
1920 sizeof(DWORD));
1921 if (dwError != ERROR_SUCCESS)
1922 goto done;
1923
1924 lpService->Status.dwServiceType = dwServiceType;
1925 }
1926
1927 if (dwStartType != SERVICE_NO_CHANGE)
1928 {
1929 /* Set the start value */
1930 dwError = RegSetValueExW(hServiceKey,
1931 L"Start",
1932 0,
1933 REG_DWORD,
1934 (LPBYTE)&dwStartType,
1935 sizeof(DWORD));
1936 if (dwError != ERROR_SUCCESS)
1937 goto done;
1938
1939 lpService->dwStartType = dwStartType;
1940 }
1941
1942 if (dwErrorControl != SERVICE_NO_CHANGE)
1943 {
1944 /* Set the error control value */
1945 dwError = RegSetValueExW(hServiceKey,
1946 L"ErrorControl",
1947 0,
1948 REG_DWORD,
1949 (LPBYTE)&dwErrorControl,
1950 sizeof(DWORD));
1951 if (dwError != ERROR_SUCCESS)
1952 goto done;
1953
1954 lpService->dwErrorControl = dwErrorControl;
1955 }
1956
1957 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1958 {
1959 /* Set the image path */
1960 lpImagePathW = lpBinaryPathName;
1961
1962 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1963 {
1964 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
1965 lpBinaryPathName,
1966 &lpImagePathW);
1967
1968 if (dwError != ERROR_SUCCESS)
1969 goto done;
1970 }
1971
1972 dwError = RegSetValueExW(hServiceKey,
1973 L"ImagePath",
1974 0,
1975 REG_EXPAND_SZ,
1976 (LPBYTE)lpImagePathW,
1977 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
1978
1979 if (lpImagePathW != lpBinaryPathName)
1980 HeapFree(GetProcessHeap(), 0, lpImagePathW);
1981
1982 if (dwError != ERROR_SUCCESS)
1983 goto done;
1984 }
1985
1986 /* Set the group name */
1987 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1988 {
1989 dwError = RegSetValueExW(hServiceKey,
1990 L"Group",
1991 0,
1992 REG_SZ,
1993 (LPBYTE)lpLoadOrderGroup,
1994 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
1995 if (dwError != ERROR_SUCCESS)
1996 goto done;
1997
1998 dwError = ScmSetServiceGroup(lpService,
1999 lpLoadOrderGroup);
2000 if (dwError != ERROR_SUCCESS)
2001 goto done;
2002 }
2003
2004 if (lpdwTagId != NULL)
2005 {
2006 dwError = ScmAssignNewTag(lpService);
2007 if (dwError != ERROR_SUCCESS)
2008 goto done;
2009
2010 dwError = RegSetValueExW(hServiceKey,
2011 L"Tag",
2012 0,
2013 REG_DWORD,
2014 (LPBYTE)&lpService->dwTag,
2015 sizeof(DWORD));
2016 if (dwError != ERROR_SUCCESS)
2017 goto done;
2018
2019 *lpdwTagId = lpService->dwTag;
2020 }
2021
2022 /* Write dependencies */
2023 if (lpDependencies != NULL && *lpDependencies != 0)
2024 {
2025 dwError = ScmWriteDependencies(hServiceKey,
2026 (LPWSTR)lpDependencies,
2027 dwDependSize);
2028 if (dwError != ERROR_SUCCESS)
2029 goto done;
2030 }
2031
2032 if (lpPassword != NULL)
2033 {
2034 /* FIXME: Decrypt and write password */
2035 }
2036
2037 done:
2038 if (hServiceKey != NULL)
2039 RegCloseKey(hServiceKey);
2040
2041 /* Unlock the service database */
2042 ScmUnlockDatabase();
2043
2044 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
2045
2046 return dwError;
2047 }
2048
2049
2050 /* Function 12 */
2051 DWORD RCreateServiceW(
2052 SC_RPC_HANDLE hSCManager,
2053 LPCWSTR lpServiceName,
2054 LPCWSTR lpDisplayName,
2055 DWORD dwDesiredAccess,
2056 DWORD dwServiceType,
2057 DWORD dwStartType,
2058 DWORD dwErrorControl,
2059 LPCWSTR lpBinaryPathName,
2060 LPCWSTR lpLoadOrderGroup,
2061 LPDWORD lpdwTagId,
2062 LPBYTE lpDependencies,
2063 DWORD dwDependSize,
2064 LPCWSTR lpServiceStartName,
2065 LPBYTE lpPassword,
2066 DWORD dwPwSize,
2067 LPSC_RPC_HANDLE lpServiceHandle)
2068 {
2069 PMANAGER_HANDLE hManager;
2070 DWORD dwError = ERROR_SUCCESS;
2071 PSERVICE lpService = NULL;
2072 SC_HANDLE hServiceHandle = NULL;
2073 LPWSTR lpImagePath = NULL;
2074 HKEY hServiceKey = NULL;
2075 LPWSTR lpObjectName;
2076
2077 DPRINT("RCreateServiceW() called\n");
2078 DPRINT("lpServiceName = %S\n", lpServiceName);
2079 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2080 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2081 DPRINT("dwServiceType = 0x%lx\n", dwServiceType);
2082 DPRINT("dwStartType = %lu\n", dwStartType);
2083 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2084 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2085 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2086 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2087
2088 if (ScmShutdown)
2089 return ERROR_SHUTDOWN_IN_PROGRESS;
2090
2091 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2092 if (hManager == NULL)
2093 {
2094 DPRINT1("Invalid service manager handle!\n");
2095 return ERROR_INVALID_HANDLE;
2096 }
2097
2098 /* Check access rights */
2099 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2100 SC_MANAGER_CREATE_SERVICE))
2101 {
2102 DPRINT("Insufficient access rights! 0x%lx\n",
2103 hManager->Handle.DesiredAccess);
2104 return ERROR_ACCESS_DENIED;
2105 }
2106
2107 if (wcslen(lpServiceName) == 0)
2108 {
2109 return ERROR_INVALID_NAME;
2110 }
2111
2112 if (wcslen(lpBinaryPathName) == 0)
2113 {
2114 return ERROR_INVALID_PARAMETER;
2115 }
2116
2117 /* Check for invalid service type value */
2118 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2119 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2120 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2121 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2122 return ERROR_INVALID_PARAMETER;
2123
2124 /* Check for invalid start type value */
2125 if ((dwStartType != SERVICE_BOOT_START) &&
2126 (dwStartType != SERVICE_SYSTEM_START) &&
2127 (dwStartType != SERVICE_AUTO_START) &&
2128 (dwStartType != SERVICE_DEMAND_START) &&
2129 (dwStartType != SERVICE_DISABLED))
2130 return ERROR_INVALID_PARAMETER;
2131
2132 /* Only drivers can be boot start or system start services */
2133 if ((dwStartType == SERVICE_BOOT_START) ||
2134 (dwStartType == SERVICE_SYSTEM_START))
2135 {
2136 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2137 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2138 return ERROR_INVALID_PARAMETER;
2139 }
2140
2141 /* Check for invalid error control value */
2142 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2143 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2144 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2145 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2146 return ERROR_INVALID_PARAMETER;
2147
2148 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2149 (lpServiceStartName))
2150 {
2151 return ERROR_INVALID_PARAMETER;
2152 }
2153
2154 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2155 {
2156 return ERROR_INVALID_PARAMETER;
2157 }
2158
2159 /* Lock the service database exclusively */
2160 ScmLockDatabaseExclusive();
2161
2162 lpService = ScmGetServiceEntryByName(lpServiceName);
2163 if (lpService)
2164 {
2165 /* Unlock the service database */
2166 ScmUnlockDatabase();
2167
2168 /* Check if it is marked for deletion */
2169 if (lpService->bDeleted)
2170 return ERROR_SERVICE_MARKED_FOR_DELETE;
2171
2172 /* Return Error exist */
2173 return ERROR_SERVICE_EXISTS;
2174 }
2175
2176 if (lpDisplayName != NULL &&
2177 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2178 {
2179 /* Unlock the service database */
2180 ScmUnlockDatabase();
2181
2182 return ERROR_DUPLICATE_SERVICE_NAME;
2183 }
2184
2185 if (dwServiceType & SERVICE_DRIVER)
2186 {
2187 dwError = ScmCanonDriverImagePath(dwStartType,
2188 lpBinaryPathName,
2189 &lpImagePath);
2190 if (dwError != ERROR_SUCCESS)
2191 goto done;
2192 }
2193 else
2194 {
2195 if (dwStartType == SERVICE_BOOT_START ||
2196 dwStartType == SERVICE_SYSTEM_START)
2197 {
2198 /* Unlock the service database */
2199 ScmUnlockDatabase();
2200
2201 return ERROR_INVALID_PARAMETER;
2202 }
2203 }
2204
2205 /* Allocate a new service entry */
2206 dwError = ScmCreateNewServiceRecord(lpServiceName,
2207 &lpService);
2208 if (dwError != ERROR_SUCCESS)
2209 goto done;
2210
2211 /* Fill the new service entry */
2212 lpService->Status.dwServiceType = dwServiceType;
2213 lpService->dwStartType = dwStartType;
2214 lpService->dwErrorControl = dwErrorControl;
2215
2216 /* Fill the display name */
2217 if (lpDisplayName != NULL &&
2218 *lpDisplayName != 0 &&
2219 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2220 {
2221 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2222 HEAP_ZERO_MEMORY,
2223 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2224 if (lpService->lpDisplayName == NULL)
2225 {
2226 dwError = ERROR_NOT_ENOUGH_MEMORY;
2227 goto done;
2228 }
2229 wcscpy(lpService->lpDisplayName, lpDisplayName);
2230 }
2231
2232 /* Assign the service to a group */
2233 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2234 {
2235 dwError = ScmSetServiceGroup(lpService,
2236 lpLoadOrderGroup);
2237 if (dwError != ERROR_SUCCESS)
2238 goto done;
2239 }
2240
2241 /* Assign a new tag */
2242 if (lpdwTagId != NULL)
2243 {
2244 dwError = ScmAssignNewTag(lpService);
2245 if (dwError != ERROR_SUCCESS)
2246 goto done;
2247 }
2248
2249 /* Write service data to the registry */
2250 /* Create the service key */
2251 dwError = ScmCreateServiceKey(lpServiceName,
2252 KEY_WRITE,
2253 &hServiceKey);
2254 if (dwError != ERROR_SUCCESS)
2255 goto done;
2256
2257 /* Set the display name */
2258 if (lpDisplayName != NULL && *lpDisplayName != 0)
2259 {
2260 RegSetValueExW(hServiceKey,
2261 L"DisplayName",
2262 0,
2263 REG_SZ,
2264 (LPBYTE)lpDisplayName,
2265 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2266 }
2267
2268 /* Set the service type */
2269 dwError = RegSetValueExW(hServiceKey,
2270 L"Type",
2271 0,
2272 REG_DWORD,
2273 (LPBYTE)&dwServiceType,
2274 sizeof(DWORD));
2275 if (dwError != ERROR_SUCCESS)
2276 goto done;
2277
2278 /* Set the start value */
2279 dwError = RegSetValueExW(hServiceKey,
2280 L"Start",
2281 0,
2282 REG_DWORD,
2283 (LPBYTE)&dwStartType,
2284 sizeof(DWORD));
2285 if (dwError != ERROR_SUCCESS)
2286 goto done;
2287
2288 /* Set the error control value */
2289 dwError = RegSetValueExW(hServiceKey,
2290 L"ErrorControl",
2291 0,
2292 REG_DWORD,
2293 (LPBYTE)&dwErrorControl,
2294 sizeof(DWORD));
2295 if (dwError != ERROR_SUCCESS)
2296 goto done;
2297
2298 /* Set the image path */
2299 if (dwServiceType & SERVICE_WIN32)
2300 {
2301 dwError = RegSetValueExW(hServiceKey,
2302 L"ImagePath",
2303 0,
2304 REG_EXPAND_SZ,
2305 (LPBYTE)lpBinaryPathName,
2306 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2307 if (dwError != ERROR_SUCCESS)
2308 goto done;
2309 }
2310 else if (dwServiceType & SERVICE_DRIVER)
2311 {
2312 dwError = RegSetValueExW(hServiceKey,
2313 L"ImagePath",
2314 0,
2315 REG_EXPAND_SZ,
2316 (LPBYTE)lpImagePath,
2317 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2318 if (dwError != ERROR_SUCCESS)
2319 goto done;
2320 }
2321
2322 /* Set the group name */
2323 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2324 {
2325 dwError = RegSetValueExW(hServiceKey,
2326 L"Group",
2327 0,
2328 REG_SZ,
2329 (LPBYTE)lpLoadOrderGroup,
2330 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2331 if (dwError != ERROR_SUCCESS)
2332 goto done;
2333 }
2334
2335 if (lpdwTagId != NULL)
2336 {
2337 dwError = RegSetValueExW(hServiceKey,
2338 L"Tag",
2339 0,
2340 REG_DWORD,
2341 (LPBYTE)&lpService->dwTag,
2342 sizeof(DWORD));
2343 if (dwError != ERROR_SUCCESS)
2344 goto done;
2345 }
2346
2347 /* Write dependencies */
2348 if (lpDependencies != NULL && *lpDependencies != 0)
2349 {
2350 dwError = ScmWriteDependencies(hServiceKey,
2351 (LPCWSTR)lpDependencies,
2352 dwDependSize);
2353 if (dwError != ERROR_SUCCESS)
2354 goto done;
2355 }
2356
2357 /* Write service start name */
2358 if (dwServiceType & SERVICE_WIN32)
2359 {
2360 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2361 dwError = RegSetValueExW(hServiceKey,
2362 L"ObjectName",
2363 0,
2364 REG_SZ,
2365 (LPBYTE)lpObjectName,
2366 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2367 if (dwError != ERROR_SUCCESS)
2368 goto done;
2369 }
2370
2371 if (lpPassword != NULL)
2372 {
2373 /* FIXME: Decrypt and write password */
2374 }
2375
2376 dwError = ScmCreateServiceHandle(lpService,
2377 &hServiceHandle);
2378 if (dwError != ERROR_SUCCESS)
2379 goto done;
2380
2381 dwError = ScmCheckAccess(hServiceHandle,
2382 dwDesiredAccess);
2383 if (dwError != ERROR_SUCCESS)
2384 goto done;
2385
2386 lpService->dwRefCount = 1;
2387 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2388
2389 done:
2390 /* Unlock the service database */
2391 ScmUnlockDatabase();
2392
2393 if (hServiceKey != NULL)
2394 RegCloseKey(hServiceKey);
2395
2396 if (dwError == ERROR_SUCCESS)
2397 {
2398 DPRINT("hService %p\n", hServiceHandle);
2399 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2400
2401 if (lpdwTagId != NULL)
2402 *lpdwTagId = lpService->dwTag;
2403 }
2404 else
2405 {
2406 if (lpService != NULL &&
2407 lpService->lpServiceName != NULL)
2408 {
2409 /* Release the display name buffer */
2410 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2411 }
2412
2413 if (hServiceHandle)
2414 {
2415 /* Remove the service handle */
2416 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2417 }
2418
2419 if (lpService != NULL)
2420 {
2421 /* FIXME: remove the service entry */
2422 }
2423 }
2424
2425 if (lpImagePath != NULL)
2426 HeapFree(GetProcessHeap(), 0, lpImagePath);
2427
2428 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2429
2430 return dwError;
2431 }
2432
2433
2434 /* Function 13 */
2435 DWORD REnumDependentServicesW(
2436 SC_RPC_HANDLE hService,
2437 DWORD dwServiceState,
2438 LPBYTE lpServices,
2439 DWORD cbBufSize,
2440 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2441 LPBOUNDED_DWORD_256K lpServicesReturned)
2442 {
2443 DWORD dwError = ERROR_SUCCESS;
2444 DWORD dwServicesReturned = 0;
2445 DWORD dwServiceCount;
2446 HKEY hServicesKey = NULL;
2447 PSERVICE_HANDLE hSvc;
2448 PSERVICE lpService = NULL;
2449 PSERVICE *lpServicesArray = NULL;
2450 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2451 LPWSTR lpStr;
2452
2453 *pcbBytesNeeded = 0;
2454 *lpServicesReturned = 0;
2455
2456 DPRINT("REnumDependentServicesW() called\n");
2457
2458 hSvc = ScmGetServiceFromHandle(hService);
2459 if (hSvc == NULL)
2460 {
2461 DPRINT1("Invalid service handle!\n");
2462 return ERROR_INVALID_HANDLE;
2463 }
2464
2465 lpService = hSvc->ServiceEntry;
2466
2467 /* Check access rights */
2468 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2469 SC_MANAGER_ENUMERATE_SERVICE))
2470 {
2471 DPRINT("Insufficient access rights! 0x%lx\n",
2472 hSvc->Handle.DesiredAccess);
2473 return ERROR_ACCESS_DENIED;
2474 }
2475
2476 /* Open the Services Reg key */
2477 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2478 L"System\\CurrentControlSet\\Services",
2479 0,
2480 KEY_READ,
2481 &hServicesKey);
2482 if (dwError != ERROR_SUCCESS)
2483 return dwError;
2484
2485 /* First determine the bytes needed and get the number of dependent services */
2486 dwError = Int_EnumDependentServicesW(hServicesKey,
2487 lpService,
2488 dwServiceState,
2489 NULL,
2490 pcbBytesNeeded,
2491 &dwServicesReturned);
2492 if (dwError != ERROR_SUCCESS)
2493 goto Done;
2494
2495 /* If buffer size is less than the bytes needed or pointer is null */
2496 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2497 {
2498 dwError = ERROR_MORE_DATA;
2499 goto Done;
2500 }
2501
2502 /* Allocate memory for array of service pointers */
2503 lpServicesArray = HeapAlloc(GetProcessHeap(),
2504 HEAP_ZERO_MEMORY,
2505 (dwServicesReturned + 1) * sizeof(PSERVICE));
2506 if (!lpServicesArray)
2507 {
2508 DPRINT1("Could not allocate a buffer!!\n");
2509 dwError = ERROR_NOT_ENOUGH_MEMORY;
2510 goto Done;
2511 }
2512
2513 dwServicesReturned = 0;
2514 *pcbBytesNeeded = 0;
2515
2516 dwError = Int_EnumDependentServicesW(hServicesKey,
2517 lpService,
2518 dwServiceState,
2519 lpServicesArray,
2520 pcbBytesNeeded,
2521 &dwServicesReturned);
2522 if (dwError != ERROR_SUCCESS)
2523 {
2524 goto Done;
2525 }
2526
2527 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2528 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2529
2530 /* Copy EnumDepenedentService to Buffer */
2531 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2532 {
2533 lpService = lpServicesArray[dwServiceCount];
2534
2535 /* Copy status info */
2536 memcpy(&lpServicesPtr->ServiceStatus,
2537 &lpService->Status,
2538 sizeof(SERVICE_STATUS));
2539
2540 /* Copy display name */
2541 wcscpy(lpStr, lpService->lpDisplayName);
2542 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2543 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2544
2545 /* Copy service name */
2546 wcscpy(lpStr, lpService->lpServiceName);
2547 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2548 lpStr += (wcslen(lpService->lpServiceName) + 1);
2549
2550 lpServicesPtr++;
2551 }
2552
2553 *lpServicesReturned = dwServicesReturned;
2554
2555 Done:
2556 if (lpServicesArray != NULL)
2557 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2558
2559 RegCloseKey(hServicesKey);
2560
2561 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2562
2563 return dwError;
2564 }
2565
2566
2567 /* Function 14 */
2568 DWORD REnumServicesStatusW(
2569 SC_RPC_HANDLE hSCManager,
2570 DWORD dwServiceType,
2571 DWORD dwServiceState,
2572 LPBYTE lpBuffer,
2573 DWORD dwBufSize,
2574 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2575 LPBOUNDED_DWORD_256K lpServicesReturned,
2576 LPBOUNDED_DWORD_256K lpResumeHandle)
2577 {
2578 /* Enumerate all the services, not regarding of their group */
2579 return REnumServiceGroupW(hSCManager,
2580 dwServiceType,
2581 dwServiceState,
2582 lpBuffer,
2583 dwBufSize,
2584 pcbBytesNeeded,
2585 lpServicesReturned,
2586 lpResumeHandle,
2587 NULL);
2588 }
2589
2590
2591 /* Function 15 */
2592 DWORD ROpenSCManagerW(
2593 LPWSTR lpMachineName,
2594 LPWSTR lpDatabaseName,
2595 DWORD dwDesiredAccess,
2596 LPSC_RPC_HANDLE lpScHandle)
2597 {
2598 DWORD dwError;
2599 SC_HANDLE hHandle;
2600
2601 DPRINT("ROpenSCManagerW() called\n");
2602 DPRINT("lpMachineName = %p\n", lpMachineName);
2603 DPRINT("lpMachineName: %S\n", lpMachineName);
2604 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2605 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2606 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2607
2608 if (ScmShutdown)
2609 return ERROR_SHUTDOWN_IN_PROGRESS;
2610
2611 if (!lpScHandle)
2612 return ERROR_INVALID_PARAMETER;
2613
2614 dwError = ScmCreateManagerHandle(lpDatabaseName,
2615 &hHandle);
2616 if (dwError != ERROR_SUCCESS)
2617 {
2618 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2619 return dwError;
2620 }
2621
2622 /* Check the desired access */
2623 dwError = ScmCheckAccess(hHandle,
2624 dwDesiredAccess | SC_MANAGER_CONNECT);
2625 if (dwError != ERROR_SUCCESS)
2626 {
2627 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2628 HeapFree(GetProcessHeap(), 0, hHandle);
2629 return dwError;
2630 }
2631
2632 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2633 DPRINT("*hScm = %p\n", *lpScHandle);
2634
2635 DPRINT("ROpenSCManagerW() done\n");
2636
2637 return ERROR_SUCCESS;
2638 }
2639
2640
2641 /* Function 16 */
2642 DWORD ROpenServiceW(
2643 SC_RPC_HANDLE hSCManager,
2644 LPWSTR lpServiceName,
2645 DWORD dwDesiredAccess,
2646 LPSC_RPC_HANDLE lpServiceHandle)
2647 {
2648 PSERVICE lpService;
2649 PMANAGER_HANDLE hManager;
2650 SC_HANDLE hHandle;
2651 DWORD dwError = ERROR_SUCCESS;
2652
2653 DPRINT("ROpenServiceW() called\n");
2654 DPRINT("hSCManager = %p\n", hSCManager);
2655 DPRINT("lpServiceName = %p\n", lpServiceName);
2656 DPRINT("lpServiceName: %S\n", lpServiceName);
2657 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2658
2659 if (ScmShutdown)
2660 return ERROR_SHUTDOWN_IN_PROGRESS;
2661
2662 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2663 if (hManager == NULL)
2664 {
2665 DPRINT1("Invalid service manager handle!\n");
2666 return ERROR_INVALID_HANDLE;
2667 }
2668
2669 if (!lpServiceHandle)
2670 return ERROR_INVALID_PARAMETER;
2671
2672 if (!lpServiceName)
2673 return ERROR_INVALID_ADDRESS;
2674
2675 /* Lock the service database exclusive */
2676 ScmLockDatabaseExclusive();
2677
2678 /* Get service database entry */
2679 lpService = ScmGetServiceEntryByName(lpServiceName);
2680 if (lpService == NULL)
2681 {
2682 DPRINT("Could not find a service!\n");
2683 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2684 goto Done;
2685 }
2686
2687 /* Create a service handle */
2688 dwError = ScmCreateServiceHandle(lpService,
2689 &hHandle);
2690 if (dwError != ERROR_SUCCESS)
2691 {
2692 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2693 goto Done;
2694 }
2695
2696 /* Check the desired access */
2697 dwError = ScmCheckAccess(hHandle,
2698 dwDesiredAccess);
2699 if (dwError != ERROR_SUCCESS)
2700 {
2701 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2702 HeapFree(GetProcessHeap(), 0, hHandle);
2703 goto Done;
2704 }
2705
2706 lpService->dwRefCount++;
2707 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2708
2709 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2710 DPRINT("*hService = %p\n", *lpServiceHandle);
2711
2712 Done:
2713 /* Unlock the service database */
2714 ScmUnlockDatabase();
2715
2716 DPRINT("ROpenServiceW() done\n");
2717
2718 return dwError;
2719 }
2720
2721
2722 /* Function 17 */
2723 DWORD RQueryServiceConfigW(
2724 SC_RPC_HANDLE hService,
2725 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2726 DWORD cbBufSize,
2727 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2728 {
2729 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2730 DWORD dwError = ERROR_SUCCESS;
2731 PSERVICE_HANDLE hSvc;
2732 PSERVICE lpService = NULL;
2733 HKEY hServiceKey = NULL;
2734 LPWSTR lpImagePath = NULL;
2735 LPWSTR lpServiceStartName = NULL;
2736 LPWSTR lpDependencies = NULL;
2737 DWORD dwDependenciesLength = 0;
2738 DWORD dwRequiredSize;
2739 WCHAR lpEmptyString[] = {0,0};
2740 LPWSTR lpStr;
2741
2742 DPRINT("RQueryServiceConfigW() called\n");
2743
2744 if (ScmShutdown)
2745 return ERROR_SHUTDOWN_IN_PROGRESS;
2746
2747 hSvc = ScmGetServiceFromHandle(hService);
2748 if (hSvc == NULL)
2749 {
2750 DPRINT1("Invalid service handle!\n");
2751 return ERROR_INVALID_HANDLE;
2752 }
2753
2754 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2755 SERVICE_QUERY_CONFIG))
2756 {
2757 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2758 return ERROR_ACCESS_DENIED;
2759 }
2760
2761 lpService = hSvc->ServiceEntry;
2762 if (lpService == NULL)
2763 {
2764 DPRINT("lpService == NULL!\n");
2765 return ERROR_INVALID_HANDLE;
2766 }
2767
2768 /* Lock the service database shared */
2769 ScmLockDatabaseShared();
2770
2771 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2772 KEY_READ,
2773 &hServiceKey);
2774 if (dwError != ERROR_SUCCESS)
2775 goto Done;
2776
2777 /* Read the image path */
2778 dwError = ScmReadString(hServiceKey,
2779 L"ImagePath",
2780 &lpImagePath);
2781 if (dwError != ERROR_SUCCESS)
2782 goto Done;
2783
2784 /* Read the service start name */
2785 ScmReadString(hServiceKey,
2786 L"ObjectName",
2787 &lpServiceStartName);
2788
2789 /* Read the dependencies */
2790 ScmReadDependencies(hServiceKey,
2791 &lpDependencies,
2792 &dwDependenciesLength);
2793
2794 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2795
2796 if (lpImagePath != NULL)
2797 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2798 else
2799 dwRequiredSize += 2 * sizeof(WCHAR);
2800
2801 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2802 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2803 else
2804 dwRequiredSize += 2 * sizeof(WCHAR);
2805
2806 if (lpDependencies != NULL)
2807 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2808 else
2809 dwRequiredSize += 2 * sizeof(WCHAR);
2810
2811 if (lpServiceStartName != NULL)
2812 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2813 else
2814 dwRequiredSize += 2 * sizeof(WCHAR);
2815
2816 if (lpService->lpDisplayName != NULL)
2817 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2818 else
2819 dwRequiredSize += 2 * sizeof(WCHAR);
2820
2821 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2822 {
2823 dwError = ERROR_INSUFFICIENT_BUFFER;
2824 }
2825 else
2826 {
2827 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
2828 lpServiceConfig->dwStartType = lpService->dwStartType;
2829 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
2830 lpServiceConfig->dwTagId = lpService->dwTag;
2831
2832 lpStr = (LPWSTR)(lpServiceConfig + 1);
2833
2834 /* Append the image path */
2835 if (lpImagePath != NULL)
2836 {
2837 wcscpy(lpStr, lpImagePath);
2838 }
2839 else
2840 {
2841 wcscpy(lpStr, lpEmptyString);
2842 }
2843
2844 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2845 lpStr += (wcslen(lpStr) + 1);
2846
2847 /* Append the group name */
2848 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2849 {
2850 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2851 }
2852 else
2853 {
2854 wcscpy(lpStr, lpEmptyString);
2855 }
2856
2857 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2858 lpStr += (wcslen(lpStr) + 1);
2859
2860 /* Append Dependencies */
2861 if (lpDependencies != NULL)
2862 {
2863 memcpy(lpStr,
2864 lpDependencies,
2865 dwDependenciesLength * sizeof(WCHAR));
2866 }
2867 else
2868 {
2869 wcscpy(lpStr, lpEmptyString);
2870 }
2871
2872 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2873 if (lpDependencies != NULL)
2874 lpStr += dwDependenciesLength;
2875 else
2876 lpStr += (wcslen(lpStr) + 1);
2877
2878 /* Append the service start name */
2879 if (lpServiceStartName != NULL)
2880 {
2881 wcscpy(lpStr, lpServiceStartName);
2882 }
2883 else
2884 {
2885 wcscpy(lpStr, lpEmptyString);
2886 }
2887
2888 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2889 lpStr += (wcslen(lpStr) + 1);
2890
2891 /* Append the display name */
2892 if (lpService->lpDisplayName != NULL)
2893 {
2894 wcscpy(lpStr, lpService->lpDisplayName);
2895 }
2896 else
2897 {
2898 wcscpy(lpStr, lpEmptyString);
2899 }
2900
2901 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2902 }
2903
2904 if (pcbBytesNeeded != NULL)
2905 *pcbBytesNeeded = dwRequiredSize;
2906
2907 Done:
2908 /* Unlock the service database */
2909 ScmUnlockDatabase();
2910
2911 if (lpImagePath != NULL)
2912 HeapFree(GetProcessHeap(), 0, lpImagePath);
2913
2914 if (lpServiceStartName != NULL)
2915 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2916
2917 if (lpDependencies != NULL)
2918 HeapFree(GetProcessHeap(), 0, lpDependencies);
2919
2920 if (hServiceKey != NULL)
2921 RegCloseKey(hServiceKey);
2922
2923 DPRINT("RQueryServiceConfigW() done\n");
2924
2925 return dwError;
2926 }
2927
2928
2929 /* Function 18 */
2930 DWORD RQueryServiceLockStatusW(
2931 SC_RPC_HANDLE hSCManager,
2932 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2933 DWORD cbBufSize,
2934 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2935 {
2936 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
2937 PMANAGER_HANDLE hMgr;
2938 DWORD dwRequiredSize;
2939
2940 if (!lpLockStatus || !pcbBytesNeeded)
2941 return ERROR_INVALID_PARAMETER;
2942
2943 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
2944 if (hMgr == NULL)
2945 {
2946 DPRINT1("Invalid service manager handle!\n");
2947 return ERROR_INVALID_HANDLE;
2948 }
2949
2950 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
2951 SC_MANAGER_QUERY_LOCK_STATUS))
2952 {
2953 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
2954 return ERROR_ACCESS_DENIED;
2955 }
2956
2957 /* FIXME: we need to compute instead the real length of the owner name */
2958 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
2959 *pcbBytesNeeded = dwRequiredSize;
2960
2961 if (cbBufSize < dwRequiredSize)
2962 return ERROR_INSUFFICIENT_BUFFER;
2963
2964 ScmQueryServiceLockStatusW(lpLockStatus);
2965
2966 return ERROR_SUCCESS;
2967 }
2968
2969
2970 /* Function 19 */
2971 DWORD RStartServiceW(
2972 SC_RPC_HANDLE hService,
2973 DWORD argc,
2974 LPSTRING_PTRSW argv)
2975 {
2976 DWORD dwError = ERROR_SUCCESS;
2977 PSERVICE_HANDLE hSvc;
2978 PSERVICE lpService = NULL;
2979
2980 #ifndef NDEBUG
2981 DWORD i;
2982
2983 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
2984 DPRINT(" argc: %lu\n", argc);
2985 if (argv != NULL)
2986 {
2987 for (i = 0; i < argc; i++)
2988 {
2989 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
2990 }
2991 }
2992 #endif
2993
2994 if (ScmShutdown)
2995 return ERROR_SHUTDOWN_IN_PROGRESS;
2996
2997 hSvc = ScmGetServiceFromHandle(hService);
2998 if (hSvc == NULL)
2999 {
3000 DPRINT1("Invalid service handle!\n");
3001 return ERROR_INVALID_HANDLE;
3002 }
3003
3004 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3005 SERVICE_START))
3006 {
3007 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3008 return ERROR_ACCESS_DENIED;
3009 }
3010
3011 lpService = hSvc->ServiceEntry;
3012 if (lpService == NULL)
3013 {
3014 DPRINT("lpService == NULL!\n");
3015 return ERROR_INVALID_HANDLE;
3016 }
3017
3018 if (lpService->dwStartType == SERVICE_DISABLED)
3019 return ERROR_SERVICE_DISABLED;
3020
3021 if (lpService->bDeleted)
3022 return ERROR_SERVICE_MARKED_FOR_DELETE;
3023
3024 /* Start the service */
3025 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
3026
3027 return dwError;
3028 }
3029
3030
3031 /* Function 20 */
3032 DWORD RGetServiceDisplayNameW(
3033 SC_RPC_HANDLE hSCManager,
3034 LPCWSTR lpServiceName,
3035 LPWSTR lpDisplayName,
3036 DWORD *lpcchBuffer)
3037 {
3038 // PMANAGER_HANDLE hManager;
3039 PSERVICE lpService;
3040 DWORD dwLength;
3041 DWORD dwError;
3042
3043 DPRINT("RGetServiceDisplayNameW() called\n");
3044 DPRINT("hSCManager = %p\n", hSCManager);
3045 DPRINT("lpServiceName: %S\n", lpServiceName);
3046 DPRINT("lpDisplayName: %p\n", lpDisplayName);
3047 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3048
3049 // hManager = (PMANAGER_HANDLE)hSCManager;
3050 // if (hManager->Handle.Tag != MANAGER_TAG)
3051 // {
3052 // DPRINT("Invalid manager handle!\n");
3053 // return ERROR_INVALID_HANDLE;
3054 // }
3055
3056 /* Get service database entry */
3057 lpService = ScmGetServiceEntryByName(lpServiceName);
3058 if (lpService == NULL)
3059 {
3060 DPRINT("Could not find a service!\n");
3061
3062 /* If the service could not be found and lpcchBuffer is less than 2, windows
3063 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3064 if (*lpcchBuffer < 2)
3065 {
3066 *lpcchBuffer = 2;
3067 if (lpDisplayName != NULL)
3068 {
3069 *lpDisplayName = 0;
3070 }
3071 }
3072
3073 return ERROR_SERVICE_DOES_NOT_EXIST;
3074 }
3075
3076 if (!lpService->lpDisplayName)
3077 {
3078 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3079
3080 if (lpDisplayName != NULL &&
3081 *lpcchBuffer > dwLength)
3082 {
3083 wcscpy(lpDisplayName, lpService->lpServiceName);
3084 }
3085 }
3086 else
3087 {
3088 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3089
3090 if (lpDisplayName != NULL &&
3091 *lpcchBuffer > dwLength)
3092 {
3093 wcscpy(lpDisplayName, lpService->lpDisplayName);
3094 }
3095 }
3096
3097 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3098
3099 *lpcchBuffer = dwLength;
3100
3101 return dwError;
3102 }
3103
3104
3105 /* Function 21 */
3106 DWORD RGetServiceKeyNameW(
3107 SC_RPC_HANDLE hSCManager,
3108 LPCWSTR lpDisplayName,
3109 LPWSTR lpServiceName,
3110 DWORD *lpcchBuffer)
3111 {
3112 // PMANAGER_HANDLE hManager;
3113 PSERVICE lpService;
3114 DWORD dwLength;
3115 DWORD dwError;
3116
3117 DPRINT("RGetServiceKeyNameW() called\n");
3118 DPRINT("hSCManager = %p\n", hSCManager);
3119 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3120 DPRINT("lpServiceName: %p\n", lpServiceName);
3121 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3122
3123 // hManager = (PMANAGER_HANDLE)hSCManager;
3124 // if (hManager->Handle.Tag != MANAGER_TAG)
3125 // {
3126 // DPRINT("Invalid manager handle!\n");
3127 // return ERROR_INVALID_HANDLE;
3128 // }
3129
3130 /* Get service database entry */
3131 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3132 if (lpService == NULL)
3133 {
3134 DPRINT("Could not find a service!\n");
3135
3136 /* If the service could not be found and lpcchBuffer is less than 2, windows
3137 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3138 if (*lpcchBuffer < 2)
3139 {
3140 *lpcchBuffer = 2;
3141 if (lpServiceName != NULL)
3142 {
3143 *lpServiceName = 0;
3144 }
3145 }
3146
3147 return ERROR_SERVICE_DOES_NOT_EXIST;
3148 }
3149
3150 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3151
3152 if (lpServiceName != NULL &&
3153 *lpcchBuffer > dwLength)
3154 {
3155 wcscpy(lpServiceName, lpService->lpServiceName);
3156 *lpcchBuffer = dwLength;
3157 return ERROR_SUCCESS;
3158 }
3159
3160 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3161
3162 *lpcchBuffer = dwLength;
3163
3164 return dwError;
3165 }
3166
3167
3168 /* Function 22 */
3169 DWORD RI_ScSetServiceBitsA(
3170 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3171 DWORD dwServiceBits,
3172 int bSetBitsOn,
3173 int bUpdateImmediately,
3174 char *lpString)
3175 {
3176 UNIMPLEMENTED;
3177 return ERROR_CALL_NOT_IMPLEMENTED;
3178 }
3179
3180
3181 /* Function 23 */
3182 DWORD RChangeServiceConfigA(
3183 SC_RPC_HANDLE hService,
3184 DWORD dwServiceType,
3185 DWORD dwStartType,
3186 DWORD dwErrorControl,
3187 LPSTR lpBinaryPathName,
3188 LPSTR lpLoadOrderGroup,
3189 LPDWORD lpdwTagId,
3190 LPBYTE lpDependencies,
3191 DWORD dwDependSize,
3192 LPSTR lpServiceStartName,
3193 LPBYTE lpPassword,
3194 DWORD dwPwSize,
3195 LPSTR lpDisplayName)
3196 {
3197 DWORD dwError = ERROR_SUCCESS;
3198 PSERVICE_HANDLE hSvc;
3199 PSERVICE lpService = NULL;
3200 HKEY hServiceKey = NULL;
3201 LPWSTR lpDisplayNameW = NULL;
3202 LPWSTR lpBinaryPathNameW = NULL;
3203 LPWSTR lpCanonicalImagePathW = NULL;
3204 LPWSTR lpLoadOrderGroupW = NULL;
3205 LPWSTR lpDependenciesW = NULL;
3206
3207 DPRINT("RChangeServiceConfigA() called\n");
3208 DPRINT("dwServiceType = %lu\n", dwServiceType);
3209 DPRINT("dwStartType = %lu\n", dwStartType);
3210 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3211 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3212 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3213 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3214
3215 if (ScmShutdown)
3216 return ERROR_SHUTDOWN_IN_PROGRESS;
3217
3218 hSvc = ScmGetServiceFromHandle(hService);
3219 if (hSvc == NULL)
3220 {
3221 DPRINT1("Invalid service handle!\n");
3222 return ERROR_INVALID_HANDLE;
3223 }
3224
3225 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3226 SERVICE_CHANGE_CONFIG))
3227 {
3228 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3229 return ERROR_ACCESS_DENIED;
3230 }
3231
3232 lpService = hSvc->ServiceEntry;
3233 if (lpService == NULL)
3234 {
3235 DPRINT("lpService == NULL!\n");
3236 return ERROR_INVALID_HANDLE;
3237 }
3238
3239 /* Lock the service database exclusively */
3240 ScmLockDatabaseExclusive();
3241
3242 if (lpService->bDeleted)
3243 {
3244 DPRINT("The service has already been marked for delete!\n");
3245 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3246 goto done;
3247 }
3248
3249 /* Open the service key */
3250 dwError = ScmOpenServiceKey(lpService->szServiceName,
3251 KEY_SET_VALUE,
3252 &hServiceKey);
3253 if (dwError != ERROR_SUCCESS)
3254 goto done;
3255
3256 /* Write service data to the registry */
3257
3258 if (lpDisplayName != NULL && *lpDisplayName != 0)
3259 {
3260 /* Set the display name */
3261 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3262 HEAP_ZERO_MEMORY,
3263 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3264 if (lpDisplayNameW == NULL)
3265 {
3266 dwError = ERROR_NOT_ENOUGH_MEMORY;
3267 goto done;
3268 }
3269
3270