📄 database.c
字号:
/*
*
* service control manager
*
* ReactOS Operating System
*
* --------------------------------------------------------------------
*
* This software is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this software; see the file COPYING.LIB. If not, write
* to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge,
* MA 02139, USA.
*
*/
/* INCLUDES *****************************************************************/
#include "services.h"
#define NDEBUG
#include <debug.h>
/* GLOBALS *******************************************************************/
LIST_ENTRY ServiceListHead;
static RTL_RESOURCE DatabaseLock;
static DWORD dwResumeCount = 1;
/* FUNCTIONS *****************************************************************/
PSERVICE
ScmGetServiceEntryByName(LPWSTR lpServiceName)
{
PLIST_ENTRY ServiceEntry;
PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByName() called\n");
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
CurrentService = CONTAINING_RECORD(ServiceEntry,
SERVICE,
ServiceListEntry);
if (_wcsicmp(CurrentService->lpServiceName, lpServiceName) == 0)
{
DPRINT("Found service: '%S'\n", CurrentService->lpServiceName);
return CurrentService;
}
ServiceEntry = ServiceEntry->Flink;
}
DPRINT("Couldn't find a matching service\n");
return NULL;
}
PSERVICE
ScmGetServiceEntryByDisplayName(LPWSTR lpDisplayName)
{
PLIST_ENTRY ServiceEntry;
PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByDisplayName() called\n");
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
CurrentService = CONTAINING_RECORD(ServiceEntry,
SERVICE,
ServiceListEntry);
if (_wcsicmp(CurrentService->lpDisplayName, lpDisplayName) == 0)
{
DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
return CurrentService;
}
ServiceEntry = ServiceEntry->Flink;
}
DPRINT("Couldn't find a matching service\n");
return NULL;
}
PSERVICE
ScmGetServiceEntryByResumeCount(DWORD dwResumeCount)
{
PLIST_ENTRY ServiceEntry;
PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByResumeCount() called\n");
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
CurrentService = CONTAINING_RECORD(ServiceEntry,
SERVICE,
ServiceListEntry);
if (CurrentService->dwResumeCount > dwResumeCount)
{
DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
return CurrentService;
}
ServiceEntry = ServiceEntry->Flink;
}
DPRINT("Couldn't find a matching service\n");
return NULL;
}
PSERVICE
ScmGetServiceEntryByThreadId(ULONG ThreadId)
{
PLIST_ENTRY ServiceEntry;
PSERVICE CurrentService;
DPRINT("ScmGetServiceEntryByThreadId() called\n");
DPRINT("Finding ThreadId %lu\n", ThreadId);
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
CurrentService = CONTAINING_RECORD(ServiceEntry,
SERVICE,
ServiceListEntry);
DPRINT("Found threadId %lu\n", CurrentService->ThreadId);
if (CurrentService->ThreadId == ThreadId)
{
DPRINT("Found service: '%S'\n", CurrentService->lpDisplayName);
return CurrentService;
}
ServiceEntry = ServiceEntry->Flink;
}
DPRINT("Couldn't find a matching service\n");
return NULL;
}
DWORD
ScmCreateNewServiceRecord(LPWSTR lpServiceName,
PSERVICE *lpServiceRecord)
{
PSERVICE lpService = NULL;
DPRINT("Service: '%S'\n", lpServiceName);
/* Allocate service entry */
lpService = (SERVICE*) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(SERVICE) + ((wcslen(lpServiceName) + 1) * sizeof(WCHAR)));
if (lpService == NULL)
return ERROR_NOT_ENOUGH_MEMORY;
*lpServiceRecord = lpService;
/* Copy service name */
wcscpy(lpService->szServiceName, lpServiceName);
lpService->lpServiceName = lpService->szServiceName;
lpService->lpDisplayName = lpService->lpServiceName;
/* Set the resume count */
lpService->dwResumeCount = dwResumeCount++;
/* Append service entry */
InsertTailList(&ServiceListHead,
&lpService->ServiceListEntry);
lpService->Status.dwCurrentState = SERVICE_STOPPED;
lpService->Status.dwControlsAccepted = 0;
lpService->Status.dwWin32ExitCode = ERROR_SERVICE_NEVER_STARTED;
lpService->Status.dwServiceSpecificExitCode = 0;
lpService->Status.dwCheckPoint = 0;
lpService->Status.dwWaitHint = 2000; /* 2 seconds */
return ERROR_SUCCESS;
}
static DWORD
CreateServiceListEntry(LPWSTR lpServiceName,
HKEY hServiceKey)
{
PSERVICE lpService = NULL;
LPWSTR lpDisplayName = NULL;
LPWSTR lpGroup = NULL;
DWORD dwSize;
DWORD dwError;
DWORD dwServiceType;
DWORD dwStartType;
DWORD dwErrorControl;
DWORD dwTagId;
DPRINT("Service: '%S'\n", lpServiceName);
if (*lpServiceName == L'{')
return ERROR_SUCCESS;
dwSize = sizeof(DWORD);
dwError = RegQueryValueExW(hServiceKey,
L"Type",
NULL,
NULL,
(LPBYTE)&dwServiceType,
&dwSize);
if (dwError != ERROR_SUCCESS)
return ERROR_SUCCESS;
if (((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_OWN_PROCESS) &&
((dwServiceType & ~SERVICE_INTERACTIVE_PROCESS) != SERVICE_WIN32_SHARE_PROCESS) &&
(dwServiceType != SERVICE_KERNEL_DRIVER) &&
(dwServiceType != SERVICE_FILE_SYSTEM_DRIVER))
return ERROR_SUCCESS;
DPRINT("Service type: %lx\n", dwServiceType);
dwSize = sizeof(DWORD);
dwError = RegQueryValueExW(hServiceKey,
L"Start",
NULL,
NULL,
(LPBYTE)&dwStartType,
&dwSize);
if (dwError != ERROR_SUCCESS)
return ERROR_SUCCESS;
DPRINT("Start type: %lx\n", dwStartType);
dwSize = sizeof(DWORD);
dwError = RegQueryValueExW(hServiceKey,
L"ErrorControl",
NULL,
NULL,
(LPBYTE)&dwErrorControl,
&dwSize);
if (dwError != ERROR_SUCCESS)
return ERROR_SUCCESS;
DPRINT("Error control: %lx\n", dwErrorControl);
dwError = RegQueryValueExW(hServiceKey,
L"Tag",
NULL,
NULL,
(LPBYTE)&dwTagId,
&dwSize);
if (dwError != ERROR_SUCCESS)
dwTagId = 0;
DPRINT("Tag: %lx\n", dwTagId);
dwError = ScmReadString(hServiceKey,
L"Group",
&lpGroup);
if (dwError != ERROR_SUCCESS)
lpGroup = NULL;
DPRINT("Group: %S\n", lpGroup);
dwError = ScmReadString(hServiceKey,
L"DisplayName",
&lpDisplayName);
if (dwError != ERROR_SUCCESS)
lpDisplayName = NULL;
DPRINT("Display name: %S\n", lpDisplayName);
dwError = ScmCreateNewServiceRecord(lpServiceName,
&lpService);
if (dwError != ERROR_SUCCESS)
goto done;
lpService->Status.dwServiceType = dwServiceType;
lpService->dwStartType = dwStartType;
lpService->dwErrorControl = dwErrorControl;
lpService->dwTag = dwTagId;
if (lpGroup != NULL)
{
dwError = ScmSetServiceGroup(lpService, lpGroup);
if (dwError != ERROR_SUCCESS)
goto done;
}
if (lpDisplayName != NULL)
{
lpService->lpDisplayName = lpDisplayName;
lpDisplayName = NULL;
}
DPRINT("ServiceName: '%S'\n", lpService->lpServiceName);
if (lpService->lpGroup != NULL)
{
DPRINT("Group: '%S'\n", lpService->lpGroup->lpGroupName);
}
DPRINT("Start %lx Type %lx Tag %lx ErrorControl %lx\n",
lpService->dwStartType,
lpService->Status.dwServiceType,
lpService->dwTag,
lpService->dwErrorControl);
if (ScmIsDeleteFlagSet(hServiceKey))
lpService->bDeleted = TRUE;
done:;
if (lpGroup != NULL)
HeapFree(GetProcessHeap(), 0, lpGroup);
if (lpDisplayName != NULL)
HeapFree(GetProcessHeap(), 0, lpDisplayName);
return dwError;
}
VOID
ScmDeleteMarkedServices(VOID)
{
PLIST_ENTRY ServiceEntry;
PSERVICE CurrentService;
ServiceEntry = ServiceListHead.Flink;
while (ServiceEntry != &ServiceListHead)
{
CurrentService = CONTAINING_RECORD(ServiceEntry, SERVICE, ServiceListEntry);
ServiceEntry = ServiceEntry->Flink;
if (CurrentService->bDeleted == TRUE)
{
DPRINT1("Delete service: %S\n", CurrentService->lpServiceName);
/* FIXME: Delete the registry keys */
/* FIXME: Delete the service record from the list */
}
}
}
DWORD
ScmCreateServiceDatabase(VOID)
{
WCHAR szSubKey[MAX_PATH];
HKEY hServicesKey;
HKEY hServiceKey;
DWORD dwSubKey;
DWORD dwSubKeyLength;
FILETIME ftLastChanged;
DWORD dwError;
DPRINT("ScmCreateServiceDatabase() called\n");
dwError = ScmCreateGroupList();
if (dwError != ERROR_SUCCESS)
return dwError;
/* Initialize basic variables */
InitializeListHead(&ServiceListHead);
/* Initialize the database lock */
RtlInitializeResource(&DatabaseLock);
dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
L"System\\CurrentControlSet\\Services",
0,
KEY_READ,
&hServicesKey);
if (dwError != ERROR_SUCCESS)
return dwError;
dwSubKey = 0;
for (;;)
{
dwSubKeyLength = MAX_PATH;
dwError = RegEnumKeyExW(hServicesKey,
dwSubKey,
szSubKey,
&dwSubKeyLength,
NULL,
NULL,
NULL,
&ftLastChanged);
if (dwError == ERROR_SUCCESS &&
szSubKey[0] != L'{')
{
DPRINT("SubKeyName: '%S'\n", szSubKey);
dwError = RegOpenKeyExW(hServicesKey,
szSubKey,
0,
KEY_READ,
&hServiceKey);
if (dwError == ERROR_SUCCESS)
{
dwError = CreateServiceListEntry(szSubKey,
hServiceKey);
RegCloseKey(hServiceKey);
}
}
if (dwError != ERROR_SUCCESS)
break;
dwSubKey++;
}
RegCloseKey(hServicesKey);
/* Delete services that are marked for delete */
ScmDeleteMarkedServices();
DPRINT("ScmCreateServiceDatabase() done\n");
return ERROR_SUCCESS;
}
static NTSTATUS
ScmCheckDriver(PSERVICE Service)
{
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING DirName;
HANDLE DirHandle;
NTSTATUS Status;
POBJECT_DIRECTORY_INFORMATION DirInfo;
ULONG BufferLength;
ULONG DataLength;
ULONG Index;
DPRINT("ScmCheckDriver(%S) called\n", Service->lpServiceName);
if (Service->Status.dwServiceType == SERVICE_KERNEL_DRIVER)
{
RtlInitUnicodeString(&DirName,
L"\\Driver");
}
else
{
RtlInitUnicodeString(&DirName,
L"\\FileSystem");
}
InitializeObjectAttributes(&ObjectAttributes,
&DirName,
0,
NULL,
NULL);
Status = NtOpenDirectoryObject(&DirHandle,
DIRECTORY_QUERY | DIRECTORY_TRAVERSE,
&ObjectAttributes);
if (!NT_SUCCESS(Status))
{
return Status;
}
BufferLength = sizeof(OBJECT_DIRECTORY_INFORMATION) +
2 * MAX_PATH * sizeof(WCHAR);
DirInfo = (OBJECT_DIRECTORY_INFORMATION*) HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY,
BufferLength);
Index = 0;
while (TRUE)
{
Status = NtQueryDirectoryObject(DirHandle,
DirInfo,
BufferLength,
TRUE,
FALSE,
&Index,
&DataLength);
if (Status == STATUS_NO_MORE_ENTRIES)
{
/* FIXME: Add current service to 'failed service' list */
DPRINT("Service '%S' failed\n", Service->lpServiceName);
break;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -