/ src / modules / MouseWithoutBorders / App / Service / NativeMethods.cs
NativeMethods.cs
  1  // Copyright (c) Microsoft Corporation
  2  // The Microsoft Corporation licenses this file to you under the MIT license.
  3  // See the LICENSE file in the project root for more information.
  4  
  5  using System.Diagnostics;
  6  using System.Diagnostics.CodeAnalysis;
  7  using System.Runtime.InteropServices;
  8  using System.Security;
  9  using System.ServiceProcess;
 10  
 11  namespace MouseWithoutBordersService
 12  {
 13      internal sealed class NativeMethods
 14      {
 15          private NativeMethods()
 16          {
 17          }
 18  
 19          private const string MY_KEY = @"SOFTWARE\Microsoft\MouseWithoutBorders";
 20          private const string MY_KEY_EX = @"S-1-5-19\SOFTWARE\Microsoft\MouseWithoutBorders";
 21  
 22          [StructLayout(LayoutKind.Sequential)]
 23          private struct SECURITY_ATTRIBUTES
 24          {
 25              internal int Length;
 26              internal IntPtr lpSecurityDescriptor;
 27              internal bool bInheritHandle;
 28          }
 29  
 30          private enum TOKEN_TYPE : int
 31          {
 32              TokenPrimary = 1,
 33              TokenImpersonation = 2,
 34          }
 35  
 36          private enum TOKEN_INFORMATION_CLASS : int
 37          {
 38              TokenUser = 1,
 39              TokenGroups,
 40              TokenPrivileges,
 41              TokenOwner,
 42              TokenPrimaryGroup,
 43              TokenDefaultDacl,
 44              TokenSource,
 45              TokenType,
 46              TokenImpersonationLevel,
 47              TokenStatistics,
 48              TokenRestrictedSids,
 49              TokenSessionId,
 50              TokenGroupsAndPrivileges,
 51              TokenSessionReference,
 52              TokenSandBoxInert,
 53              TokenAuditPolicy,
 54              TokenOrigin,
 55              MaxTokenInfoClass,  // MaxTokenInfoClass should always be the last enum
 56          }
 57  
 58          [StructLayout(LayoutKind.Sequential)]
 59          private struct STARTUPINFO
 60          {
 61              internal int cb;
 62              internal string lpReserved;
 63              internal string lpDesktop;
 64              internal string lpTitle;
 65              internal uint dwX;
 66              internal uint dwY;
 67              internal uint dwXSize;
 68              internal uint dwYSize;
 69              internal uint dwXCountChars;
 70              internal uint dwYCountChars;
 71              internal uint dwFillAttribute;
 72              internal uint dwFlags;
 73              internal short wShowWindow;
 74              internal short cbReserved2;
 75              internal IntPtr lpReserved2;
 76              internal IntPtr hStdInput;
 77              internal IntPtr hStdOutput;
 78              internal IntPtr hStdError;
 79          }
 80  
 81          [StructLayout(LayoutKind.Sequential)]
 82          private struct SID_AND_ATTRIBUTES
 83          {
 84              internal IntPtr Sid;
 85              internal int Attributes;
 86          }
 87  
 88          [StructLayout(LayoutKind.Sequential)]
 89          private struct TOKEN_MANDATORY_LABEL
 90          {
 91              internal SID_AND_ATTRIBUTES Label;
 92          }
 93  
 94          [StructLayout(LayoutKind.Sequential)]
 95          internal struct PROCESS_INFORMATION
 96          {
 97              internal IntPtr hProcess;
 98              internal IntPtr hThread;
 99              internal uint dwProcessId;
100              internal uint dwThreadId;
101          }
102  
103          private enum SECURITY_IMPERSONATION_LEVEL : int
104          {
105              SecurityAnonymous = 0,
106              SecurityIdentification = 1,
107              SecurityImpersonation = 2,
108              SecurityDelegation = 3,
109          }
110  
111          [StructLayout(LayoutKind.Sequential)]
112          internal struct LUID
113          {
114              internal int LowPart;
115              internal int HighPart;
116          }// end struct
117  
118          [StructLayout(LayoutKind.Sequential)]
119          internal struct LUID_AND_ATTRIBUTES
120          {
121              internal LUID Luid;
122              internal int Attributes;
123          }// end struct
124  
125          [StructLayout(LayoutKind.Sequential)]
126          internal struct TOKEN_PRIVILEGES
127          {
128              internal int PrivilegeCount;
129              [MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
130              internal int[] Privileges;
131          }
132  
133          private const int READ_CONTROL = 0x00020000;
134  
135          private const int STANDARD_RIGHTS_REQUIRED = 0x000F0000;
136  
137          private const int STANDARD_RIGHTS_READ = READ_CONTROL;
138          private const int STANDARD_RIGHTS_WRITE = READ_CONTROL;
139          private const int STANDARD_RIGHTS_EXECUTE = READ_CONTROL;
140  
141          private const int STANDARD_RIGHTS_ALL = 0x001F0000;
142  
143          private const int SPECIFIC_RIGHTS_ALL = 0x0000FFFF;
144  
145          private const int TOKEN_ASSIGN_PRIMARY = 0x0001;
146          private const int TOKEN_DUPLICATE = 0x0002;
147          private const int TOKEN_IMPERSONATE = 0x0004;
148          private const int TOKEN_QUERY = 0x0008;
149          private const int TOKEN_QUERY_SOURCE = 0x0010;
150          private const int TOKEN_ADJUST_PRIVILEGES = 0x0020;
151          private const int TOKEN_ADJUST_GROUPS = 0x0040;
152          private const int TOKEN_ADJUST_DEFAULT = 0x0080;
153          private const int TOKEN_ADJUST_SESSIONID = 0x0100;
154  
155          private const int TOKEN_ALL_ACCESS_P = STANDARD_RIGHTS_REQUIRED |
156                                        TOKEN_ASSIGN_PRIMARY |
157                                        TOKEN_DUPLICATE |
158                                        TOKEN_IMPERSONATE |
159                                        TOKEN_QUERY |
160                                        TOKEN_QUERY_SOURCE |
161                                        TOKEN_ADJUST_PRIVILEGES |
162                                        TOKEN_ADJUST_GROUPS |
163                                        TOKEN_ADJUST_DEFAULT;
164  
165          private const int TOKEN_ALL_ACCESS = TOKEN_ALL_ACCESS_P | TOKEN_ADJUST_SESSIONID;
166  
167          private const int TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY;
168  
169          private const int TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
170                                        TOKEN_ADJUST_PRIVILEGES |
171                                        TOKEN_ADJUST_GROUPS |
172                                        TOKEN_ADJUST_DEFAULT;
173  
174          private const int TOKEN_EXECUTE = STANDARD_RIGHTS_EXECUTE;
175  
176          private const uint MAXIMUM_ALLOWED = 0x2000000;
177  
178          private const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
179          private const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
180  
181          private const int IDLE_PRIORITY_CLASS = 0x40;
182          private const int NORMAL_PRIORITY_CLASS = 0x20;
183          private const int HIGH_PRIORITY_CLASS = 0x80;
184          private const int REALTIME_PRIORITY_CLASS = 0x100;
185  
186          private const int CREATE_NEW_CONSOLE = 0x00000010;
187  
188          private const string SE_DEBUG_NAME = "SeDebugPrivilege";
189          private const string SE_RESTORE_NAME = "SeRestorePrivilege";
190          private const string SE_BACKUP_NAME = "SeBackupPrivilege";
191  
192          private const int SE_PRIVILEGE_ENABLED = 0x0002;
193  
194          private const int ERROR_NOT_ALL_ASSIGNED = 1300;
195  
196          [StructLayout(LayoutKind.Sequential)]
197          private struct PROCESSENTRY32
198          {
199              internal uint dwSize;
200              internal uint cntUsage;
201              internal uint th32ProcessID;
202              internal IntPtr th32DefaultHeapID;
203              internal uint th32ModuleID;
204              internal uint cntThreads;
205              internal uint th32ParentProcessID;
206              internal int pcPriClassBase;
207              internal uint dwFlags;
208              [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 260)]
209              internal string szExeFile;
210          }
211  
212          private const uint TH32CS_SNAPPROCESS = 0x00000002;
213  
214          [DllImport("kernel32.dll", SetLastError = true)]
215          [return: MarshalAs(UnmanagedType.Bool)]
216          private static extern bool CloseHandle(IntPtr hSnapshot);
217  
218          [DllImport("kernel32.dll")]
219          internal static extern uint WTSGetActiveConsoleSessionId();
220  
221          [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", MessageId = "1", Justification = "Dotnet port with style preservation")]
222          [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Auto)]
223          [return: MarshalAs(UnmanagedType.Bool)]
224          private static extern bool LookupPrivilegeValue(IntPtr lpSystemName, string lpname, [MarshalAs(UnmanagedType.Struct)] ref LUID lpLuid);
225  
226          [SuppressMessage("Microsoft.Globalization", "CA2101:SpecifyMarshalingForPInvokeStringArguments", Justification = "Dotnet port with style preservation")]
227          [DllImport("advapi32.dll", EntryPoint = "CreateProcessAsUser", SetLastError = true, CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)]
228          [return: MarshalAs(UnmanagedType.Bool)]
229          private static extern bool CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, int dwCreationFlags, IntPtr lpEnvironment, string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out PROCESS_INFORMATION lpProcessInformation);
230  
231          [DllImport("advapi32.dll", EntryPoint = "DuplicateTokenEx")]
232          [return: MarshalAs(UnmanagedType.Bool)]
233          private static extern bool DuplicateTokenEx(IntPtr ExistingTokenHandle, uint dwDesiredAccess, ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType, int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);
234  
235          [DllImport("kernel32.dll")]
236          private static extern IntPtr OpenProcess(uint dwDesiredAccess, [MarshalAs(UnmanagedType.Bool)] bool bInheritHandle, uint dwProcessId);
237  
238          [DllImport("advapi32", SetLastError = true)]
239          [SuppressUnmanagedCodeSecurityAttribute]
240          [return: MarshalAs(UnmanagedType.Bool)]
241          private static extern bool OpenProcessToken(
242              IntPtr ProcessHandle, // handle to process
243              int DesiredAccess, // desired access to process
244              ref IntPtr TokenHandle); // handle to open access token
245  
246          [DllImport("advapi32.dll", SetLastError = true)]
247          [return: MarshalAs(UnmanagedType.Bool)]
248          private static extern bool AdjustTokenPrivileges(IntPtr TokenHandle, [MarshalAs(UnmanagedType.Bool)] bool DisableAllPrivileges, ref TOKEN_PRIVILEGES NewState, int BufferLength, IntPtr PreviousState, IntPtr ReturnLength);
249  
250          [DllImport("userenv.dll", SetLastError = true)]
251          [return: MarshalAs(UnmanagedType.Bool)]
252          private static extern bool CreateEnvironmentBlock(ref IntPtr lpEnvironment, IntPtr hToken, [MarshalAs(UnmanagedType.Bool)] bool bInherit);
253  
254          [DllImport("sas.dll", SetLastError = true)]
255          internal static extern IntPtr SendSAS([MarshalAs(UnmanagedType.Bool)] bool AsUser);
256  
257          [SuppressMessage("Microsoft.Design", "CA1031:DoNotCatchGeneralExceptionTypes", Justification = "Dotnet port with style preservation")]
258          [return: MarshalAs(UnmanagedType.Bool)]
259          internal static bool CreateProcessAsSystemAccountOnSpecificDesktop(string CommandLine, string Desktop, int NoOfTry, int sessionId = -1)
260          {
261              int lastError;
262              int dwSessionId = sessionId < 0 ? (int)WTSGetActiveConsoleSessionId() : sessionId;
263              int winlogonPid = 0;
264              IntPtr hUserTokenDup = IntPtr.Zero, hPToken = IntPtr.Zero, hProcess = IntPtr.Zero;
265  
266              try
267              {
268                  int noTry = 0;
269  
270                  // At startup, services may start before winlogon.
271                  do
272                  {
273                      Process[] p = Process.GetProcessesByName("winlogon");
274                      if (p != null)
275                      {
276                          for (int i = 0; i < p.Length; i++)
277                          {
278                              if (p[i].SessionId == dwSessionId)
279                              {
280                                  winlogonPid = p[i].Id;
281                                  break;
282                              }
283                          }
284                      }
285  
286                      noTry++;
287                      if (winlogonPid == 0 && noTry < NoOfTry)
288                      {
289                          Thread.Sleep(1000);
290                      }
291                  }
292                  while (winlogonPid == 0 && noTry < NoOfTry);
293  
294                  if (winlogonPid == 0)
295                  {
296                      return false;
297                  }
298  
299                  STARTUPINFO si = default(STARTUPINFO);
300                  si.cb = (int)Marshal.SizeOf(si);
301                  si.lpDesktop = "winsta0\\" + Desktop;
302  
303                  hProcess = OpenProcess(MAXIMUM_ALLOWED, false, (uint)winlogonPid);
304  
305                  if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE, ref hPToken))
306                  {
307                      lastError = Marshal.GetLastWin32Error();
308                      CloseHandle(hProcess);
309                      return false;
310                  }
311  
312                  SECURITY_ATTRIBUTES sa = default(SECURITY_ATTRIBUTES);
313                  sa.Length = Marshal.SizeOf(sa);
314  
315                  if (!DuplicateTokenEx(hPToken, MAXIMUM_ALLOWED, ref sa, (int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification, (int)TOKEN_TYPE.TokenPrimary, ref hUserTokenDup))
316                  {
317                      lastError = Marshal.GetLastWin32Error();
318                      CloseHandle(hProcess);
319                      CloseHandle(hPToken);
320                      return false;
321                  }
322  
323                  uint dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
324                  IntPtr pEnv = IntPtr.Zero;
325  
326                  if (CreateEnvironmentBlock(ref pEnv, hUserTokenDup, true))
327                  {
328                      dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
329                  }
330                  else
331                  {
332                      lastError = Marshal.GetLastWin32Error();
333                      pEnv = IntPtr.Zero;
334                  }
335  
336                  // Launch the process
337                  PROCESS_INFORMATION pi = default(PROCESS_INFORMATION);
338                  bool rv = CreateProcessAsUser(
339                      hUserTokenDup,            // client's access token
340                      null,                   // file to execute
341                      CommandLine,            // command line
342                      ref sa,                 // pointer to process SECURITY_ATTRIBUTES
343                      ref sa,                 // pointer to thread SECURITY_ATTRIBUTES
344                      false,                  // handles are not inheritable
345                      (int)dwCreationFlags,   // creation flags
346                      pEnv,                   // pointer to new environment block
347                      null,                   // name of current directory
348                      ref si,                 // pointer to STARTUPINFO structure
349                      out pi); // receives information about new process
350  
351                  // GetLastError should be nonezero
352                  int createProcessAsUserRv = Marshal.GetLastWin32Error();
353  
354                  // Close handles task
355                  CloseHandle(hProcess);
356                  CloseHandle(hUserTokenDup);
357                  CloseHandle(hPToken);
358  
359                  if (rv)
360                  {
361                      return true;
362                  }
363                  else
364                  {
365                      return false;
366                  }
367              }
368              catch (Exception)
369              {
370                  return false;
371              }
372          }
373  
374  #if DESKTOP_STUFFS
375          [DllImport("kernel32.dll")]
376          private static extern UInt32 GetCurrentThreadId();
377  
378          [DllImport("user32.dll", SetLastError = true)]
379          private static extern IntPtr GetThreadDesktop(UInt32 dwThreadId);
380  
381          [DllImport("user32.dll", SetLastError = true)]
382          private static extern bool SetThreadDesktop(IntPtr hDesktop);
383  
384          [DllImport("user32.dll", SetLastError = true)]
385          private static extern IntPtr OpenInputDesktop(UInt32 dwFlags, bool fInherit, UInt32 dwDesiredAccess);
386  
387          private const int UOI_FLAGS = 1;
388          private const int UOI_NAME = 2;
389          private const int UOI_TYPE = 3;
390          private const int UOI_USER_SID = 4;
391          private const UInt32 DESKTOP_WRITEOBJECTS = 0x0080;
392          private const UInt32 DESKTOP_READOBJECTS = 0x0001;
393  
394          [DllImport("user32.dll", SetLastError = true)]
395          private static extern bool GetUserObjectInformation(IntPtr hObj, int nIndex, [Out] byte[] pvInfo, int nLength, out UInt32 lpnLengthNeeded);
396  
397          internal static string GetMyDesktop()
398          {
399              UInt32 nLengthNeeded;
400              byte[] arThreadDesktop = new byte[256];
401              IntPtr hD = GetThreadDesktop(GetCurrentThreadId());
402              if (hD != IntPtr.Zero)
403              {
404                  GetUserObjectInformation(hD, UOI_NAME, arThreadDesktop, arThreadDesktop.Length, out nLengthNeeded);
405                  return ASCIIEncoding.ASCII.GetString(arThreadDesktop);
406              }
407              return "";
408          }
409  
410          internal static string GetInputDesktop()
411          {
412              UInt32 nLengthNeeded;
413              byte[] arInputDesktop = new byte[256];
414              IntPtr hD = OpenInputDesktop(0, false, DESKTOP_READOBJECTS);
415              if (hD != IntPtr.Zero)
416              {
417                  GetUserObjectInformation(hD, UOI_NAME, arInputDesktop, arInputDesktop.Length, out nLengthNeeded);
418                  return ASCIIEncoding.ASCII.GetString(arInputDesktop);
419              }
420              return "";
421          }
422  #endif
423      }
424  }