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