Hardware/KernelDriver.cs
author moel.mich
Thu, 04 Nov 2010 21:46:14 +0000
changeset 239 91800d0f54de
parent 236 763675f19ff4
child 344 3145aadca3d2
permissions -rw-r--r--
Replaced the direct reference to the Mono.Posix assembly with reflection.
moel@236
     1
/*
moel@236
     2
  
moel@236
     3
  Version: MPL 1.1/GPL 2.0/LGPL 2.1
moel@236
     4
moel@236
     5
  The contents of this file are subject to the Mozilla Public License Version
moel@236
     6
  1.1 (the "License"); you may not use this file except in compliance with
moel@236
     7
  the License. You may obtain a copy of the License at
moel@236
     8
 
moel@236
     9
  http://www.mozilla.org/MPL/
moel@236
    10
moel@236
    11
  Software distributed under the License is distributed on an "AS IS" basis,
moel@236
    12
  WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
moel@236
    13
  for the specific language governing rights and limitations under the License.
moel@236
    14
moel@236
    15
  The Original Code is the Open Hardware Monitor code.
moel@236
    16
moel@236
    17
  The Initial Developer of the Original Code is 
moel@236
    18
  Michael Möller <m.moeller@gmx.ch>.
moel@236
    19
  Portions created by the Initial Developer are Copyright (C) 2010
moel@236
    20
  the Initial Developer. All Rights Reserved.
moel@236
    21
moel@236
    22
  Contributor(s):
moel@236
    23
moel@236
    24
  Alternatively, the contents of this file may be used under the terms of
moel@236
    25
  either the GNU General Public License Version 2 or later (the "GPL"), or
moel@236
    26
  the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
moel@236
    27
  in which case the provisions of the GPL or the LGPL are applicable instead
moel@236
    28
  of those above. If you wish to allow use of your version of this file only
moel@236
    29
  under the terms of either the GPL or the LGPL, and not to allow others to
moel@236
    30
  use your version of this file under the terms of the MPL, indicate your
moel@236
    31
  decision by deleting the provisions above and replace them with the notice
moel@236
    32
  and other provisions required by the GPL or the LGPL. If you do not delete
moel@236
    33
  the provisions above, a recipient may use your version of this file under
moel@236
    34
  the terms of any one of the MPL, the GPL or the LGPL.
moel@236
    35
 
moel@236
    36
*/
moel@236
    37
moel@236
    38
using System;
moel@237
    39
using System.IO;
moel@236
    40
using System.Runtime.InteropServices;
moel@237
    41
using System.Security.AccessControl;
moel@236
    42
using Microsoft.Win32.SafeHandles;
moel@236
    43
moel@236
    44
namespace OpenHardwareMonitor.Hardware {
moel@236
    45
  internal class KernelDriver {
moel@236
    46
moel@236
    47
    private string id;
moel@236
    48
moel@236
    49
    private SafeFileHandle device; 
moel@236
    50
    
moel@236
    51
    public KernelDriver(string id) {
moel@236
    52
      this.id = id;
moel@236
    53
    }
moel@236
    54
   
moel@236
    55
    public bool Install(string path) {
moel@236
    56
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
    57
        ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
    58
moel@236
    59
      if (manager == IntPtr.Zero)
moel@236
    60
        return false;
moel@236
    61
moel@236
    62
      IntPtr service = NativeMethods.CreateService(manager, id, id,
moel@236
    63
        ServiceAccessRights.SERVICE_ALL_ACCESS,
moel@236
    64
        ServiceType.SERVICE_KERNEL_DRIVER, StartType.SERVICE_DEMAND_START,
moel@236
    65
        ErrorControl.SERVICE_ERROR_NORMAL, path, null, null, null, null,
moel@236
    66
        null);
moel@236
    67
moel@236
    68
      if (service == IntPtr.Zero) {
moel@236
    69
        if (Marshal.GetHRForLastWin32Error() == ERROR_SERVICE_EXISTS)
moel@236
    70
          service = NativeMethods.OpenService(manager, id,
moel@236
    71
            ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
    72
        else
moel@236
    73
          return false;
moel@236
    74
      }
moel@236
    75
moel@236
    76
      if (!NativeMethods.StartService(service, 0, null)) {
moel@236
    77
        if (Marshal.GetHRForLastWin32Error() != ERROR_SERVICE_ALREADY_RUNNING)
moel@236
    78
          return false;
moel@236
    79
      }
moel@236
    80
moel@236
    81
      NativeMethods.CloseServiceHandle(service);
moel@236
    82
      NativeMethods.CloseServiceHandle(manager);
moel@237
    83
      
moel@237
    84
      try {
moel@237
    85
        // restrict the driver access to system (SY) and builtin admins (BA)
moel@237
    86
        // TODO: replace with a call to IoCreateDeviceSecure in the driver
moel@237
    87
        FileSecurity fileSecurity = File.GetAccessControl(@"\\.\" + id);
moel@237
    88
        fileSecurity.SetSecurityDescriptorSddlForm(
moel@237
    89
          "O:BAG:SYD:(A;;FA;;;SY)(A;;FA;;;BA)");
moel@237
    90
        File.SetAccessControl(@"\\.\" + id, fileSecurity);
moel@237
    91
      } catch { }
moel@237
    92
      
moel@236
    93
      return true;
moel@236
    94
    }
moel@236
    95
moel@236
    96
    public bool Open() {
moel@236
    97
      device = new SafeFileHandle(NativeMethods.CreateFile(@"\\.\" + id,
moel@236
    98
        FileAccess.GENERIC_READ | FileAccess.GENERIC_WRITE, 0, IntPtr.Zero,
moel@236
    99
        CreationDisposition.OPEN_EXISTING, FileAttributes.FILE_ATTRIBUTE_NORMAL,
moel@236
   100
        IntPtr.Zero), true);
moel@236
   101
moel@236
   102
      if (device.IsInvalid) {
moel@236
   103
        device.Close();
moel@236
   104
        device.Dispose();
moel@236
   105
        device = null;
moel@236
   106
      }
moel@236
   107
moel@236
   108
      return device != null;
moel@236
   109
    }
moel@236
   110
moel@236
   111
    public bool IsOpen {
moel@236
   112
      get { return device != null; }
moel@236
   113
    }
moel@236
   114
moel@236
   115
    public bool DeviceIOControl(IOControlCode ioControlCode, object inBuffer) {
moel@236
   116
      if (device == null)
moel@236
   117
        return false;
moel@236
   118
moel@236
   119
      uint bytesReturned;
moel@236
   120
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   121
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   122
        null, 0, out bytesReturned, IntPtr.Zero);
moel@236
   123
      return b;
moel@236
   124
    }
moel@236
   125
moel@236
   126
    public bool DeviceIOControl<T>(IOControlCode ioControlCode, object inBuffer, 
moel@236
   127
      ref T outBuffer) 
moel@236
   128
    {
moel@236
   129
      if (device == null)
moel@236
   130
        return false;
moel@236
   131
moel@236
   132
      object boxedOutBuffer = outBuffer;
moel@236
   133
      uint bytesReturned;
moel@236
   134
      bool b = NativeMethods.DeviceIoControl(device, ioControlCode,
moel@236
   135
        inBuffer, inBuffer == null ? 0 : (uint)Marshal.SizeOf(inBuffer),
moel@236
   136
        boxedOutBuffer, (uint)Marshal.SizeOf(boxedOutBuffer),
moel@236
   137
        out bytesReturned, IntPtr.Zero);
moel@236
   138
      outBuffer = (T)boxedOutBuffer;
moel@236
   139
      return b;
moel@236
   140
    }
moel@236
   141
moel@236
   142
    public void Close() {
moel@236
   143
      if (device != null) {
moel@236
   144
        device.Close();
moel@236
   145
        device.Dispose();
moel@236
   146
        device = null;
moel@236
   147
      }
moel@236
   148
    }
moel@236
   149
moel@236
   150
    public bool Delete() {
moel@236
   151
      IntPtr manager = NativeMethods.OpenSCManager(null, null,
moel@236
   152
      ServiceControlManagerAccessRights.SC_MANAGER_ALL_ACCESS);
moel@236
   153
moel@236
   154
      if (manager == IntPtr.Zero)
moel@236
   155
        return false;      
moel@236
   156
moel@236
   157
      IntPtr service = NativeMethods.OpenService(manager, id,
moel@236
   158
        ServiceAccessRights.SERVICE_ALL_ACCESS);
moel@236
   159
moel@236
   160
      if (service == IntPtr.Zero)
moel@236
   161
        return true;
moel@236
   162
moel@236
   163
      ServiceStatus status = new ServiceStatus();
moel@236
   164
      NativeMethods.ControlService(service, ServiceControl.SERVICE_CONTROL_STOP, 
moel@236
   165
        ref status);
moel@236
   166
moel@236
   167
      NativeMethods.DeleteService(service);
moel@236
   168
moel@236
   169
      NativeMethods.CloseServiceHandle(service);
moel@236
   170
      NativeMethods.CloseServiceHandle(manager);
moel@236
   171
      
moel@236
   172
      return true;
moel@236
   173
    }
moel@236
   174
moel@236
   175
    private enum ServiceAccessRights : uint {
moel@236
   176
      SERVICE_ALL_ACCESS = 0xF01FF
moel@236
   177
    }
moel@236
   178
moel@236
   179
    private enum ServiceControlManagerAccessRights : uint {
moel@236
   180
      SC_MANAGER_ALL_ACCESS = 0xF003F
moel@236
   181
    }
moel@236
   182
moel@236
   183
    private enum ServiceType : uint {
moel@236
   184
      SERVICE_KERNEL_DRIVER = 1,
moel@236
   185
      SERVICE_FILE_SYSTEM_DRIVER = 2
moel@236
   186
    }
moel@236
   187
moel@236
   188
    private enum StartType : uint {
moel@236
   189
      SERVICE_BOOT_START = 0,
moel@236
   190
      SERVICE_SYSTEM_START = 1,
moel@236
   191
      SERVICE_AUTO_START = 2,
moel@236
   192
      SERVICE_DEMAND_START = 3,
moel@236
   193
      SERVICE_DISABLED = 4
moel@236
   194
    }
moel@236
   195
moel@236
   196
    private enum ErrorControl : uint {
moel@236
   197
      SERVICE_ERROR_IGNORE = 0,
moel@236
   198
      SERVICE_ERROR_NORMAL = 1,
moel@236
   199
      SERVICE_ERROR_SEVERE = 2,
moel@236
   200
      SERVICE_ERROR_CRITICAL = 3
moel@236
   201
    }
moel@236
   202
moel@236
   203
    private enum ServiceControl : uint {
moel@236
   204
      SERVICE_CONTROL_STOP = 1,
moel@236
   205
      SERVICE_CONTROL_PAUSE = 2,
moel@236
   206
      SERVICE_CONTROL_CONTINUE = 3,
moel@236
   207
      SERVICE_CONTROL_INTERROGATE = 4,
moel@236
   208
      SERVICE_CONTROL_SHUTDOWN = 5,
moel@236
   209
      SERVICE_CONTROL_PARAMCHANGE = 6,
moel@236
   210
      SERVICE_CONTROL_NETBINDADD = 7,
moel@236
   211
      SERVICE_CONTROL_NETBINDREMOVE = 8,
moel@236
   212
      SERVICE_CONTROL_NETBINDENABLE = 9,
moel@236
   213
      SERVICE_CONTROL_NETBINDDISABLE = 10,
moel@236
   214
      SERVICE_CONTROL_DEVICEEVENT = 11,
moel@236
   215
      SERVICE_CONTROL_HARDWAREPROFILECHANGE = 12,
moel@236
   216
      SERVICE_CONTROL_POWEREVENT = 13,
moel@236
   217
      SERVICE_CONTROL_SESSIONCHANGE = 14
moel@236
   218
    }
moel@236
   219
moel@236
   220
    [StructLayout(LayoutKind.Sequential, Pack = 1)]
moel@236
   221
    private struct ServiceStatus {
moel@236
   222
      public uint dwServiceType;
moel@236
   223
      public uint dwCurrentState;
moel@236
   224
      public uint dwControlsAccepted;
moel@236
   225
      public uint dwWin32ExitCode;
moel@236
   226
      public uint dwServiceSpecificExitCode;
moel@236
   227
      public uint dwCheckPoint;
moel@236
   228
      public uint dwWaitHint;
moel@236
   229
    }
moel@236
   230
moel@236
   231
    private enum FileAccess : uint {
moel@236
   232
      GENERIC_READ = 0x80000000,
moel@236
   233
      GENERIC_WRITE = 0x40000000
moel@236
   234
    }
moel@236
   235
moel@236
   236
    private enum CreationDisposition : uint {
moel@236
   237
      CREATE_NEW = 1,
moel@236
   238
      CREATE_ALWAYS = 2,
moel@236
   239
      OPEN_EXISTING = 3,
moel@236
   240
      OPEN_ALWAYS = 4,
moel@236
   241
      TRUNCATE_EXISTING = 5
moel@236
   242
    }
moel@236
   243
moel@236
   244
    private enum FileAttributes : uint {
moel@236
   245
      FILE_ATTRIBUTE_NORMAL = 0x80
moel@236
   246
    }
moel@236
   247
moel@236
   248
    private const int
moel@236
   249
      ERROR_SERVICE_EXISTS = unchecked((int)0x80070431),
moel@236
   250
      ERROR_SERVICE_ALREADY_RUNNING = unchecked((int)0x80070420);
moel@236
   251
moel@236
   252
    private static class NativeMethods {
moel@236
   253
      private const string ADVAPI = "advapi32.dll";
moel@236
   254
      private const string KERNEL = "kernel32.dll";
moel@236
   255
moel@236
   256
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   257
      public static extern IntPtr OpenSCManager(string machineName,
moel@236
   258
        string databaseName, ServiceControlManagerAccessRights dwAccess);
moel@236
   259
moel@236
   260
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi)]
moel@236
   261
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   262
      public static extern bool CloseServiceHandle(IntPtr hSCObject);
moel@236
   263
moel@236
   264
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   265
        SetLastError = true)]
moel@236
   266
      public static extern IntPtr CreateService(IntPtr hSCManager,
moel@236
   267
        string lpServiceName, string lpDisplayName, 
moel@236
   268
        ServiceAccessRights dwDesiredAccess, ServiceType dwServiceType,
moel@236
   269
        StartType dwStartType, ErrorControl dwErrorControl,
moel@236
   270
        string lpBinaryPathName, string lpLoadOrderGroup, string lpdwTagId,
moel@236
   271
        string lpDependencies, string lpServiceStartName, string lpPassword);
moel@236
   272
moel@236
   273
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   274
        SetLastError = true)]
moel@236
   275
      public static extern IntPtr OpenService(IntPtr hSCManager,
moel@236
   276
        string lpServiceName, ServiceAccessRights dwDesiredAccess);
moel@236
   277
moel@236
   278
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   279
        SetLastError = true)]
moel@236
   280
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   281
      public static extern bool DeleteService(IntPtr hService);
moel@236
   282
moel@236
   283
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   284
        SetLastError = true)]
moel@236
   285
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   286
      public static extern bool StartService(IntPtr hService, 
moel@236
   287
        uint dwNumServiceArgs, string[] lpServiceArgVectors);
moel@236
   288
moel@236
   289
      [DllImport(ADVAPI, CallingConvention = CallingConvention.Winapi,
moel@236
   290
        SetLastError = true)]
moel@236
   291
      [return: MarshalAs(UnmanagedType.Bool)]
moel@236
   292
      public static extern bool ControlService(IntPtr hService,
moel@236
   293
        ServiceControl dwControl, ref ServiceStatus lpServiceStatus);
moel@236
   294
moel@236
   295
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
moel@236
   296
      public static extern bool DeviceIoControl(SafeFileHandle device,
moel@236
   297
        IOControlCode ioControlCode, 
moel@236
   298
        [MarshalAs(UnmanagedType.AsAny)] [In] object inBuffer, 
moel@236
   299
        uint inBufferSize,
moel@236
   300
        [MarshalAs(UnmanagedType.AsAny)] [Out] object outBuffer,
moel@236
   301
        uint nOutBufferSize, out uint bytesReturned, IntPtr overlapped);
moel@236
   302
moel@236
   303
      [DllImport(KERNEL, CallingConvention = CallingConvention.Winapi, 
moel@236
   304
        SetLastError = true)]
moel@236
   305
      public static extern IntPtr CreateFile(string lpFileName,
moel@236
   306
        FileAccess dwDesiredAccess, uint dwShareMode, 
moel@236
   307
        IntPtr lpSecurityAttributes, CreationDisposition dwCreationDisposition, 
moel@236
   308
        FileAttributes dwFlagsAndAttributes, IntPtr hTemplateFile);
moel@236
   309
    }
moel@236
   310
  }
moel@236
   311
}