[PSEH3]
[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 LPCWSTR lpErrorStrings[2];
1621 WCHAR szErrorBuffer[32];
1622
1623 DPRINT("RSetServiceStatus() called\n");
1624 DPRINT("hServiceStatus = %lu\n", hServiceStatus);
1625 DPRINT("dwServiceType = %lu\n", lpServiceStatus->dwServiceType);
1626 DPRINT("dwCurrentState = %lu\n", lpServiceStatus->dwCurrentState);
1627 DPRINT("dwControlsAccepted = %lu\n", lpServiceStatus->dwControlsAccepted);
1628 DPRINT("dwWin32ExitCode = %lu\n", lpServiceStatus->dwWin32ExitCode);
1629 DPRINT("dwServiceSpecificExitCode = %lu\n", lpServiceStatus->dwServiceSpecificExitCode);
1630 DPRINT("dwCheckPoint = %lu\n", lpServiceStatus->dwCheckPoint);
1631 DPRINT("dwWaitHint = %lu\n", lpServiceStatus->dwWaitHint);
1632
1633 if (hServiceStatus == 0)
1634 {
1635 DPRINT("hServiceStatus == NULL!\n");
1636 return ERROR_INVALID_HANDLE;
1637 }
1638
1639 lpService = (PSERVICE)hServiceStatus;
1640
1641 /* Check current state */
1642 if (!ScmIsValidServiceState(lpServiceStatus->dwCurrentState))
1643 {
1644 DPRINT("Invalid service state!\n");
1645 return ERROR_INVALID_DATA;
1646 }
1647
1648 /* Check service type */
1649 if (!(lpServiceStatus->dwServiceType & SERVICE_WIN32) &&
1650 (lpServiceStatus->dwServiceType & SERVICE_DRIVER))
1651 {
1652 DPRINT("Invalid service type!\n");
1653 return ERROR_INVALID_DATA;
1654 }
1655
1656 /* Check accepted controls */
1657 if (lpServiceStatus->dwControlsAccepted & ~0xFF)
1658 {
1659 DPRINT("Invalid controls accepted!\n");
1660 return ERROR_INVALID_DATA;
1661 }
1662
1663 /* Lock the service database exclusively */
1664 ScmLockDatabaseExclusive();
1665
1666 /* Save the current service state */
1667 dwPreviousState = lpService->Status.dwCurrentState;
1668
1669 RtlCopyMemory(&lpService->Status,
1670 lpServiceStatus,
1671 sizeof(SERVICE_STATUS));
1672
1673 /* Unlock the service database */
1674 ScmUnlockDatabase();
1675
1676 /* Log a failed service stop */
1677 if ((lpServiceStatus->dwCurrentState == SERVICE_STOPPED) &&
1678 (dwPreviousState != SERVICE_STOPPED))
1679 {
1680 if (lpServiceStatus->dwWin32ExitCode != ERROR_SUCCESS)
1681 {
1682 swprintf(szErrorBuffer, L"%lu", lpServiceStatus->dwWin32ExitCode);
1683 lpErrorStrings[0] = lpService->lpDisplayName;
1684 lpErrorStrings[1] = szErrorBuffer;
1685
1686 ScmLogError(EVENT_SERVICE_EXIT_FAILED,
1687 2,
1688 lpErrorStrings);
1689 }
1690 }
1691
1692 DPRINT("Set %S to %lu\n", lpService->lpDisplayName, lpService->Status.dwCurrentState);
1693 DPRINT("RSetServiceStatus() done\n");
1694
1695 return ERROR_SUCCESS;
1696 }
1697
1698
1699 /* Function 8 */
1700 DWORD RUnlockServiceDatabase(
1701 LPSC_RPC_LOCK Lock)
1702 {
1703 DPRINT("RUnlockServiceDatabase(%p)\n", Lock);
1704 return ScmReleaseServiceStartLock(Lock);
1705 }
1706
1707
1708 /* Function 9 */
1709 DWORD RNotifyBootConfigStatus(
1710 SVCCTL_HANDLEW lpMachineName,
1711 DWORD BootAcceptable)
1712 {
1713 DPRINT1("RNotifyBootConfigStatus(%p %lu) called\n", lpMachineName, BootAcceptable);
1714 return ERROR_SUCCESS;
1715
1716 // UNIMPLEMENTED;
1717 // return ERROR_CALL_NOT_IMPLEMENTED;
1718 }
1719
1720
1721 /* Function 10 */
1722 DWORD RI_ScSetServiceBitsW(
1723 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
1724 DWORD dwServiceBits,
1725 int bSetBitsOn,
1726 int bUpdateImmediately,
1727 wchar_t *lpString)
1728 {
1729 UNIMPLEMENTED;
1730 return ERROR_CALL_NOT_IMPLEMENTED;
1731 }
1732
1733
1734 /* Function 11 */
1735 DWORD RChangeServiceConfigW(
1736 SC_RPC_HANDLE hService,
1737 DWORD dwServiceType,
1738 DWORD dwStartType,
1739 DWORD dwErrorControl,
1740 LPWSTR lpBinaryPathName,
1741 LPWSTR lpLoadOrderGroup,
1742 LPDWORD lpdwTagId,
1743 LPBYTE lpDependencies,
1744 DWORD dwDependSize,
1745 LPWSTR lpServiceStartName,
1746 LPBYTE lpPassword,
1747 DWORD dwPwSize,
1748 LPWSTR lpDisplayName)
1749 {
1750 DWORD dwError = ERROR_SUCCESS;
1751 PSERVICE_HANDLE hSvc;
1752 PSERVICE lpService = NULL;
1753 HKEY hServiceKey = NULL;
1754 LPWSTR lpDisplayNameW = NULL;
1755 LPWSTR lpImagePathW = NULL;
1756
1757 DPRINT("RChangeServiceConfigW() called\n");
1758 DPRINT("dwServiceType = %lu\n", dwServiceType);
1759 DPRINT("dwStartType = %lu\n", dwStartType);
1760 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
1761 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
1762 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
1763 DPRINT("lpDisplayName = %S\n", lpDisplayName);
1764
1765 if (ScmShutdown)
1766 return ERROR_SHUTDOWN_IN_PROGRESS;
1767
1768 hSvc = ScmGetServiceFromHandle(hService);
1769 if (hSvc == NULL)
1770 {
1771 DPRINT1("Invalid service handle!\n");
1772 return ERROR_INVALID_HANDLE;
1773 }
1774
1775 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
1776 SERVICE_CHANGE_CONFIG))
1777 {
1778 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
1779 return ERROR_ACCESS_DENIED;
1780 }
1781
1782 lpService = hSvc->ServiceEntry;
1783 if (lpService == NULL)
1784 {
1785 DPRINT("lpService == NULL!\n");
1786 return ERROR_INVALID_HANDLE;
1787 }
1788
1789 /* Lock the service database exclusively */
1790 ScmLockDatabaseExclusive();
1791
1792 if (lpService->bDeleted)
1793 {
1794 DPRINT("The service has already been marked for delete!\n");
1795 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
1796 goto done;
1797 }
1798
1799 /* Open the service key */
1800 dwError = ScmOpenServiceKey(lpService->szServiceName,
1801 KEY_SET_VALUE,
1802 &hServiceKey);
1803 if (dwError != ERROR_SUCCESS)
1804 goto done;
1805
1806 /* Write service data to the registry */
1807 /* Set the display name */
1808 if (lpDisplayName != NULL && *lpDisplayName != 0)
1809 {
1810 RegSetValueExW(hServiceKey,
1811 L"DisplayName",
1812 0,
1813 REG_SZ,
1814 (LPBYTE)lpDisplayName,
1815 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
1816
1817 /* Update the display name */
1818 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
1819 HEAP_ZERO_MEMORY,
1820 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
1821 if (lpDisplayNameW == NULL)
1822 {
1823 dwError = ERROR_NOT_ENOUGH_MEMORY;
1824 goto done;
1825 }
1826
1827 if (lpService->lpDisplayName != lpService->lpServiceName)
1828 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
1829
1830 lpService->lpDisplayName = lpDisplayNameW;
1831 }
1832
1833 if (dwServiceType != SERVICE_NO_CHANGE)
1834 {
1835 /* Set the service type */
1836 dwError = RegSetValueExW(hServiceKey,
1837 L"Type",
1838 0,
1839 REG_DWORD,
1840 (LPBYTE)&dwServiceType,
1841 sizeof(DWORD));
1842 if (dwError != ERROR_SUCCESS)
1843 goto done;
1844
1845 lpService->Status.dwServiceType = dwServiceType;
1846 }
1847
1848 if (dwStartType != SERVICE_NO_CHANGE)
1849 {
1850 /* Set the start value */
1851 dwError = RegSetValueExW(hServiceKey,
1852 L"Start",
1853 0,
1854 REG_DWORD,
1855 (LPBYTE)&dwStartType,
1856 sizeof(DWORD));
1857 if (dwError != ERROR_SUCCESS)
1858 goto done;
1859
1860 lpService->dwStartType = dwStartType;
1861 }
1862
1863 if (dwErrorControl != SERVICE_NO_CHANGE)
1864 {
1865 /* Set the error control value */
1866 dwError = RegSetValueExW(hServiceKey,
1867 L"ErrorControl",
1868 0,
1869 REG_DWORD,
1870 (LPBYTE)&dwErrorControl,
1871 sizeof(DWORD));
1872 if (dwError != ERROR_SUCCESS)
1873 goto done;
1874
1875 lpService->dwErrorControl = dwErrorControl;
1876 }
1877
1878 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
1879 {
1880 /* Set the image path */
1881 lpImagePathW = lpBinaryPathName;
1882
1883 if (lpService->Status.dwServiceType & SERVICE_DRIVER)
1884 {
1885 dwError = ScmCanonDriverImagePath(lpService->dwStartType,
1886 lpBinaryPathName,
1887 &lpImagePathW);
1888
1889 if (dwError != ERROR_SUCCESS)
1890 goto done;
1891 }
1892
1893 dwError = RegSetValueExW(hServiceKey,
1894 L"ImagePath",
1895 0,
1896 REG_EXPAND_SZ,
1897 (LPBYTE)lpImagePathW,
1898 (DWORD)((wcslen(lpImagePathW) + 1) * sizeof(WCHAR)));
1899
1900 if (lpImagePathW != lpBinaryPathName)
1901 HeapFree(GetProcessHeap(), 0, lpImagePathW);
1902
1903 if (dwError != ERROR_SUCCESS)
1904 goto done;
1905 }
1906
1907 /* Set the group name */
1908 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
1909 {
1910 dwError = RegSetValueExW(hServiceKey,
1911 L"Group",
1912 0,
1913 REG_SZ,
1914 (LPBYTE)lpLoadOrderGroup,
1915 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
1916 if (dwError != ERROR_SUCCESS)
1917 goto done;
1918
1919 dwError = ScmSetServiceGroup(lpService,
1920 lpLoadOrderGroup);
1921 if (dwError != ERROR_SUCCESS)
1922 goto done;
1923 }
1924
1925 if (lpdwTagId != NULL)
1926 {
1927 dwError = ScmAssignNewTag(lpService);
1928 if (dwError != ERROR_SUCCESS)
1929 goto done;
1930
1931 dwError = RegSetValueExW(hServiceKey,
1932 L"Tag",
1933 0,
1934 REG_DWORD,
1935 (LPBYTE)&lpService->dwTag,
1936 sizeof(DWORD));
1937 if (dwError != ERROR_SUCCESS)
1938 goto done;
1939
1940 *lpdwTagId = lpService->dwTag;
1941 }
1942
1943 /* Write dependencies */
1944 if (lpDependencies != NULL && *lpDependencies != 0)
1945 {
1946 dwError = ScmWriteDependencies(hServiceKey,
1947 (LPWSTR)lpDependencies,
1948 dwDependSize);
1949 if (dwError != ERROR_SUCCESS)
1950 goto done;
1951 }
1952
1953 if (lpPassword != NULL)
1954 {
1955 /* FIXME: Decrypt and write password */
1956 }
1957
1958 done:
1959 if (hServiceKey != NULL)
1960 RegCloseKey(hServiceKey);
1961
1962 /* Unlock the service database */
1963 ScmUnlockDatabase();
1964
1965 DPRINT("RChangeServiceConfigW() done (Error %lu)\n", dwError);
1966
1967 return dwError;
1968 }
1969
1970
1971 /* Function 12 */
1972 DWORD RCreateServiceW(
1973 SC_RPC_HANDLE hSCManager,
1974 LPCWSTR lpServiceName,
1975 LPCWSTR lpDisplayName,
1976 DWORD dwDesiredAccess,
1977 DWORD dwServiceType,
1978 DWORD dwStartType,
1979 DWORD dwErrorControl,
1980 LPCWSTR lpBinaryPathName,
1981 LPCWSTR lpLoadOrderGroup,
1982 LPDWORD lpdwTagId,
1983 LPBYTE lpDependencies,
1984 DWORD dwDependSize,
1985 LPCWSTR lpServiceStartName,
1986 LPBYTE lpPassword,
1987 DWORD dwPwSize,
1988 LPSC_RPC_HANDLE lpServiceHandle)
1989 {
1990 PMANAGER_HANDLE hManager;
1991 DWORD dwError = ERROR_SUCCESS;
1992 PSERVICE lpService = NULL;
1993 SC_HANDLE hServiceHandle = NULL;
1994 LPWSTR lpImagePath = NULL;
1995 HKEY hServiceKey = NULL;
1996 LPWSTR lpObjectName;
1997
1998 DPRINT("RCreateServiceW() called\n");
1999 DPRINT("lpServiceName = %S\n", lpServiceName);
2000 DPRINT("lpDisplayName = %S\n", lpDisplayName);
2001 DPRINT("dwDesiredAccess = %lx\n", dwDesiredAccess);
2002 DPRINT("dwServiceType = %lu\n", dwServiceType);
2003 DPRINT("dwStartType = %lu\n", dwStartType);
2004 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
2005 DPRINT("lpBinaryPathName = %S\n", lpBinaryPathName);
2006 DPRINT("lpLoadOrderGroup = %S\n", lpLoadOrderGroup);
2007 DPRINT("lpdwTagId = %p\n", lpdwTagId);
2008
2009 if (ScmShutdown)
2010 return ERROR_SHUTDOWN_IN_PROGRESS;
2011
2012 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2013 if (hManager == NULL)
2014 {
2015 DPRINT1("Invalid service manager handle!\n");
2016 return ERROR_INVALID_HANDLE;
2017 }
2018
2019 /* Check access rights */
2020 if (!RtlAreAllAccessesGranted(hManager->Handle.DesiredAccess,
2021 SC_MANAGER_CREATE_SERVICE))
2022 {
2023 DPRINT("Insufficient access rights! 0x%lx\n",
2024 hManager->Handle.DesiredAccess);
2025 return ERROR_ACCESS_DENIED;
2026 }
2027
2028 if (wcslen(lpServiceName) == 0)
2029 {
2030 return ERROR_INVALID_NAME;
2031 }
2032
2033 if (wcslen(lpBinaryPathName) == 0)
2034 {
2035 return ERROR_INVALID_PARAMETER;
2036 }
2037
2038 /* Check for invalid service type value */
2039 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2040 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER) &&
2041 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
2042 ((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS))
2043 return ERROR_INVALID_PARAMETER;
2044
2045 /* Check for invalid start type value */
2046 if ((dwStartType != SERVICE_BOOT_START) &&
2047 (dwStartType != SERVICE_SYSTEM_START) &&
2048 (dwStartType != SERVICE_AUTO_START) &&
2049 (dwStartType != SERVICE_DEMAND_START) &&
2050 (dwStartType != SERVICE_DISABLED))
2051 return ERROR_INVALID_PARAMETER;
2052
2053 /* Only drivers can be boot start or system start services */
2054 if ((dwStartType == SERVICE_BOOT_START) ||
2055 (dwStartType == SERVICE_SYSTEM_START))
2056 {
2057 if ((dwServiceType != SERVICE_KERNEL_DRIVER) &&
2058 (dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
2059 return ERROR_INVALID_PARAMETER;
2060 }
2061
2062 /* Check for invalid error control value */
2063 if ((dwErrorControl != SERVICE_ERROR_IGNORE) &&
2064 (dwErrorControl != SERVICE_ERROR_NORMAL) &&
2065 (dwErrorControl != SERVICE_ERROR_SEVERE) &&
2066 (dwErrorControl != SERVICE_ERROR_CRITICAL))
2067 return ERROR_INVALID_PARAMETER;
2068
2069 if ((dwServiceType == (SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS)) &&
2070 (lpServiceStartName))
2071 {
2072 return ERROR_INVALID_PARAMETER;
2073 }
2074
2075 if (lpdwTagId && (!lpLoadOrderGroup || !*lpLoadOrderGroup))
2076 {
2077 return ERROR_INVALID_PARAMETER;
2078 }
2079
2080 /* Lock the service database exclusively */
2081 ScmLockDatabaseExclusive();
2082
2083 lpService = ScmGetServiceEntryByName(lpServiceName);
2084 if (lpService)
2085 {
2086 /* Unlock the service database */
2087 ScmUnlockDatabase();
2088
2089 /* Check if it is marked for deletion */
2090 if (lpService->bDeleted)
2091 return ERROR_SERVICE_MARKED_FOR_DELETE;
2092
2093 /* Return Error exist */
2094 return ERROR_SERVICE_EXISTS;
2095 }
2096
2097 if (lpDisplayName != NULL &&
2098 ScmGetServiceEntryByDisplayName(lpDisplayName) != NULL)
2099 {
2100 /* Unlock the service database */
2101 ScmUnlockDatabase();
2102
2103 return ERROR_DUPLICATE_SERVICE_NAME;
2104 }
2105
2106 if (dwServiceType & SERVICE_DRIVER)
2107 {
2108 dwError = ScmCanonDriverImagePath(dwStartType,
2109 lpBinaryPathName,
2110 &lpImagePath);
2111 if (dwError != ERROR_SUCCESS)
2112 goto done;
2113 }
2114 else
2115 {
2116 if (dwStartType == SERVICE_BOOT_START ||
2117 dwStartType == SERVICE_SYSTEM_START)
2118 {
2119 /* Unlock the service database */
2120 ScmUnlockDatabase();
2121
2122 return ERROR_INVALID_PARAMETER;
2123 }
2124 }
2125
2126 /* Allocate a new service entry */
2127 dwError = ScmCreateNewServiceRecord(lpServiceName,
2128 &lpService);
2129 if (dwError != ERROR_SUCCESS)
2130 goto done;
2131
2132 /* Fill the new service entry */
2133 lpService->Status.dwServiceType = dwServiceType;
2134 lpService->dwStartType = dwStartType;
2135 lpService->dwErrorControl = dwErrorControl;
2136
2137 /* Fill the display name */
2138 if (lpDisplayName != NULL &&
2139 *lpDisplayName != 0 &&
2140 _wcsicmp(lpService->lpDisplayName, lpDisplayName) != 0)
2141 {
2142 lpService->lpDisplayName = HeapAlloc(GetProcessHeap(),
2143 HEAP_ZERO_MEMORY,
2144 (wcslen(lpDisplayName) + 1) * sizeof(WCHAR));
2145 if (lpService->lpDisplayName == NULL)
2146 {
2147 dwError = ERROR_NOT_ENOUGH_MEMORY;
2148 goto done;
2149 }
2150 wcscpy(lpService->lpDisplayName, lpDisplayName);
2151 }
2152
2153 /* Assign the service to a group */
2154 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2155 {
2156 dwError = ScmSetServiceGroup(lpService,
2157 lpLoadOrderGroup);
2158 if (dwError != ERROR_SUCCESS)
2159 goto done;
2160 }
2161
2162 /* Assign a new tag */
2163 if (lpdwTagId != NULL)
2164 {
2165 dwError = ScmAssignNewTag(lpService);
2166 if (dwError != ERROR_SUCCESS)
2167 goto done;
2168 }
2169
2170 /* Write service data to the registry */
2171 /* Create the service key */
2172 dwError = ScmCreateServiceKey(lpServiceName,
2173 KEY_WRITE,
2174 &hServiceKey);
2175 if (dwError != ERROR_SUCCESS)
2176 goto done;
2177
2178 /* Set the display name */
2179 if (lpDisplayName != NULL && *lpDisplayName != 0)
2180 {
2181 RegSetValueExW(hServiceKey,
2182 L"DisplayName",
2183 0,
2184 REG_SZ,
2185 (LPBYTE)lpDisplayName,
2186 (DWORD)((wcslen(lpDisplayName) + 1) * sizeof(WCHAR)));
2187 }
2188
2189 /* Set the service type */
2190 dwError = RegSetValueExW(hServiceKey,
2191 L"Type",
2192 0,
2193 REG_DWORD,
2194 (LPBYTE)&dwServiceType,
2195 sizeof(DWORD));
2196 if (dwError != ERROR_SUCCESS)
2197 goto done;
2198
2199 /* Set the start value */
2200 dwError = RegSetValueExW(hServiceKey,
2201 L"Start",
2202 0,
2203 REG_DWORD,
2204 (LPBYTE)&dwStartType,
2205 sizeof(DWORD));
2206 if (dwError != ERROR_SUCCESS)
2207 goto done;
2208
2209 /* Set the error control value */
2210 dwError = RegSetValueExW(hServiceKey,
2211 L"ErrorControl",
2212 0,
2213 REG_DWORD,
2214 (LPBYTE)&dwErrorControl,
2215 sizeof(DWORD));
2216 if (dwError != ERROR_SUCCESS)
2217 goto done;
2218
2219 /* Set the image path */
2220 if (dwServiceType & SERVICE_WIN32)
2221 {
2222 dwError = RegSetValueExW(hServiceKey,
2223 L"ImagePath",
2224 0,
2225 REG_EXPAND_SZ,
2226 (LPBYTE)lpBinaryPathName,
2227 (DWORD)((wcslen(lpBinaryPathName) + 1) * sizeof(WCHAR)));
2228 if (dwError != ERROR_SUCCESS)
2229 goto done;
2230 }
2231 else if (dwServiceType & SERVICE_DRIVER)
2232 {
2233 dwError = RegSetValueExW(hServiceKey,
2234 L"ImagePath",
2235 0,
2236 REG_EXPAND_SZ,
2237 (LPBYTE)lpImagePath,
2238 (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR)));
2239 if (dwError != ERROR_SUCCESS)
2240 goto done;
2241 }
2242
2243 /* Set the group name */
2244 if (lpLoadOrderGroup != NULL && *lpLoadOrderGroup != 0)
2245 {
2246 dwError = RegSetValueExW(hServiceKey,
2247 L"Group",
2248 0,
2249 REG_SZ,
2250 (LPBYTE)lpLoadOrderGroup,
2251 (DWORD)((wcslen(lpLoadOrderGroup) + 1) * sizeof(WCHAR)));
2252 if (dwError != ERROR_SUCCESS)
2253 goto done;
2254 }
2255
2256 if (lpdwTagId != NULL)
2257 {
2258 dwError = RegSetValueExW(hServiceKey,
2259 L"Tag",
2260 0,
2261 REG_DWORD,
2262 (LPBYTE)&lpService->dwTag,
2263 sizeof(DWORD));
2264 if (dwError != ERROR_SUCCESS)
2265 goto done;
2266 }
2267
2268 /* Write dependencies */
2269 if (lpDependencies != NULL && *lpDependencies != 0)
2270 {
2271 dwError = ScmWriteDependencies(hServiceKey,
2272 (LPCWSTR)lpDependencies,
2273 dwDependSize);
2274 if (dwError != ERROR_SUCCESS)
2275 goto done;
2276 }
2277
2278 /* Write service start name */
2279 if (dwServiceType & SERVICE_WIN32)
2280 {
2281 lpObjectName = (lpServiceStartName != NULL) ? (LPWSTR)lpServiceStartName : L"LocalSystem";
2282 dwError = RegSetValueExW(hServiceKey,
2283 L"ObjectName",
2284 0,
2285 REG_SZ,
2286 (LPBYTE)lpObjectName,
2287 (DWORD)((wcslen(lpObjectName) + 1) * sizeof(WCHAR)));
2288 if (dwError != ERROR_SUCCESS)
2289 goto done;
2290 }
2291
2292 if (lpPassword != NULL)
2293 {
2294 /* FIXME: Decrypt and write password */
2295 }
2296
2297 dwError = ScmCreateServiceHandle(lpService,
2298 &hServiceHandle);
2299 if (dwError != ERROR_SUCCESS)
2300 goto done;
2301
2302 dwError = ScmCheckAccess(hServiceHandle,
2303 dwDesiredAccess);
2304 if (dwError != ERROR_SUCCESS)
2305 goto done;
2306
2307 lpService->dwRefCount = 1;
2308 DPRINT("CreateService - lpService->dwRefCount %u\n", lpService->dwRefCount);
2309
2310 done:
2311 /* Unlock the service database */
2312 ScmUnlockDatabase();
2313
2314 if (hServiceKey != NULL)
2315 RegCloseKey(hServiceKey);
2316
2317 if (dwError == ERROR_SUCCESS)
2318 {
2319 DPRINT("hService %p\n", hServiceHandle);
2320 *lpServiceHandle = (SC_RPC_HANDLE)hServiceHandle;
2321
2322 if (lpdwTagId != NULL)
2323 *lpdwTagId = lpService->dwTag;
2324 }
2325 else
2326 {
2327 if (lpService != NULL &&
2328 lpService->lpServiceName != NULL)
2329 {
2330 /* Release the display name buffer */
2331 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
2332 }
2333
2334 if (hServiceHandle)
2335 {
2336 /* Remove the service handle */
2337 HeapFree(GetProcessHeap(), 0, hServiceHandle);
2338 }
2339
2340 if (lpService != NULL)
2341 {
2342 /* FIXME: remove the service entry */
2343 }
2344 }
2345
2346 if (lpImagePath != NULL)
2347 HeapFree(GetProcessHeap(), 0, lpImagePath);
2348
2349 DPRINT("RCreateServiceW() done (Error %lu)\n", dwError);
2350
2351 return dwError;
2352 }
2353
2354
2355 /* Function 13 */
2356 DWORD REnumDependentServicesW(
2357 SC_RPC_HANDLE hService,
2358 DWORD dwServiceState,
2359 LPBYTE lpServices,
2360 DWORD cbBufSize,
2361 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2362 LPBOUNDED_DWORD_256K lpServicesReturned)
2363 {
2364 DWORD dwError = ERROR_SUCCESS;
2365 DWORD dwServicesReturned = 0;
2366 DWORD dwServiceCount;
2367 HKEY hServicesKey = NULL;
2368 PSERVICE_HANDLE hSvc;
2369 PSERVICE lpService = NULL;
2370 PSERVICE *lpServicesArray = NULL;
2371 LPENUM_SERVICE_STATUSW lpServicesPtr = NULL;
2372 LPWSTR lpStr;
2373
2374 *pcbBytesNeeded = 0;
2375 *lpServicesReturned = 0;
2376
2377 DPRINT("REnumDependentServicesW() called\n");
2378
2379 hSvc = ScmGetServiceFromHandle(hService);
2380 if (hSvc == NULL)
2381 {
2382 DPRINT1("Invalid service handle!\n");
2383 return ERROR_INVALID_HANDLE;
2384 }
2385
2386 lpService = hSvc->ServiceEntry;
2387
2388 /* Check access rights */
2389 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2390 SC_MANAGER_ENUMERATE_SERVICE))
2391 {
2392 DPRINT("Insufficient access rights! 0x%lx\n",
2393 hSvc->Handle.DesiredAccess);
2394 return ERROR_ACCESS_DENIED;
2395 }
2396
2397 /* Open the Services Reg key */
2398 dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
2399 L"System\\CurrentControlSet\\Services",
2400 0,
2401 KEY_READ,
2402 &hServicesKey);
2403 if (dwError != ERROR_SUCCESS)
2404 return dwError;
2405
2406 /* First determine the bytes needed and get the number of dependent services */
2407 dwError = Int_EnumDependentServicesW(hServicesKey,
2408 lpService,
2409 dwServiceState,
2410 NULL,
2411 pcbBytesNeeded,
2412 &dwServicesReturned);
2413 if (dwError != ERROR_SUCCESS)
2414 goto Done;
2415
2416 /* If buffer size is less than the bytes needed or pointer is null */
2417 if ((!lpServices) || (cbBufSize < *pcbBytesNeeded))
2418 {
2419 dwError = ERROR_MORE_DATA;
2420 goto Done;
2421 }
2422
2423 /* Allocate memory for array of service pointers */
2424 lpServicesArray = HeapAlloc(GetProcessHeap(),
2425 HEAP_ZERO_MEMORY,
2426 (dwServicesReturned + 1) * sizeof(PSERVICE));
2427 if (!lpServicesArray)
2428 {
2429 DPRINT1("Could not allocate a buffer!!\n");
2430 dwError = ERROR_NOT_ENOUGH_MEMORY;
2431 goto Done;
2432 }
2433
2434 dwServicesReturned = 0;
2435 *pcbBytesNeeded = 0;
2436
2437 dwError = Int_EnumDependentServicesW(hServicesKey,
2438 lpService,
2439 dwServiceState,
2440 lpServicesArray,
2441 pcbBytesNeeded,
2442 &dwServicesReturned);
2443 if (dwError != ERROR_SUCCESS)
2444 {
2445 goto Done;
2446 }
2447
2448 lpServicesPtr = (LPENUM_SERVICE_STATUSW)lpServices;
2449 lpStr = (LPWSTR)(lpServices + (dwServicesReturned * sizeof(ENUM_SERVICE_STATUSW)));
2450
2451 /* Copy EnumDepenedentService to Buffer */
2452 for (dwServiceCount = 0; dwServiceCount < dwServicesReturned; dwServiceCount++)
2453 {
2454 lpService = lpServicesArray[dwServiceCount];
2455
2456 /* Copy status info */
2457 memcpy(&lpServicesPtr->ServiceStatus,
2458 &lpService->Status,
2459 sizeof(SERVICE_STATUS));
2460
2461 /* Copy display name */
2462 wcscpy(lpStr, lpService->lpDisplayName);
2463 lpServicesPtr->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2464 lpStr += (wcslen(lpService->lpDisplayName) + 1);
2465
2466 /* Copy service name */
2467 wcscpy(lpStr, lpService->lpServiceName);
2468 lpServicesPtr->lpServiceName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServices);
2469 lpStr += (wcslen(lpService->lpServiceName) + 1);
2470
2471 lpServicesPtr++;
2472 }
2473
2474 *lpServicesReturned = dwServicesReturned;
2475
2476 Done:
2477 if (lpServicesArray != NULL)
2478 HeapFree(GetProcessHeap(), 0, lpServicesArray);
2479
2480 RegCloseKey(hServicesKey);
2481
2482 DPRINT("REnumDependentServicesW() done (Error %lu)\n", dwError);
2483
2484 return dwError;
2485 }
2486
2487
2488 /* Function 14 */
2489 DWORD REnumServicesStatusW(
2490 SC_RPC_HANDLE hSCManager,
2491 DWORD dwServiceType,
2492 DWORD dwServiceState,
2493 LPBYTE lpBuffer,
2494 DWORD dwBufSize,
2495 LPBOUNDED_DWORD_256K pcbBytesNeeded,
2496 LPBOUNDED_DWORD_256K lpServicesReturned,
2497 LPBOUNDED_DWORD_256K lpResumeHandle)
2498 {
2499 /* Enumerate all the services, not regarding of their group */
2500 return REnumServiceGroupW(hSCManager,
2501 dwServiceType,
2502 dwServiceState,
2503 lpBuffer,
2504 dwBufSize,
2505 pcbBytesNeeded,
2506 lpServicesReturned,
2507 lpResumeHandle,
2508 NULL);
2509 }
2510
2511
2512 /* Function 15 */
2513 DWORD ROpenSCManagerW(
2514 LPWSTR lpMachineName,
2515 LPWSTR lpDatabaseName,
2516 DWORD dwDesiredAccess,
2517 LPSC_RPC_HANDLE lpScHandle)
2518 {
2519 DWORD dwError;
2520 SC_HANDLE hHandle;
2521
2522 DPRINT("ROpenSCManagerW() called\n");
2523 DPRINT("lpMachineName = %p\n", lpMachineName);
2524 DPRINT("lpMachineName: %S\n", lpMachineName);
2525 DPRINT("lpDataBaseName = %p\n", lpDatabaseName);
2526 DPRINT("lpDataBaseName: %S\n", lpDatabaseName);
2527 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2528
2529 if (ScmShutdown)
2530 return ERROR_SHUTDOWN_IN_PROGRESS;
2531
2532 if (!lpScHandle)
2533 return ERROR_INVALID_PARAMETER;
2534
2535 dwError = ScmCreateManagerHandle(lpDatabaseName,
2536 &hHandle);
2537 if (dwError != ERROR_SUCCESS)
2538 {
2539 DPRINT("ScmCreateManagerHandle() failed (Error %lu)\n", dwError);
2540 return dwError;
2541 }
2542
2543 /* Check the desired access */
2544 dwError = ScmCheckAccess(hHandle,
2545 dwDesiredAccess | SC_MANAGER_CONNECT);
2546 if (dwError != ERROR_SUCCESS)
2547 {
2548 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2549 HeapFree(GetProcessHeap(), 0, hHandle);
2550 return dwError;
2551 }
2552
2553 *lpScHandle = (SC_RPC_HANDLE)hHandle;
2554 DPRINT("*hScm = %p\n", *lpScHandle);
2555
2556 DPRINT("ROpenSCManagerW() done\n");
2557
2558 return ERROR_SUCCESS;
2559 }
2560
2561
2562 /* Function 16 */
2563 DWORD ROpenServiceW(
2564 SC_RPC_HANDLE hSCManager,
2565 LPWSTR lpServiceName,
2566 DWORD dwDesiredAccess,
2567 LPSC_RPC_HANDLE lpServiceHandle)
2568 {
2569 PSERVICE lpService;
2570 PMANAGER_HANDLE hManager;
2571 SC_HANDLE hHandle;
2572 DWORD dwError = ERROR_SUCCESS;
2573
2574 DPRINT("ROpenServiceW() called\n");
2575 DPRINT("hSCManager = %p\n", hSCManager);
2576 DPRINT("lpServiceName = %p\n", lpServiceName);
2577 DPRINT("lpServiceName: %S\n", lpServiceName);
2578 DPRINT("dwDesiredAccess = %x\n", dwDesiredAccess);
2579
2580 if (ScmShutdown)
2581 return ERROR_SHUTDOWN_IN_PROGRESS;
2582
2583 hManager = ScmGetServiceManagerFromHandle(hSCManager);
2584 if (hManager == NULL)
2585 {
2586 DPRINT1("Invalid service manager handle!\n");
2587 return ERROR_INVALID_HANDLE;
2588 }
2589
2590 if (!lpServiceHandle)
2591 return ERROR_INVALID_PARAMETER;
2592
2593 if (!lpServiceName)
2594 return ERROR_INVALID_ADDRESS;
2595
2596 /* Lock the service database exclusive */
2597 ScmLockDatabaseExclusive();
2598
2599 /* Get service database entry */
2600 lpService = ScmGetServiceEntryByName(lpServiceName);
2601 if (lpService == NULL)
2602 {
2603 DPRINT("Could not find a service!\n");
2604 dwError = ERROR_SERVICE_DOES_NOT_EXIST;
2605 goto Done;
2606 }
2607
2608 /* Create a service handle */
2609 dwError = ScmCreateServiceHandle(lpService,
2610 &hHandle);
2611 if (dwError != ERROR_SUCCESS)
2612 {
2613 DPRINT("ScmCreateServiceHandle() failed (Error %lu)\n", dwError);
2614 goto Done;
2615 }
2616
2617 /* Check the desired access */
2618 dwError = ScmCheckAccess(hHandle,
2619 dwDesiredAccess);
2620 if (dwError != ERROR_SUCCESS)
2621 {
2622 DPRINT("ScmCheckAccess() failed (Error %lu)\n", dwError);
2623 HeapFree(GetProcessHeap(), 0, hHandle);
2624 goto Done;
2625 }
2626
2627 lpService->dwRefCount++;
2628 DPRINT("OpenService - lpService->dwRefCount %u\n",lpService->dwRefCount);
2629
2630 *lpServiceHandle = (SC_RPC_HANDLE)hHandle;
2631 DPRINT("*hService = %p\n", *lpServiceHandle);
2632
2633 Done:
2634 /* Unlock the service database */
2635 ScmUnlockDatabase();
2636
2637 DPRINT("ROpenServiceW() done\n");
2638
2639 return dwError;
2640 }
2641
2642
2643 /* Function 17 */
2644 DWORD RQueryServiceConfigW(
2645 SC_RPC_HANDLE hService,
2646 LPBYTE lpBuf, //LPQUERY_SERVICE_CONFIGW lpServiceConfig,
2647 DWORD cbBufSize,
2648 LPBOUNDED_DWORD_8K pcbBytesNeeded)
2649 {
2650 LPQUERY_SERVICE_CONFIGW lpServiceConfig = (LPQUERY_SERVICE_CONFIGW)lpBuf;
2651 DWORD dwError = ERROR_SUCCESS;
2652 PSERVICE_HANDLE hSvc;
2653 PSERVICE lpService = NULL;
2654 HKEY hServiceKey = NULL;
2655 LPWSTR lpImagePath = NULL;
2656 LPWSTR lpServiceStartName = NULL;
2657 LPWSTR lpDependencies = NULL;
2658 DWORD dwDependenciesLength = 0;
2659 DWORD dwRequiredSize;
2660 WCHAR lpEmptyString[] = {0,0};
2661 LPWSTR lpStr;
2662
2663 DPRINT("RQueryServiceConfigW() called\n");
2664
2665 if (ScmShutdown)
2666 return ERROR_SHUTDOWN_IN_PROGRESS;
2667
2668 hSvc = ScmGetServiceFromHandle(hService);
2669 if (hSvc == NULL)
2670 {
2671 DPRINT1("Invalid service handle!\n");
2672 return ERROR_INVALID_HANDLE;
2673 }
2674
2675 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2676 SERVICE_QUERY_CONFIG))
2677 {
2678 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2679 return ERROR_ACCESS_DENIED;
2680 }
2681
2682 lpService = hSvc->ServiceEntry;
2683 if (lpService == NULL)
2684 {
2685 DPRINT("lpService == NULL!\n");
2686 return ERROR_INVALID_HANDLE;
2687 }
2688
2689 /* Lock the service database shared */
2690 ScmLockDatabaseShared();
2691
2692 dwError = ScmOpenServiceKey(lpService->lpServiceName,
2693 KEY_READ,
2694 &hServiceKey);
2695 if (dwError != ERROR_SUCCESS)
2696 goto Done;
2697
2698 /* Read the image path */
2699 dwError = ScmReadString(hServiceKey,
2700 L"ImagePath",
2701 &lpImagePath);
2702 if (dwError != ERROR_SUCCESS)
2703 goto Done;
2704
2705 /* Read the service start name */
2706 ScmReadString(hServiceKey,
2707 L"ObjectName",
2708 &lpServiceStartName);
2709
2710 /* Read the dependencies */
2711 ScmReadDependencies(hServiceKey,
2712 &lpDependencies,
2713 &dwDependenciesLength);
2714
2715 dwRequiredSize = sizeof(QUERY_SERVICE_CONFIGW);
2716
2717 if (lpImagePath != NULL)
2718 dwRequiredSize += (DWORD)((wcslen(lpImagePath) + 1) * sizeof(WCHAR));
2719 else
2720 dwRequiredSize += 2 * sizeof(WCHAR);
2721
2722 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2723 dwRequiredSize += (DWORD)((wcslen(lpService->lpGroup->lpGroupName) + 1) * sizeof(WCHAR));
2724 else
2725 dwRequiredSize += 2 * sizeof(WCHAR);
2726
2727 if (lpDependencies != NULL)
2728 dwRequiredSize += dwDependenciesLength * sizeof(WCHAR);
2729 else
2730 dwRequiredSize += 2 * sizeof(WCHAR);
2731
2732 if (lpServiceStartName != NULL)
2733 dwRequiredSize += (DWORD)((wcslen(lpServiceStartName) + 1) * sizeof(WCHAR));
2734 else
2735 dwRequiredSize += 2 * sizeof(WCHAR);
2736
2737 if (lpService->lpDisplayName != NULL)
2738 dwRequiredSize += (DWORD)((wcslen(lpService->lpDisplayName) + 1) * sizeof(WCHAR));
2739 else
2740 dwRequiredSize += 2 * sizeof(WCHAR);
2741
2742 if (lpServiceConfig == NULL || cbBufSize < dwRequiredSize)
2743 {
2744 dwError = ERROR_INSUFFICIENT_BUFFER;
2745 }
2746 else
2747 {
2748 lpServiceConfig->dwServiceType = lpService->Status.dwServiceType;
2749 lpServiceConfig->dwStartType = lpService->dwStartType;
2750 lpServiceConfig->dwErrorControl = lpService->dwErrorControl;
2751 lpServiceConfig->dwTagId = lpService->dwTag;
2752
2753 lpStr = (LPWSTR)(lpServiceConfig + 1);
2754
2755 /* Append the image path */
2756 if (lpImagePath != NULL)
2757 {
2758 wcscpy(lpStr, lpImagePath);
2759 }
2760 else
2761 {
2762 wcscpy(lpStr, lpEmptyString);
2763 }
2764
2765 lpServiceConfig->lpBinaryPathName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2766 lpStr += (wcslen(lpStr) + 1);
2767
2768 /* Append the group name */
2769 if ((lpService->lpGroup != NULL) && (lpService->lpGroup->lpGroupName != NULL))
2770 {
2771 wcscpy(lpStr, lpService->lpGroup->lpGroupName);
2772 }
2773 else
2774 {
2775 wcscpy(lpStr, lpEmptyString);
2776 }
2777
2778 lpServiceConfig->lpLoadOrderGroup = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2779 lpStr += (wcslen(lpStr) + 1);
2780
2781 /* Append Dependencies */
2782 if (lpDependencies != NULL)
2783 {
2784 memcpy(lpStr,
2785 lpDependencies,
2786 dwDependenciesLength * sizeof(WCHAR));
2787 }
2788 else
2789 {
2790 wcscpy(lpStr, lpEmptyString);
2791 }
2792
2793 lpServiceConfig->lpDependencies = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2794 if (lpDependencies != NULL)
2795 lpStr += dwDependenciesLength;
2796 else
2797 lpStr += (wcslen(lpStr) + 1);
2798
2799 /* Append the service start name */
2800 if (lpServiceStartName != NULL)
2801 {
2802 wcscpy(lpStr, lpServiceStartName);
2803 }
2804 else
2805 {
2806 wcscpy(lpStr, lpEmptyString);
2807 }
2808
2809 lpServiceConfig->lpServiceStartName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2810 lpStr += (wcslen(lpStr) + 1);
2811
2812 /* Append the display name */
2813 if (lpService->lpDisplayName != NULL)
2814 {
2815 wcscpy(lpStr, lpService->lpDisplayName);
2816 }
2817 else
2818 {
2819 wcscpy(lpStr, lpEmptyString);
2820 }
2821
2822 lpServiceConfig->lpDisplayName = (LPWSTR)((ULONG_PTR)lpStr - (ULONG_PTR)lpServiceConfig);
2823 }
2824
2825 if (pcbBytesNeeded != NULL)
2826 *pcbBytesNeeded = dwRequiredSize;
2827
2828 Done:
2829 /* Unlock the service database */
2830 ScmUnlockDatabase();
2831
2832 if (lpImagePath != NULL)
2833 HeapFree(GetProcessHeap(), 0, lpImagePath);
2834
2835 if (lpServiceStartName != NULL)
2836 HeapFree(GetProcessHeap(), 0, lpServiceStartName);
2837
2838 if (lpDependencies != NULL)
2839 HeapFree(GetProcessHeap(), 0, lpDependencies);
2840
2841 if (hServiceKey != NULL)
2842 RegCloseKey(hServiceKey);
2843
2844 DPRINT("RQueryServiceConfigW() done\n");
2845
2846 return dwError;
2847 }
2848
2849
2850 /* Function 18 */
2851 DWORD RQueryServiceLockStatusW(
2852 SC_RPC_HANDLE hSCManager,
2853 LPBYTE lpBuf, // LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus,
2854 DWORD cbBufSize,
2855 LPBOUNDED_DWORD_4K pcbBytesNeeded)
2856 {
2857 LPQUERY_SERVICE_LOCK_STATUSW lpLockStatus = (LPQUERY_SERVICE_LOCK_STATUSW)lpBuf;
2858 PMANAGER_HANDLE hMgr;
2859 DWORD dwRequiredSize;
2860
2861 if (!lpLockStatus || !pcbBytesNeeded)
2862 return ERROR_INVALID_PARAMETER;
2863
2864 hMgr = ScmGetServiceManagerFromHandle(hSCManager);
2865 if (hMgr == NULL)
2866 {
2867 DPRINT1("Invalid service manager handle!\n");
2868 return ERROR_INVALID_HANDLE;
2869 }
2870
2871 if (!RtlAreAllAccessesGranted(hMgr->Handle.DesiredAccess,
2872 SC_MANAGER_QUERY_LOCK_STATUS))
2873 {
2874 DPRINT("Insufficient access rights! 0x%lx\n", hMgr->Handle.DesiredAccess);
2875 return ERROR_ACCESS_DENIED;
2876 }
2877
2878 /* FIXME: we need to compute instead the real length of the owner name */
2879 dwRequiredSize = sizeof(QUERY_SERVICE_LOCK_STATUSW) + sizeof(WCHAR);
2880 *pcbBytesNeeded = dwRequiredSize;
2881
2882 if (cbBufSize < dwRequiredSize)
2883 return ERROR_INSUFFICIENT_BUFFER;
2884
2885 ScmQueryServiceLockStatusW(lpLockStatus);
2886
2887 return ERROR_SUCCESS;
2888 }
2889
2890
2891 /* Function 19 */
2892 DWORD RStartServiceW(
2893 SC_RPC_HANDLE hService,
2894 DWORD argc,
2895 LPSTRING_PTRSW argv)
2896 {
2897 DWORD dwError = ERROR_SUCCESS;
2898 PSERVICE_HANDLE hSvc;
2899 PSERVICE lpService = NULL;
2900
2901 #ifndef NDEBUG
2902 DWORD i;
2903
2904 DPRINT("RStartServiceW(%p %lu %p) called\n", hService, argc, argv);
2905 DPRINT(" argc: %lu\n", argc);
2906 if (argv != NULL)
2907 {
2908 for (i = 0; i < argc; i++)
2909 {
2910 DPRINT(" argv[%lu]: %S\n", i, argv[i].StringPtr);
2911 }
2912 }
2913 #endif
2914
2915 if (ScmShutdown)
2916 return ERROR_SHUTDOWN_IN_PROGRESS;
2917
2918 hSvc = ScmGetServiceFromHandle(hService);
2919 if (hSvc == NULL)
2920 {
2921 DPRINT1("Invalid service handle!\n");
2922 return ERROR_INVALID_HANDLE;
2923 }
2924
2925 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
2926 SERVICE_START))
2927 {
2928 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
2929 return ERROR_ACCESS_DENIED;
2930 }
2931
2932 lpService = hSvc->ServiceEntry;
2933 if (lpService == NULL)
2934 {
2935 DPRINT("lpService == NULL!\n");
2936 return ERROR_INVALID_HANDLE;
2937 }
2938
2939 if (lpService->dwStartType == SERVICE_DISABLED)
2940 return ERROR_SERVICE_DISABLED;
2941
2942 if (lpService->bDeleted)
2943 return ERROR_SERVICE_MARKED_FOR_DELETE;
2944
2945 /* Start the service */
2946 dwError = ScmStartService(lpService, argc, (LPWSTR*)argv);
2947
2948 return dwError;
2949 }
2950
2951
2952 /* Function 20 */
2953 DWORD RGetServiceDisplayNameW(
2954 SC_RPC_HANDLE hSCManager,
2955 LPCWSTR lpServiceName,
2956 LPWSTR lpDisplayName,
2957 DWORD *lpcchBuffer)
2958 {
2959 // PMANAGER_HANDLE hManager;
2960 PSERVICE lpService;
2961 DWORD dwLength;
2962 DWORD dwError;
2963
2964 DPRINT("RGetServiceDisplayNameW() called\n");
2965 DPRINT("hSCManager = %p\n", hSCManager);
2966 DPRINT("lpServiceName: %S\n", lpServiceName);
2967 DPRINT("lpDisplayName: %p\n", lpDisplayName);
2968 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
2969
2970 // hManager = (PMANAGER_HANDLE)hSCManager;
2971 // if (hManager->Handle.Tag != MANAGER_TAG)
2972 // {
2973 // DPRINT("Invalid manager handle!\n");
2974 // return ERROR_INVALID_HANDLE;
2975 // }
2976
2977 /* Get service database entry */
2978 lpService = ScmGetServiceEntryByName(lpServiceName);
2979 if (lpService == NULL)
2980 {
2981 DPRINT("Could not find a service!\n");
2982
2983 /* If the service could not be found and lpcchBuffer is less than 2, windows
2984 puts null in lpDisplayName and puts 2 in lpcchBuffer */
2985 if (*lpcchBuffer < 2)
2986 {
2987 *lpcchBuffer = 2;
2988 if (lpDisplayName != NULL)
2989 {
2990 *lpDisplayName = 0;
2991 }
2992 }
2993
2994 return ERROR_SERVICE_DOES_NOT_EXIST;
2995 }
2996
2997 if (!lpService->lpDisplayName)
2998 {
2999 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3000
3001 if (lpDisplayName != NULL &&
3002 *lpcchBuffer > dwLength)
3003 {
3004 wcscpy(lpDisplayName, lpService->lpServiceName);
3005 }
3006 }
3007 else
3008 {
3009 dwLength = (DWORD)wcslen(lpService->lpDisplayName);
3010
3011 if (lpDisplayName != NULL &&
3012 *lpcchBuffer > dwLength)
3013 {
3014 wcscpy(lpDisplayName, lpService->lpDisplayName);
3015 }
3016 }
3017
3018 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3019
3020 *lpcchBuffer = dwLength;
3021
3022 return dwError;
3023 }
3024
3025
3026 /* Function 21 */
3027 DWORD RGetServiceKeyNameW(
3028 SC_RPC_HANDLE hSCManager,
3029 LPCWSTR lpDisplayName,
3030 LPWSTR lpServiceName,
3031 DWORD *lpcchBuffer)
3032 {
3033 // PMANAGER_HANDLE hManager;
3034 PSERVICE lpService;
3035 DWORD dwLength;
3036 DWORD dwError;
3037
3038 DPRINT("RGetServiceKeyNameW() called\n");
3039 DPRINT("hSCManager = %p\n", hSCManager);
3040 DPRINT("lpDisplayName: %S\n", lpDisplayName);
3041 DPRINT("lpServiceName: %p\n", lpServiceName);
3042 DPRINT("*lpcchBuffer: %lu\n", *lpcchBuffer);
3043
3044 // hManager = (PMANAGER_HANDLE)hSCManager;
3045 // if (hManager->Handle.Tag != MANAGER_TAG)
3046 // {
3047 // DPRINT("Invalid manager handle!\n");
3048 // return ERROR_INVALID_HANDLE;
3049 // }
3050
3051 /* Get service database entry */
3052 lpService = ScmGetServiceEntryByDisplayName(lpDisplayName);
3053 if (lpService == NULL)
3054 {
3055 DPRINT("Could not find a service!\n");
3056
3057 /* If the service could not be found and lpcchBuffer is less than 2, windows
3058 puts null in lpDisplayName and puts 2 in lpcchBuffer */
3059 if (*lpcchBuffer < 2)
3060 {
3061 *lpcchBuffer = 2;
3062 if (lpServiceName != NULL)
3063 {
3064 *lpServiceName = 0;
3065 }
3066 }
3067
3068 return ERROR_SERVICE_DOES_NOT_EXIST;
3069 }
3070
3071 dwLength = (DWORD)wcslen(lpService->lpServiceName);
3072
3073 if (lpServiceName != NULL &&
3074 *lpcchBuffer > dwLength)
3075 {
3076 wcscpy(lpServiceName, lpService->lpServiceName);
3077 *lpcchBuffer = dwLength;
3078 return ERROR_SUCCESS;
3079 }
3080
3081 dwError = (*lpcchBuffer > dwLength) ? ERROR_SUCCESS : ERROR_INSUFFICIENT_BUFFER;
3082
3083 *lpcchBuffer = dwLength;
3084
3085 return dwError;
3086 }
3087
3088
3089 /* Function 22 */
3090 DWORD RI_ScSetServiceBitsA(
3091 RPC_SERVICE_STATUS_HANDLE hServiceStatus,
3092 DWORD dwServiceBits,
3093 int bSetBitsOn,
3094 int bUpdateImmediately,
3095 char *lpString)
3096 {
3097 UNIMPLEMENTED;
3098 return ERROR_CALL_NOT_IMPLEMENTED;
3099 }
3100
3101
3102 /* Function 23 */
3103 DWORD RChangeServiceConfigA(
3104 SC_RPC_HANDLE hService,
3105 DWORD dwServiceType,
3106 DWORD dwStartType,
3107 DWORD dwErrorControl,
3108 LPSTR lpBinaryPathName,
3109 LPSTR lpLoadOrderGroup,
3110 LPDWORD lpdwTagId,
3111 LPBYTE lpDependencies,
3112 DWORD dwDependSize,
3113 LPSTR lpServiceStartName,
3114 LPBYTE lpPassword,
3115 DWORD dwPwSize,
3116 LPSTR lpDisplayName)
3117 {
3118 DWORD dwError = ERROR_SUCCESS;
3119 PSERVICE_HANDLE hSvc;
3120 PSERVICE lpService = NULL;
3121 HKEY hServiceKey = NULL;
3122 LPWSTR lpDisplayNameW = NULL;
3123 LPWSTR lpBinaryPathNameW = NULL;
3124 LPWSTR lpCanonicalImagePathW = NULL;
3125 LPWSTR lpLoadOrderGroupW = NULL;
3126 LPWSTR lpDependenciesW = NULL;
3127
3128 DPRINT("RChangeServiceConfigA() called\n");
3129 DPRINT("dwServiceType = %lu\n", dwServiceType);
3130 DPRINT("dwStartType = %lu\n", dwStartType);
3131 DPRINT("dwErrorControl = %lu\n", dwErrorControl);
3132 DPRINT("lpBinaryPathName = %s\n", lpBinaryPathName);
3133 DPRINT("lpLoadOrderGroup = %s\n", lpLoadOrderGroup);
3134 DPRINT("lpDisplayName = %s\n", lpDisplayName);
3135
3136 if (ScmShutdown)
3137 return ERROR_SHUTDOWN_IN_PROGRESS;
3138
3139 hSvc = ScmGetServiceFromHandle(hService);
3140 if (hSvc == NULL)
3141 {
3142 DPRINT1("Invalid service handle!\n");
3143 return ERROR_INVALID_HANDLE;
3144 }
3145
3146 if (!RtlAreAllAccessesGranted(hSvc->Handle.DesiredAccess,
3147 SERVICE_CHANGE_CONFIG))
3148 {
3149 DPRINT("Insufficient access rights! 0x%lx\n", hSvc->Handle.DesiredAccess);
3150 return ERROR_ACCESS_DENIED;
3151 }
3152
3153 lpService = hSvc->ServiceEntry;
3154 if (lpService == NULL)
3155 {
3156 DPRINT("lpService == NULL!\n");
3157 return ERROR_INVALID_HANDLE;
3158 }
3159
3160 /* Lock the service database exclusively */
3161 ScmLockDatabaseExclusive();
3162
3163 if (lpService->bDeleted)
3164 {
3165 DPRINT("The service has already been marked for delete!\n");
3166 dwError = ERROR_SERVICE_MARKED_FOR_DELETE;
3167 goto done;
3168 }
3169
3170 /* Open the service key */
3171 dwError = ScmOpenServiceKey(lpService->szServiceName,
3172 KEY_SET_VALUE,
3173 &hServiceKey);
3174 if (dwError != ERROR_SUCCESS)
3175 goto done;
3176
3177 /* Write service data to the registry */
3178
3179 if (lpDisplayName != NULL && *lpDisplayName != 0)
3180 {
3181 /* Set the display name */
3182 lpDisplayNameW = HeapAlloc(GetProcessHeap(),
3183 HEAP_ZERO_MEMORY,
3184 (strlen(lpDisplayName) + 1) * sizeof(WCHAR));
3185 if (lpDisplayNameW == NULL)
3186 {
3187 dwError = ERROR_NOT_ENOUGH_MEMORY;
3188 goto done;
3189 }
3190
3191 MultiByteToWideChar(CP_ACP,
3192 0,
3193 lpDisplayName,
3194 -1,
3195 lpDisplayNameW,
3196 (int)(strlen(lpDisplayName) + 1));
3197
3198 RegSetValueExW(hServiceKey,
3199 L"DisplayName",
3200 0,
3201 REG_SZ,
3202 (LPBYTE)lpDisplayNameW,
3203 (DWORD)((wcslen(lpDisplayNameW) + 1) * sizeof(WCHAR)));
3204
3205 /* Update lpService->lpDisplayName */
3206 if (lpService->lpDisplayName)
3207 HeapFree(GetProcessHeap(), 0, lpService->lpDisplayName);
3208
3209 lpService->lpDisplayName = lpDisplayNameW;
3210 }
3211
3212 if (dwServiceType != SERVICE_NO_CHANGE)
3213 {
3214 /* Set the service type */
3215 dwError = RegSetValueExW(hServiceKey,
3216 L"Type",
3217 0,
3218 REG_DWORD,
3219 (LPBYTE)&dwServiceType,
3220 sizeof(DWORD));
3221 if (dwError != ERROR_SUCCESS)
3222 goto done;
3223
3224 lpService->Status.dwServiceType = dwServiceType;
3225 }
3226
3227 if (dwStartType != SERVICE_NO_CHANGE)
3228 {
3229 /* Set the start value */
3230 dwError = RegSetValueExW(hServiceKey,
3231 L"Start",
3232 0,
3233 REG_DWORD,
3234 (LPBYTE)&dwStartType,
3235 sizeof(DWORD));
3236 if (dwError != ERROR_SUCCESS)
3237 goto done;
3238
3239 lpService->dwStartType = dwStartType;
3240 }
3241
3242 if (dwErrorControl != SERVICE_NO_CHANGE)
3243 {
3244 /* Set the error control value */
3245 dwError = RegSetValueExW(hServiceKey,
3246 L"ErrorControl",
3247 0,
3248 REG_DWORD,
3249 (LPBYTE)&dwErrorControl,
3250 sizeof(DWORD));
3251 if (dwError != ERROR_SUCCESS)
3252 goto done;
3253
3254 lpService->dwErrorControl = dwErrorControl;
3255 }
3256
3257 if (lpBinaryPathName != NULL && *lpBinaryPathName != 0)
3258 {
3259 /* Set the image path */
3260 lpBinaryPathNameW = HeapAlloc(GetProcessHeap(),
3261 HEAP_ZERO_MEMORY,
3262 (strlen(lpBinaryPathName) + 1) * sizeof(WCHAR));
3263 if (lpBinaryPathNameW == NULL)
3264 {
3265 dwError = ERROR_NOT_ENOUGH_MEMORY;
3266 goto done;
3267 }
3268