Hardware/KernelDriver.cs
author moel.mich
Sun, 27 May 2012 14:23:31 +0000
changeset 344 3145aadca3d2
parent 237 9bf70d316cea
child 367 45215572a774
permissions -rw-r--r--
Changed the license to the Mozilla Public License 2.0 and update the licensing information.
moel@236
     1
/*
moel@236
     2
 
moel@344
     3
  This Source Code Form is subject to the terms of the Mozilla Public
moel@344
     4
  License, v. 2.0. If a copy of the MPL was not distributed with this
moel@344
     5
  file, You can obtain one at http://mozilla.org/MPL/2.0/.
moel@236
     6
 
moel@344
     7
  Copyright (C) 2010 Michael Möller <mmoeller@openhardwaremonitor.org>
moel@344
     8
	
moel@236
     9
*/
moel@236
    10
moel@236
    11
using System;
moel@237
    12
using System.IO;
moel@236
    13
using System.Runtime.InteropServices;
moel@237
    14
using System.Security.AccessControl;
moel@236
    15
using Microsoft.Win32.SafeHandles;
moel@236
    16
moel@236
    17
namespace OpenHardwareMonitor.Hardware {
moel@236
    18
  internal class KernelDriver {
moel@236
    19
moel@236
    20
    private string id;
moel@236
    21
moel@236
    22
    private SafeFileHandle device; 
moel@236
    23
    
moel@236
    24
    public KernelDriver(string id) {
moel@236
    25
      this.id = id;
moel@236
    26
    }
moel@236
    27
   
moel@236
    28
    public bool Install(string path) {
moel@236
    29
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
    30
        ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
    31
moel@236
    32
      if (manager == IntPtr.Zero)
moel@236
    33
        return false;
moel@236
    34
moel@236
    35
      IntPtr service = NativeMethods.CreateService(manager, id, id,
moel@236
    36
        ServiceAccessRights.SERVICE_ALL_ACCESS,
moel@236
    37
        ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
moel@236
    38
        ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
moel@236
    39
        null);
moel@236
    40
moel@236
    41
      if (service == IntPtr.Zero) {
moel@236
    42
        if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
moel@236
    43
          service = NativeMethods.OpenService(manager, id,
moel@236
    44
            ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
    45
        else
moel@236
    46
          return false;
moel@236
    47
      }
moel@236
    48
moel@236
    49
      if (!NativeMethods.StartService(service, 0, null)) {
moel@236
    50
        if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING)
moel@236
    51
          return false;
moel@236
    52
      }
moel@236
    53
moel@236
    54
      NativeMethods.CloseServiceHandle(service);
moel@236
    55
      NativeMethods.CloseServiceHandle(manager);
moel@237
    56
      
moel@237
    57
      try {
moel@237
    58
        // restrict the driver access to system (SY) and builtin admins (BA)
moel@237
    59
        // TODO: replace with a call to IoCreateDeviceSecure in the driver
moel@237
    60
        FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id);
moel@237
    61
        fileSecurity.SetSecurityDescriptorSddlForm(
moel@237
    62
          "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
moel@237
    63
        File.SetAccessControl(@"\\.\" + id, fileSecurity);
moel@237
    64
      } catch { }
moel@237
    65
      
moel@236
    66
      return true;
moel@236
    67
    }
moel@236
    68
moel@236
    69
    public bool Open() {
moel@236
    70
      device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
moel@236
    71
        FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
moel@236
    72
        CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
moel@236
    73
        IntPtr.Zero), true);
moel@236
    74
moel@236
    75
      if (device.IsInvalid) {
moel@236
    76
        device.Close();
moel@236
    77
        device.Dispose();
moel@236
    78
        device = null;
moel@236
    79
      }
moel@236
    80
moel@236
    81
      return device != null;
moel@236
    82
    }
moel@236
    83
moel@236
    84
    public bool IsOpen {
moel@236
    85
      get { return device != null; }
moel@236
    86
    }
moel@236
    87
moel@236
    88
    public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
moel@236
    89
      if (device == null)
moel@236
    90
        return false;
moel@236
    91
moel@236
    92
      uint bytesReturned;
moel@236
    93
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
    94
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
    95
        null, 0, out bytesReturned, IntPtr.Zero);
moel@236
    96
      return b;
moel@236
    97
    }
moel@236
    98
moel@236
    99
    public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
moel@236
   100
      ref T outBuffer) 
moel@236
   101
    {
moel@236
   102
      if (device == null)
moel@236
   103
        return false;
moel@236
   104
moel@236
   105
      object boxedOutBuffer = outBuffer;
moel@236
   106
      uint bytesReturned;
moel@236
   107
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   108
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   109
        boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
moel@236
   110
        out bytesReturned, IntPtr.Zero);
moel@236
   111
      outBuffer = (T)boxedOutBuffer;
moel@236
   112
      return b;
moel@236
   113
    }
moel@236
   114
moel@236
   115
    public void Close() {
moel@236
   116
      if (device != null) {
moel@236
   117
        device.Close();
moel@236
   118
        device.Dispose();
moel@236
   119
        device = null;
moel@236
   120
      }
moel@236
   121
    }
moel@236
   122
moel@236
   123
    public bool Delete() {
moel@236
   124
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
   125
      ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
   126
moel@236
   127
      if (manager == IntPtr.Zero)
moel@236
   128
        return false;      
moel@236
   129
moel@236
   130
      IntPtr service = NativeMethods.OpenService(manager, id,
moel@236
   131
        ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
   132
moel@236
   133
      if (service == IntPtr.Zero)
moel@236
   134
        return true;
moel@236
   135
moel@236
   136
      ServiceStatus status = new ServiceStatus();
moel@236
   137
      NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
moel@236
   138
        ref status);
moel@236
   139
moel@236
   140
      NativeMethods.DeleteService(service);
moel@236
   141
moel@236
   142
      NativeMethods.CloseServiceHandle(service);
moel@236
   143
      NativeMethods.CloseServiceHandle(manager);
moel@236
   144
      
moel@236
   145
      return true;
moel@236
   146
    }
moel@236
   147
moel@236
   148
    private enum ServiceAccessRights : uint {
moel@236
   149
      SERVICE_ALL_ACCESS = 0xF01FF
moel@236
   150
    }
moel@236
   151
moel@236
   152
    private enum ServiceControlManagerAccessRights : uint {
moel@236
   153
      SC_MANAGER_ALL_ACCESS = 0xF003F
moel@236
   154
    }
moel@236
   155
moel@236
   156
    private enum ServiceType : uint {
moel@236
   157
      SERVICE_KERNEL_DRIVER = 1,
moel@236
   158
      SERVICE_FILE_SYSTEM_DRIVER = 2
moel@236
   159
    }
moel@236
   160
moel@236
   161
    private enum StartType : uint {
moel@236
   162
      SERVICE_BOOT_START = 0,
moel@236
   163
      SERVICE_SYSTEM_START = 1,
moel@236
   164
      SERVICE_AUTO_START = 2,
moel@236
   165
      SERVICE_DEMAND_START = 3,
moel@236
   166
      SERVICE_DISABLED = 4
moel@236
   167
    }
moel@236
   168
moel@236
   169
    private enum ErrorControl : uint {
moel@236
   170
      SERVICE_ERROR_IGNORE = 0,
moel@236
   171
      SERVICE_ERROR_NORMAL = 1,
moel@236
   172
      SERVICE_ERROR_SEVERE = 2,
moel@236
   173
      SERVICE_ERROR_CRITICAL = 3
moel@236
   174
    }
moel@236
   175
moel@236
   176
    private enum ServiceControl : uint {
moel@236
   177
      SERVICE_CONTROL_STOP = 1,
moel@236
   178
      SERVICE_CONTROL_PAUSE = 2,
moel@236
   179
      SERVICE_CONTROL_CONTINUE = 3,
moel@236
   180
      SERVICE_CONTROL_INTERROGATE = 4,
moel@236
   181
      SERVICE_CONTROL_SHUTDOWN = 5,
moel@236
   182
      SERVICE_CONTROL_PARAMCHANGE = 6,
moel@236
   183
      SERVICE_CONTROL_NETBINDADD = 7,
moel@236
   184
      SERVICE_CONTROL_NETBINDREMOVE = 8,
moel@236
   185
      SERVICE_CONTROL_NETBINDENABLE = 9,
moel@236
   186
      SERVICE_CONTROL_NETBINDDISABLE = 10,
moel@236
   187
      SERVICE_CONTROL_DEVICEEVENT = 11,
moel@236
   188
      SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
moel@236
   189
      SERVICE_CONTROL_POWEREVENT = 13,
moel@236
   190
      SERVICE_CONTROL_SESSIONCHANGE = 14
moel@236
   191
    }
moel@236
   192
moel@236
   193
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   194
    private struct ServiceStatus {
moel@236
   195
      public uint dwServiceType;
moel@236
   196
      public uint dwCurrentState;
moel@236
   197
      public uint dwControlsAccepted;
moel@236
   198
      public uint dwWin32ExitCode;
moel@236
   199
      public uint dwServiceSpecificExitCode;
moel@236
   200
      public uint dwCheckPoint;
moel@236
   201
      public uint dwWaitHint;
moel@236
   202
    }
moel@236
   203
moel@236
   204
    private enum FileAccess : uint {
moel@236
   205
      GENERIC_READ = 0x80000000,
moel@236
   206
      GENERIC_WRITE = 0x40000000
moel@236
   207
    }
moel@236
   208
moel@236
   209
    private enum CreationDisposition : uint {
moel@236
   210
      CREATE_NEW = 1,
moel@236
   211
      CREATE_ALWAYS = 2,
moel@236
   212
      OPEN_EXISTING = 3,
moel@236
   213
      OPEN_ALWAYS = 4,
moel@236
   214
      TRUNCATE_EXISTING = 5
moel@236
   215
    }
moel@236
   216
moel@236
   217
    private enum FileAttributes : uint {
moel@236
   218
      FILE_ATTRIBUTE_NORMAL = 0x80
moel@236
   219
    }
moel@236
   220
moel@236
   221
    private const int
moel@236
   222
      ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
moel@236
   223
      ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
moel@236
   224
moel@236
   225
    private static class NativeMethods {
moel@236
   226
      private const string ADVAPI = "advapi32.dll";
moel@236
   227
      private const string KERNEL = "kernel32.dll";
moel@236
   228
moel@236
   229
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   230
      public static extern IntPtr OpenSCManager(string machineName,
moel@236
   231
        string databaseName, ServiceControlManagerAccessRights dwAccess);
moel@236
   232
moel@236
   233
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   234
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   235
      public static extern bool CloseServiceHandle(IntPtr hSCObject);
moel@236
   236
moel@236
   237
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   238
        SetLastError = true)]
moel@236
   239
      public static extern IntPtr CreateService(IntPtr hSCManager,
moel@236
   240
        string lpServiceName, string lpDisplayName, 
moel@236
   241
        ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
moel@236
   242
        StartType dwStartType, ErrorControl dwErrorControl,
moel@236
   243
        string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
moel@236
   244
        string lpDependencies, string lpServiceStartName, string lpPassword);
moel@236
   245
moel@236
   246
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   247
        SetLastError = true)]
moel@236
   248
      public static extern IntPtr OpenService(IntPtr hSCManager,
moel@236
   249
        string lpServiceName, ServiceAccessRights dwDesiredAccess);
moel@236
   250
moel@236
   251
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   252
        SetLastError = true)]
moel@236
   253
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   254
      public static extern bool DeleteService(IntPtr hService);
moel@236
   255
moel@236
   256
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   257
        SetLastError = true)]
moel@236
   258
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   259
      public static extern bool StartService(IntPtr hService, 
moel@236
   260
        uint dwNumServiceArgs, string[] lpServiceArgVectors);
moel@236
   261
moel@236
   262
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   263
        SetLastError = true)]
moel@236
   264
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   265
      public static extern bool ControlService(IntPtr hService,
moel@236
   266
        ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
moel@236
   267
moel@236
   268
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   269
      public static extern bool DeviceIoControl(SafeFileHandle device,
moel@236
   270
        IOControlCode ioControlCode, 
moel@236
   271
        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
moel@236
   272
        uint inBufferSize,
moel@236
   273
        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
moel@236
   274
        uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
moel@236
   275
moel@236
   276
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
moel@236
   277
        SetLastError = true)]
moel@236
   278
      public static extern IntPtr CreateFile(string lpFileName,
moel@236
   279
        FileAccess dwDesiredAccess, uint dwShareMode, 
moel@236
   280
        IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
moel@236
   281
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
moel@236
   282
    }
moel@236
   283
  }
moel@236
   284
}