moel@236: /* moel@236: moel@344: This Source Code Form is subject to the terms of the Mozilla Public moel@344: License, v. 2.0. If a copy of the MPL was not distributed with this moel@344: file, You can obtain one at http://mozilla.org/MPL/2.0/. moel@236: moel@367: Copyright (C) 2010-2012 Michael Möller moel@344: moel@236: */ moel@236: moel@236: using System; moel@237: using System.IO; moel@236: using System.Runtime.InteropServices; moel@237: using System.Security.AccessControl; moel@236: using Microsoft.Win32.SafeHandles; moel@236: moel@236: namespace OpenHardwareMonitor.Hardware { moel@236: internal class KernelDriver { moel@236: moel@236: private string id; moel@236: moel@236: private SafeFileHandle device; moel@236: moel@236: public KernelDriver(string id) { moel@236: this.id = id; moel@236: } moel@236: moel@367: public bool Install(string path, out string errorMessage) { moel@236: IntPtr manager = NativeMethods.OpenSCManager(null, null, moel@236: ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS); moel@236: moel@367: if (manager == IntPtr.Zero) { moel@367: errorMessage = "OpenSCManager returned zero."; moel@236: return false; moel@367: } moel@236: moel@236: IntPtr service = NativeMethods.CreateService(manager, id, id, moel@236: ServiceAccessRights.SERVICE_ALL_ACCESS, moel@236: ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START, moel@236: ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null, moel@236: null); moel@236: moel@236: if (service == IntPtr.Zero) { moel@236: if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS) moel@236: service = NativeMethods.OpenService(manager, id, moel@236: ServiceAccessRights.SERVICE_ALL_ACCESS); moel@367: else { moel@367: errorMessage = "CreateService returned the error: " + moel@367: Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message; moel@367: NativeMethods.CloseServiceHandle(manager); moel@236: return false; moel@367: } moel@236: } moel@236: moel@236: if (!NativeMethods.StartService(service, 0, null)) { moel@367: if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING) { moel@367: errorMessage = "StartService returned the error: " + moel@367: Marshal.GetExceptionForHR(Marshal.GetHRForLastWin32Error()).Message; moel@367: NativeMethods.CloseServiceHandle(service); moel@367: NativeMethods.CloseServiceHandle(manager); moel@236: return false; moel@367: } moel@236: } moel@236: moel@236: NativeMethods.CloseServiceHandle(service); moel@236: NativeMethods.CloseServiceHandle(manager); moel@237: moel@237: try { moel@237: // restrict the driver access to system (SY) and builtin admins (BA) moel@237: // TODO: replace with a call to IoCreateDeviceSecure in the driver moel@237: FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id); moel@237: fileSecurity.SetSecurityDescriptorSddlForm( moel@237: "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)"); moel@237: File.SetAccessControl(@"\\.\" + id, fileSecurity); moel@237: } catch { } moel@367: moel@367: errorMessage = null; moel@236: return true; moel@236: } moel@236: moel@236: public bool Open() { moel@236: device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id, moel@236: FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero, moel@236: CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL, moel@236: IntPtr.Zero), true); moel@236: moel@236: if (device.IsInvalid) { moel@236: device.Close(); moel@236: device.Dispose(); moel@236: device = null; moel@236: } moel@236: moel@236: return device != null; moel@236: } moel@236: moel@236: public bool IsOpen { moel@236: get { return device != null; } moel@236: } moel@236: moel@236: public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) { moel@236: if (device == null) moel@236: return false; moel@236: moel@236: uint bytesReturned; moel@236: bool b = NativeMethods.DeviceIoControl(device, ioControlCode, moel@236: inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), moel@236: null, 0, out bytesReturned, IntPtr.Zero); moel@236: return b; moel@236: } moel@236: moel@236: public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer, moel@236: ref T outBuffer) moel@236: { moel@236: if (device == null) moel@236: return false; moel@236: moel@236: object boxedOutBuffer = outBuffer; moel@236: uint bytesReturned; moel@236: bool b = NativeMethods.DeviceIoControl(device, ioControlCode, moel@236: inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer), moel@236: boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer), moel@236: out bytesReturned, IntPtr.Zero); moel@236: outBuffer = (T)boxedOutBuffer; moel@236: return b; moel@236: } moel@236: moel@236: public void Close() { moel@236: if (device != null) { moel@236: device.Close(); moel@236: device.Dispose(); moel@236: device = null; moel@236: } moel@236: } moel@236: moel@236: public bool Delete() { moel@236: IntPtr manager = NativeMethods.OpenSCManager(null, null, moel@236: ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS); moel@236: moel@236: if (manager == IntPtr.Zero) moel@236: return false; moel@236: moel@236: IntPtr service = NativeMethods.OpenService(manager, id, moel@236: ServiceAccessRights.SERVICE_ALL_ACCESS); moel@236: moel@236: if (service == IntPtr.Zero) moel@236: return true; moel@236: moel@236: ServiceStatus status = new ServiceStatus(); moel@236: NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, moel@236: ref status); moel@236: moel@236: NativeMethods.DeleteService(service); moel@236: moel@236: NativeMethods.CloseServiceHandle(service); moel@236: NativeMethods.CloseServiceHandle(manager); moel@236: moel@236: return true; moel@236: } moel@236: moel@236: private enum ServiceAccessRights : uint { moel@236: SERVICE_ALL_ACCESS = 0xF01FF moel@236: } moel@236: moel@236: private enum ServiceControlManagerAccessRights : uint { moel@236: SC_MANAGER_ALL_ACCESS = 0xF003F moel@236: } moel@236: moel@236: private enum ServiceType : uint { moel@236: SERVICE_KERNEL_DRIVER = 1, moel@236: SERVICE_FILE_SYSTEM_DRIVER = 2 moel@236: } moel@236: moel@236: private enum StartType : uint { moel@236: SERVICE_BOOT_START = 0, moel@236: SERVICE_SYSTEM_START = 1, moel@236: SERVICE_AUTO_START = 2, moel@236: SERVICE_DEMAND_START = 3, moel@236: SERVICE_DISABLED = 4 moel@236: } moel@236: moel@236: private enum ErrorControl : uint { moel@236: SERVICE_ERROR_IGNORE = 0, moel@236: SERVICE_ERROR_NORMAL = 1, moel@236: SERVICE_ERROR_SEVERE = 2, moel@236: SERVICE_ERROR_CRITICAL = 3 moel@236: } moel@236: moel@236: private enum ServiceControl : uint { moel@236: SERVICE_CONTROL_STOP = 1, moel@236: SERVICE_CONTROL_PAUSE = 2, moel@236: SERVICE_CONTROL_CONTINUE = 3, moel@236: SERVICE_CONTROL_INTERROGATE = 4, moel@236: SERVICE_CONTROL_SHUTDOWN = 5, moel@236: SERVICE_CONTROL_PARAMCHANGE = 6, moel@236: SERVICE_CONTROL_NETBINDADD = 7, moel@236: SERVICE_CONTROL_NETBINDREMOVE = 8, moel@236: SERVICE_CONTROL_NETBINDENABLE = 9, moel@236: SERVICE_CONTROL_NETBINDDISABLE = 10, moel@236: SERVICE_CONTROL_DEVICEEVENT = 11, moel@236: SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12, moel@236: SERVICE_CONTROL_POWEREVENT = 13, moel@236: SERVICE_CONTROL_SESSIONCHANGE = 14 moel@236: } moel@236: moel@236: [StructLayout(LayoutKind.Sequential, Pack = 1)] moel@236: private struct ServiceStatus { moel@236: public uint dwServiceType; moel@236: public uint dwCurrentState; moel@236: public uint dwControlsAccepted; moel@236: public uint dwWin32ExitCode; moel@236: public uint dwServiceSpecificExitCode; moel@236: public uint dwCheckPoint; moel@236: public uint dwWaitHint; moel@236: } moel@236: moel@236: private enum FileAccess : uint { moel@236: GENERIC_READ = 0x80000000, moel@236: GENERIC_WRITE = 0x40000000 moel@236: } moel@236: moel@236: private enum CreationDisposition : uint { moel@236: CREATE_NEW = 1, moel@236: CREATE_ALWAYS = 2, moel@236: OPEN_EXISTING = 3, moel@236: OPEN_ALWAYS = 4, moel@236: TRUNCATE_EXISTING = 5 moel@236: } moel@236: moel@236: private enum FileAttributes : uint { moel@236: FILE_ATTRIBUTE_NORMAL = 0x80 moel@236: } moel@236: moel@236: private const int moel@236: ERROR_SERVICE_EXISTS = unchecked((int)0x80070431), moel@236: ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420); moel@236: moel@236: private static class NativeMethods { moel@236: private const string ADVAPI = "advapi32.dll"; moel@236: private const string KERNEL = "kernel32.dll"; moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)] moel@236: public static extern IntPtr OpenSCManager(string machineName, moel@236: string databaseName, ServiceControlManagerAccessRights dwAccess); moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)] moel@236: [return: MarshalAs(UnmanagedType.Bool)] moel@236: public static extern bool CloseServiceHandle(IntPtr hSCObject); moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, moel@236: SetLastError = true)] moel@236: public static extern IntPtr CreateService(IntPtr hSCManager, moel@236: string lpServiceName, string lpDisplayName, moel@236: ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType, moel@236: StartType dwStartType, ErrorControl dwErrorControl, moel@236: string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId, moel@236: string lpDependencies, string lpServiceStartName, string lpPassword); moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, moel@236: SetLastError = true)] moel@236: public static extern IntPtr OpenService(IntPtr hSCManager, moel@236: string lpServiceName, ServiceAccessRights dwDesiredAccess); moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, moel@236: SetLastError = true)] moel@236: [return: MarshalAs(UnmanagedType.Bool)] moel@236: public static extern bool DeleteService(IntPtr hService); moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, moel@236: SetLastError = true)] moel@236: [return: MarshalAs(UnmanagedType.Bool)] moel@236: public static extern bool StartService(IntPtr hService, moel@236: uint dwNumServiceArgs, string[] lpServiceArgVectors); moel@236: moel@236: [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi, moel@236: SetLastError = true)] moel@236: [return: MarshalAs(UnmanagedType.Bool)] moel@236: public static extern bool ControlService(IntPtr hService, moel@236: ServiceControl dwControl, ref ServiceStatus lpServiceStatus); moel@236: moel@236: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)] moel@236: public static extern bool DeviceIoControl(SafeFileHandle device, moel@236: IOControlCode ioControlCode, moel@236: [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, moel@236: uint inBufferSize, moel@236: [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer, moel@236: uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped); moel@236: moel@236: [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, moel@236: SetLastError = true)] moel@236: public static extern IntPtr CreateFile(string lpFileName, moel@236: FileAccess dwDesiredAccess, uint dwShareMode, moel@236: IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, moel@236: FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile); moel@236: } moel@236: } moel@236: }