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