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