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