#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)) { KdPrint(("SETUP: warning: ZwDeleteKey of %ws returned %lx\n",ServiceKey,Status)); } } else { KdPrint(("SETUP: warning: ZwOpenKey of %ws returned %lx\n",ServiceKey,Status)); } return(Status); } NTSTATUS SpCreateServiceEntry( IN PWCHAR ImagePath, 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 - 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; // // 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_VOLATILE, NULL ); if(!NT_SUCCESS(Status)) { KdPrint(("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)) { KdPrint(("SETUP: Unable to set ImagePath value in key %ws (%lx)\n",KeyName,Status)); goto cs1; } // // Set the Type value in the service key. // u = SERVICE_KERNEL_DRIVER; RtlInitUnicodeString(&UnicodeString,L"Type"); Status = ZwSetValueKey( KeyHandle, &UnicodeString, 0, REG_DWORD, &u, sizeof(ULONG) ); if(!NT_SUCCESS(Status)) { KdPrint(("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)) { KdPrint(("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(NT_SUCCESS(Status)) { 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)) { KdPrint(("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 = (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. // Status = SpCreateServiceEntry(FullName,&ServiceKey); if(NT_SUCCESS(Status)) { RtlInitUnicodeString(&ServiceKeyU,ServiceKey); // // Attempt to load the driver. // Status = ZwLoadDriver(&ServiceKeyU); if(!NT_SUCCESS(Status)) { KdPrint(("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); }