moel@236: /* moel@236: moel@236: Version: MPL 1.1/GPL 2.0/LGPL 2.1 moel@236: moel@236: The contents of this file are subject to the Mozilla Public License Version moel@236: 1.1 (the "License"); you may not use this file except in compliance with moel@236: the License. You may obtain a copy of the License at moel@236: moel@236: http://www.mozilla.org/MPL/ moel@236: moel@236: Software distributed under the License is distributed on an "AS IS" basis, moel@236: WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License moel@236: for the specific language governing rights and limitations under the License. moel@236: moel@236: The Original Code is the Open Hardware Monitor code. moel@236: moel@236: The Initial Developer of the Original Code is moel@236: Michael Möller . moel@236: Portions created by the Initial Developer are Copyright (C) 2010 moel@236: the Initial Developer. All Rights Reserved. moel@236: moel@236: Contributor(s): moel@236: moel@236: Alternatively, the contents of this file may be used under the terms of moel@236: either the GNU General Public License Version 2 or later (the "GPL"), or moel@236: the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), moel@236: in which case the provisions of the GPL or the LGPL are applicable instead moel@236: of those above. If you wish to allow use of your version of this file only moel@236: under the terms of either the GPL or the LGPL, and not to allow others to moel@236: use your version of this file under the terms of the MPL, indicate your moel@236: decision by deleting the provisions above and replace them with the notice moel@236: and other provisions required by the GPL or the LGPL. If you do not delete moel@236: the provisions above, a recipient may use your version of this file under moel@236: the terms of any one of the MPL, the GPL or the LGPL. moel@236: 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@236: public bool Install(string path) { 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.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@236: else moel@236: return false; moel@236: } moel@236: moel@236: if (!NativeMethods.StartService(service, 0, null)) { moel@236: if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING) moel@236: return false; 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@237: 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: }