// This code mimics the MSDN defined way to adjust privilege for shutdown // http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sysinfo/base/shutting_down.asp private bool GrantShutdownPrivilege() { bool grantSuccess = false; IntPtr processToken = IntPtr.Zero; IntPtr processHandle = IntPtr.Zero; WindowsApi.TOKEN_PRIVILEGES tokenPrivileges = new WindowsApi.TOKEN_PRIVILEGES(); long luid = 0; int returnLen = 0; try { processHandle = WindowsApi.GetCurrentProcess(); bool result = WindowsApi.OpenProcessToken(processHandle, WindowsApi.TOKEN_ADJUST_PRIVILEGES | WindowsApi.TOKEN_QUERY, ref processToken); if (!result) { return(grantSuccess); } WindowsApi.LookupPrivilegeValue(null, WindowsApi.SE_SHUTDOWN_NAME, ref luid); tokenPrivileges.PrivilegeCount = 1; tokenPrivileges.Privileges.Luid = luid; tokenPrivileges.Privileges.Attributes = WindowsApi.SE_PRIVILEGE_ENABLED; result = WindowsApi.AdjustTokenPrivileges(processToken, false, ref tokenPrivileges, 0, IntPtr.Zero, ref returnLen); if (WindowsApi.GetLastError() != 0) { throw new Exception("Failed to grant shutdown privilege"); } grantSuccess = true; } catch (Exception ex) { LogInstallMessage(EventLogEntryType.Error, m_logMessagePrefix + ex.Message); } finally { if (processToken != IntPtr.Zero) { WindowsApi.CloseHandle(processToken); } } return(grantSuccess); }
public static Process CreateProcessAsStandardUser(string fileName, string arguments = "") { // The following implementation is roughly based on Aaron Margosis' post: // http://blogs.msdn.com/aaron_margosis/archive/2009/06/06/faq-how-do-i-start-a-program-as-the-desktop-user-from-an-elevated-app.aspx IntPtr hProcessToken = IntPtr.Zero; IntPtr hShellProcess = IntPtr.Zero; IntPtr hShellProcessToken = IntPtr.Zero; IntPtr hPrimaryToken = IntPtr.Zero; try { if (!WindowsApi.OpenProcessToken(WindowsApi.GetCurrentProcess(), WindowsApi.TOKEN_ADJUST_PRIVILEGES, ref hProcessToken)) { throw new Win32Exception(WindowsApi.GetLastError()); } // Enable SeIncreaseQuotaPrivilege in this process. (This requires administrative privileges.) WindowsApi.TOKEN_PRIVILEGES tkp = new WindowsApi.TOKEN_PRIVILEGES(); long luid = 0; int returnLen = 0; WindowsApi.LookupPrivilegeValue(null, WindowsApi.SE_INCREASE_QUOTA_NAME, ref luid); tkp.PrivilegeCount = 1; tkp.Privileges.Luid = luid; tkp.Privileges.Attributes = WindowsApi.SE_PRIVILEGE_ENABLED; WindowsApi.AdjustTokenPrivileges(hProcessToken, false, ref tkp, 0, IntPtr.Zero, ref returnLen); int dwLastErr = WindowsApi.GetLastError(); if (dwLastErr != 0) { throw new Win32Exception(dwLastErr); } // Get window handle representing the desktop shell. This might not work if there is no shell window, or when // using a custom shell. Also note that we're assuming that the shell is not running elevated. IntPtr hShellWnd = WindowsApi.GetShellWindow(); if (hShellWnd == IntPtr.Zero) { throw new InvalidOperationException("Unable to locate shell window. System might be using a custom shell."); } // Get the ID of the desktop shell process. uint dwShellPID; WindowsApi.GetWindowThreadProcessId(hShellWnd, out dwShellPID); if (dwShellPID == 0) { throw new Win32Exception(WindowsApi.GetLastError()); } // Open the desktop shell process in order to get the process token. hShellProcess = WindowsApi.OpenProcess(WindowsApi.ProcessAccessTypes.PROCESS_QUERY_INFORMATION, false, dwShellPID); if (hShellProcess == IntPtr.Zero) { throw new Win32Exception(WindowsApi.GetLastError()); } // Get the process token of the desktop shell. if (!WindowsApi.OpenProcessToken(hShellProcess, WindowsApi.TOKEN_DUPLICATE, ref hShellProcessToken)) { throw new Win32Exception(WindowsApi.GetLastError()); } // Duplicate the shell's process token to get a primary token. const uint dwTokenRights = WindowsApi.TOKEN_QUERY | WindowsApi.TOKEN_ASSIGN_PRIMARY | WindowsApi.TOKEN_DUPLICATE | WindowsApi.TOKEN_ADJUST_DEFAULT | WindowsApi.TOKEN_ADJUST_SESSIONID; if (!WindowsApi.DuplicateTokenEx(hShellProcessToken, dwTokenRights, IntPtr.Zero, WindowsApi.SECURITY_IMPERSONATION_LEVEL.SecurityImpersonation, WindowsApi.TOKEN_TYPE.TokenPrimary, out hPrimaryToken)) { throw new Win32Exception(WindowsApi.GetLastError()); } // Start the target process with the new token. WindowsApi.PROCESS_INFORMATION pi; WindowsApi.STARTUPINFO si = new WindowsApi.STARTUPINFO(); si.cb = Marshal.SizeOf(si); if (!WindowsApi.CreateProcessWithTokenW(hPrimaryToken, 0, null, fileName + " " + arguments, 0, IntPtr.Zero, null, ref si, out pi)) { throw new Win32Exception(WindowsApi.GetLastError()); } WindowsApi.CloseHandle(pi.hProcess); WindowsApi.CloseHandle(pi.hThread); return(Process.GetProcessById(pi.ProcessId)); } finally { if (hProcessToken != IntPtr.Zero) { WindowsApi.CloseHandle(hProcessToken); } if (hShellProcessToken != IntPtr.Zero) { WindowsApi.CloseHandle(hShellProcessToken); } if (hPrimaryToken != IntPtr.Zero) { WindowsApi.CloseHandle(hPrimaryToken); } if (hShellProcess != IntPtr.Zero) { WindowsApi.CloseHandle(hShellProcess); } } }