335 lines
8.5 KiB
C
335 lines
8.5 KiB
C
|
#include "spprecmp.h"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpDeleteServiceEntry(
|
||
|
IN PWCHAR ServiceKey
|
||
|
)
|
||
|
{
|
||
|
NTSTATUS Status;
|
||
|
HANDLE KeyHandle;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
OBJECT_ATTRIBUTES Obja;
|
||
|
|
||
|
RtlInitUnicodeString(&UnicodeString,ServiceKey);
|
||
|
InitializeObjectAttributes(&Obja,&UnicodeString,OBJ_CASE_INSENSITIVE,NULL,NULL);
|
||
|
Status = ZwOpenKey(&KeyHandle,KEY_WRITE|DELETE,&Obja);
|
||
|
|
||
|
if(NT_SUCCESS(Status)) {
|
||
|
Status = ZwDeleteKey(KeyHandle);
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: warning: ZwDeleteKey of %ws returned %lx\n",ServiceKey,Status));
|
||
|
}
|
||
|
} else {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: warning: ZwOpenKey of %ws returned %lx\n",ServiceKey,Status));
|
||
|
}
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpCreateServiceEntry(
|
||
|
IN PWCHAR ImagePath,
|
||
|
IN OUT PWCHAR *ServiceKey
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Create an services entry in the registry suitable for loading
|
||
|
a given device driver file.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
ImagePath - supplies the fully-qualified pathname of the device driver.
|
||
|
|
||
|
ServiceKey - If *ServiceKey is not NULL, then it specifies the registry
|
||
|
path to the service node for this driver. If it is NULL, then it
|
||
|
receives a pointer to a buffer containing the name of the
|
||
|
service node created by this routine. The caller must free this
|
||
|
buffer via SpMemFree when finished.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status code indicating outcome.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
WCHAR KeyName[128];
|
||
|
WCHAR FilePart[32];
|
||
|
OBJECT_ATTRIBUTES Obja;
|
||
|
UNICODE_STRING UnicodeString;
|
||
|
HANDLE KeyHandle;
|
||
|
ULONG u;
|
||
|
NTSTATUS Status;
|
||
|
PWSTR p;
|
||
|
BYTE DataBuffer[sizeof(KEY_VALUE_PARTIAL_INFORMATION) + sizeof(DWORD)];
|
||
|
ULONG ResultLength;
|
||
|
|
||
|
if (*ServiceKey) {
|
||
|
wcscpy(KeyName, *ServiceKey);
|
||
|
} else {
|
||
|
//
|
||
|
// Isolate the name of the device driver file from its path.
|
||
|
//
|
||
|
if(p = wcsrchr(ImagePath,L'\\')) {
|
||
|
p++;
|
||
|
} else {
|
||
|
p = ImagePath;
|
||
|
}
|
||
|
wcsncpy(FilePart,p,(sizeof(FilePart)/sizeof(FilePart[0]))-1);
|
||
|
FilePart[(sizeof(FilePart)/sizeof(FilePart[0]))-1] = 0;
|
||
|
if(p=wcsrchr(FilePart,L'.')) {
|
||
|
*p = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Form a unique key name in
|
||
|
// HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services.
|
||
|
//
|
||
|
|
||
|
swprintf(
|
||
|
KeyName,
|
||
|
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\%ws",
|
||
|
FilePart
|
||
|
);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Attempt to create the key for the service.
|
||
|
//
|
||
|
RtlInitUnicodeString(&UnicodeString,KeyName);
|
||
|
InitializeObjectAttributes(&Obja,&UnicodeString,OBJ_CASE_INSENSITIVE,NULL,NULL);
|
||
|
|
||
|
Status = ZwCreateKey(
|
||
|
&KeyHandle,
|
||
|
KEY_READ | KEY_WRITE,
|
||
|
&Obja,
|
||
|
0,
|
||
|
NULL,
|
||
|
REG_OPTION_NON_VOLATILE,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: SpCreateServiceEntry: ZwCreateKey %ws returns %lx\n",KeyName,Status));
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
//
|
||
|
// Set the ImagePath value in the service key.
|
||
|
//
|
||
|
RtlInitUnicodeString(&UnicodeString,L"ImagePath");
|
||
|
Status = ZwSetValueKey(
|
||
|
KeyHandle,
|
||
|
&UnicodeString,
|
||
|
0,
|
||
|
REG_SZ,
|
||
|
ImagePath,
|
||
|
(wcslen(ImagePath) + 1) * sizeof(WCHAR)
|
||
|
);
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set ImagePath value in key %ws (%lx)\n",KeyName,Status));
|
||
|
goto cs1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the Type value in the service key. If the type is preset in the registry to SERVICE_FILE_SYSTEM_DRIVER
|
||
|
// leave it alone. Otherwise set it to SERVICE_KERNEL_DRIVER.
|
||
|
//
|
||
|
RtlInitUnicodeString(&UnicodeString, REGSTR_VALUE_TYPE);
|
||
|
|
||
|
ResultLength = 0;
|
||
|
Status = ZwQueryValueKey(KeyHandle,
|
||
|
&UnicodeString,
|
||
|
KeyValuePartialInformation,
|
||
|
(PKEY_VALUE_PARTIAL_INFORMATION)DataBuffer,
|
||
|
sizeof(DataBuffer),
|
||
|
&ResultLength);
|
||
|
|
||
|
if( NT_SUCCESS(Status) &&
|
||
|
ResultLength &&
|
||
|
( (INT) ( (PKEY_VALUE_PARTIAL_INFORMATION) DataBuffer)->Type == REG_DWORD ) &&
|
||
|
( (INT) *(( (PKEY_VALUE_PARTIAL_INFORMATION) DataBuffer)->Data) == SERVICE_FILE_SYSTEM_DRIVER ) ) {
|
||
|
|
||
|
u = SERVICE_FILE_SYSTEM_DRIVER;
|
||
|
}
|
||
|
else {
|
||
|
//
|
||
|
// If the type is not preset in the registry to SERVICE_FILE_SYSTEM_DRIVER set it to SERVICE_KERNEL_DRIVER by default.
|
||
|
//
|
||
|
u = SERVICE_KERNEL_DRIVER;
|
||
|
}
|
||
|
|
||
|
Status = ZwSetValueKey(
|
||
|
KeyHandle,
|
||
|
&UnicodeString,
|
||
|
0,
|
||
|
REG_DWORD,
|
||
|
&u,
|
||
|
sizeof(ULONG)
|
||
|
);
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set Type value in key %ws (%lx)\n",KeyName,Status));
|
||
|
goto cs1;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Set the Start value in the service key.
|
||
|
//
|
||
|
u = SERVICE_DEMAND_START;
|
||
|
RtlInitUnicodeString(&UnicodeString,L"Start");
|
||
|
Status = ZwSetValueKey(
|
||
|
KeyHandle,
|
||
|
&UnicodeString,
|
||
|
0,
|
||
|
REG_DWORD,
|
||
|
&u,
|
||
|
sizeof(ULONG)
|
||
|
);
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: Unable to set Start value in key %ws (%lx)\n",KeyName,Status));
|
||
|
goto cs1;
|
||
|
}
|
||
|
|
||
|
|
||
|
cs1:
|
||
|
|
||
|
//
|
||
|
// If we were not entirely successful creating the service,
|
||
|
// we'll want to clean it out here. Otherwise duplicate the KeyName
|
||
|
// string to return to the caller, if it was not passed in.
|
||
|
//
|
||
|
if(NT_SUCCESS(Status)) {
|
||
|
|
||
|
if (*ServiceKey == NULL) {
|
||
|
if((*ServiceKey = SpDupStringW(KeyName)) == NULL) {
|
||
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
|
||
|
NTSTATUS s;
|
||
|
|
||
|
//
|
||
|
// Remove the key we just created.
|
||
|
//
|
||
|
s = ZwDeleteKey(KeyHandle);
|
||
|
if(!NT_SUCCESS(s)) {
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: warning: ZwDeleteKey of %ws returned %lx\n",KeyName,s));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
NtClose(KeyHandle);
|
||
|
|
||
|
return(Status);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
NTSTATUS
|
||
|
SpLoadDeviceDriver(
|
||
|
IN PWSTR Description,
|
||
|
IN PWSTR PathPart1,
|
||
|
IN PWSTR PathPart2, OPTIONAL
|
||
|
IN PWSTR PathPart3 OPTIONAL
|
||
|
)
|
||
|
|
||
|
/*++
|
||
|
|
||
|
Routine Description:
|
||
|
|
||
|
Load a device driver by creating a services entry for the driver and
|
||
|
then calling the I/O subsystem.
|
||
|
|
||
|
Arguments:
|
||
|
|
||
|
Description - supplies a human-readable description of the driver
|
||
|
or hardware that the driver targets.
|
||
|
|
||
|
PathPart1 - supplies first part of full pathname to driver file.
|
||
|
|
||
|
PathPart2 - if specified, supplies the second part of the full pathname;
|
||
|
PathPart2 will be concatenated to PathPart1. If not specified,
|
||
|
then PathPart1 is the full path.
|
||
|
|
||
|
PathPart3 - if specified, supplies a third part of the full pathname;
|
||
|
PathPart3 will be concatenated to PathPart1 and PathPart2.
|
||
|
|
||
|
Return Value:
|
||
|
|
||
|
Status code indicating outcome.
|
||
|
|
||
|
--*/
|
||
|
|
||
|
{
|
||
|
PWCHAR FullName;
|
||
|
NTSTATUS Status;
|
||
|
PWCHAR ServiceKey;
|
||
|
UNICODE_STRING ServiceKeyU;
|
||
|
PWSTR pwstr;
|
||
|
|
||
|
SpDisplayStatusText(
|
||
|
SP_STAT_LOADING_DRIVER,
|
||
|
DEFAULT_STATUS_ATTRIBUTE,
|
||
|
Description
|
||
|
);
|
||
|
|
||
|
pwstr = TemporaryBuffer;
|
||
|
|
||
|
//
|
||
|
// Form the full name of the device driver file.
|
||
|
//
|
||
|
wcscpy(pwstr,PathPart1);
|
||
|
if(PathPart2) {
|
||
|
SpConcatenatePaths(pwstr,PathPart2);
|
||
|
}
|
||
|
if(PathPart3) {
|
||
|
SpConcatenatePaths(pwstr,PathPart3);
|
||
|
}
|
||
|
|
||
|
FullName = SpDupStringW(pwstr);
|
||
|
|
||
|
//
|
||
|
// Create a service entry for the driver.
|
||
|
//
|
||
|
ServiceKey = NULL;
|
||
|
Status = SpCreateServiceEntry(FullName,&ServiceKey);
|
||
|
if(NT_SUCCESS(Status)) {
|
||
|
|
||
|
RtlInitUnicodeString(&ServiceKeyU,ServiceKey);
|
||
|
|
||
|
//
|
||
|
// Attempt to load the driver.
|
||
|
//
|
||
|
Status = ZwLoadDriver(&ServiceKeyU);
|
||
|
if(!NT_SUCCESS(Status)) {
|
||
|
|
||
|
KdPrintEx((DPFLTR_SETUP_ID, DPFLTR_ERROR_LEVEL, "SETUP: ZwLoadDriver %ws returned %lx\n",FullName,Status));
|
||
|
|
||
|
//
|
||
|
// Remove the service entry we created in the registry.
|
||
|
//
|
||
|
SpDeleteServiceEntry(ServiceKey);
|
||
|
}
|
||
|
|
||
|
SpMemFree(ServiceKey);
|
||
|
}
|
||
|
|
||
|
SpMemFree(FullName);
|
||
|
|
||
|
return(Status);
|
||
|
}
|