StephaneLenclud@436: #include "UserAccountControl.h" StephaneLenclud@436: StephaneLenclud@436: #include StephaneLenclud@436: #pragma comment (lib, "kernel32.lib") StephaneLenclud@436: #pragma comment (lib, "advapi32.lib") StephaneLenclud@436: StephaneLenclud@436: #include StephaneLenclud@436: #include StephaneLenclud@436: #include StephaneLenclud@436: StephaneLenclud@436: using namespace msclr::interop; StephaneLenclud@436: StephaneLenclud@436: using namespace System::ComponentModel; StephaneLenclud@436: using namespace Microsoft::Win32; StephaneLenclud@436: StephaneLenclud@436: namespace UacHelpers { StephaneLenclud@436: StephaneLenclud@436: Process^ UserAccountControl::CreateProcessAsAdmin(System::String^ exePath, System::String^ arguments) StephaneLenclud@436: { StephaneLenclud@436: ProcessStartInfo^ psi = gcnew ProcessStartInfo(exePath, arguments); StephaneLenclud@436: psi->UseShellExecute = true; StephaneLenclud@436: psi->Verb = "runas"; StephaneLenclud@436: return Process::Start(psi); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: Process^ UserAccountControl::CreateProcessAsStandardUser(System::String^ exePath, System::String^ arguments) StephaneLenclud@436: { StephaneLenclud@436: marshal_context context; StephaneLenclud@436: StephaneLenclud@436: //If the current process is not elevated, then there's no reason to go through the hassle -- StephaneLenclud@436: //just use the standard System.Diagnostics.Process facilities. StephaneLenclud@436: if (!IsCurrentProcessElevated) StephaneLenclud@436: { StephaneLenclud@436: return Process::Start(exePath, arguments); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: //The following implementation is roughly based on Aaron Margosis' post: StephaneLenclud@436: //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 StephaneLenclud@436: StephaneLenclud@436: //Enable SeIncreaseQuotaPrivilege in this process. (This requires administrative privileges.) StephaneLenclud@436: HANDLE hProcessToken = NULL; StephaneLenclud@436: if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hProcessToken)) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: } StephaneLenclud@436: else StephaneLenclud@436: { StephaneLenclud@436: TOKEN_PRIVILEGES tkp; StephaneLenclud@436: tkp.PrivilegeCount = 1; StephaneLenclud@436: LookupPrivilegeValueW(NULL, SE_INCREASE_QUOTA_NAME, &tkp.Privileges[0].Luid); StephaneLenclud@436: tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; StephaneLenclud@436: AdjustTokenPrivileges(hProcessToken, FALSE, &tkp, 0, NULL, NULL); StephaneLenclud@436: DWORD dwLastErr = GetLastError(); StephaneLenclud@436: CloseHandle(hProcessToken); StephaneLenclud@436: if (ERROR_SUCCESS != dwLastErr) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(dwLastErr); StephaneLenclud@436: } StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: //Get window handle representing the desktop shell. This might not work if there is no shell window, or when StephaneLenclud@436: //using a custom shell. Also note that we're assuming that the shell is not running elevated. StephaneLenclud@436: HWND hShellWnd = GetShellWindow(); StephaneLenclud@436: if (hShellWnd == NULL) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew System::InvalidOperationException("Unable to locate shell window; you might be using a custom shell"); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: //Get the ID of the desktop shell process. StephaneLenclud@436: DWORD dwShellPID; StephaneLenclud@436: GetWindowThreadProcessId(hShellWnd, &dwShellPID); StephaneLenclud@436: if (dwShellPID == 0) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: //Open the desktop shell process in order to get the process token. StephaneLenclud@436: HANDLE hShellProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwShellPID); StephaneLenclud@436: if (hShellProcess == NULL) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: HANDLE hShellProcessToken = NULL; StephaneLenclud@436: HANDLE hPrimaryToken = NULL; StephaneLenclud@436: try StephaneLenclud@436: { StephaneLenclud@436: //Get the process token of the desktop shell. StephaneLenclud@436: if (!OpenProcessToken(hShellProcess, TOKEN_DUPLICATE, &hShellProcessToken)) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: //Duplicate the shell's process token to get a primary token. StephaneLenclud@436: const DWORD dwTokenRights = TOKEN_QUERY | TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE | TOKEN_ADJUST_DEFAULT | TOKEN_ADJUST_SESSIONID; StephaneLenclud@436: if (!DuplicateTokenEx(hShellProcessToken, dwTokenRights, NULL, SecurityImpersonation, TokenPrimary, &hPrimaryToken)) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: //Start the target process with the new token. StephaneLenclud@436: STARTUPINFO si = {0}; si.cb = sizeof(si); StephaneLenclud@436: PROCESS_INFORMATION pi = {0}; StephaneLenclud@436: if (!CreateProcessWithTokenW(hPrimaryToken, 0, StephaneLenclud@436: context.marshal_as(exePath), context.marshal_as(exePath + " " + arguments), StephaneLenclud@436: 0, NULL, NULL, &si, &pi)) StephaneLenclud@436: { StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: } StephaneLenclud@436: CloseHandle(pi.hProcess); StephaneLenclud@436: CloseHandle(pi.hThread); StephaneLenclud@436: StephaneLenclud@436: return Process::GetProcessById(pi.dwProcessId); StephaneLenclud@436: } StephaneLenclud@436: finally StephaneLenclud@436: { StephaneLenclud@436: if (hShellProcessToken != NULL) StephaneLenclud@436: CloseHandle(hShellProcessToken); StephaneLenclud@436: StephaneLenclud@436: if (hPrimaryToken != NULL) StephaneLenclud@436: CloseHandle(hPrimaryToken); StephaneLenclud@436: StephaneLenclud@436: if (hShellProcess != NULL) StephaneLenclud@436: CloseHandle(hShellProcess); StephaneLenclud@436: } StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: bool UserAccountControl::IsUserAdmin::get() StephaneLenclud@436: { StephaneLenclud@436: if (UserAccountControl::IsUacEnabled) StephaneLenclud@436: return GetProcessTokenElevationType() != TokenElevationTypeDefault; //split token StephaneLenclud@436: StephaneLenclud@436: //If UAC is off, we can't rely on the token; check for Admin group. StephaneLenclud@436: return WindowsPrincipal(WindowsIdentity::GetCurrent()).IsInRole("Administrators"); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: bool UserAccountControl::IsUacEnabled::get() StephaneLenclud@436: { StephaneLenclud@436: //Check the HKLM\Software\Microsoft\Windows\CurrentVersion\Policies\System\EnableLUA registry value. StephaneLenclud@436: RegistryKey^ key = Registry::LocalMachine->OpenSubKey(UacRegistryKey, false); StephaneLenclud@436: return key->GetValue(UacRegistryValue)->Equals(1); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: void UserAccountControl::DisableUac() StephaneLenclud@436: { StephaneLenclud@436: SetUacRegistryValue(false); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: void UserAccountControl::DisableUacAndRestartWindows() StephaneLenclud@436: { StephaneLenclud@436: DisableUac(); StephaneLenclud@436: RestartWindows(); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: void UserAccountControl::EnableUac() StephaneLenclud@436: { StephaneLenclud@436: SetUacRegistryValue(true); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: void UserAccountControl::EnableUacAndRestartWindows() StephaneLenclud@436: { StephaneLenclud@436: EnableUac(); StephaneLenclud@436: RestartWindows(); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: bool UserAccountControl::IsCurrentProcessElevated::get() StephaneLenclud@436: { StephaneLenclud@436: return GetProcessTokenElevationType() == TokenElevationTypeFull; //elevated StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: bool UserAccountControl::IsCurrentProcessVirtualized::get() StephaneLenclud@436: { StephaneLenclud@436: HANDLE hToken; StephaneLenclud@436: try StephaneLenclud@436: { StephaneLenclud@436: if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: StephaneLenclud@436: DWORD virtualizationEnabled; StephaneLenclud@436: DWORD dwSize; StephaneLenclud@436: if (!GetTokenInformation(hToken, TokenVirtualizationEnabled, &virtualizationEnabled, sizeof(virtualizationEnabled), &dwSize)) StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: StephaneLenclud@436: return virtualizationEnabled != 0; StephaneLenclud@436: } StephaneLenclud@436: finally StephaneLenclud@436: { StephaneLenclud@436: CloseHandle(hToken); StephaneLenclud@436: } StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: int UserAccountControl::GetProcessTokenElevationType() StephaneLenclud@436: { StephaneLenclud@436: HANDLE hToken; StephaneLenclud@436: try StephaneLenclud@436: { StephaneLenclud@436: if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: StephaneLenclud@436: TOKEN_ELEVATION_TYPE elevationType; StephaneLenclud@436: DWORD dwSize; StephaneLenclud@436: if (!GetTokenInformation(hToken, TokenElevationType, &elevationType, sizeof(elevationType), &dwSize)) StephaneLenclud@436: throw gcnew Win32Exception(GetLastError()); StephaneLenclud@436: StephaneLenclud@436: return elevationType; StephaneLenclud@436: } StephaneLenclud@436: finally StephaneLenclud@436: { StephaneLenclud@436: CloseHandle(hToken); StephaneLenclud@436: } StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: void UserAccountControl::SetUacRegistryValue(bool enabled) StephaneLenclud@436: { StephaneLenclud@436: RegistryKey^ key = Registry::LocalMachine->OpenSubKey(UacRegistryKey, true); StephaneLenclud@436: key->SetValue(UacRegistryValue, enabled ? 1 : 0); StephaneLenclud@436: } StephaneLenclud@436: StephaneLenclud@436: void UserAccountControl::RestartWindows() StephaneLenclud@436: { StephaneLenclud@436: InitiateSystemShutdownEx(NULL, NULL, 0/*Timeout*/, StephaneLenclud@436: TRUE/*ForceAppsClosed*/, TRUE/*RebootAfterShutdown*/, StephaneLenclud@436: SHTDN_REASON_MAJOR_OPERATINGSYSTEM | SHTDN_REASON_MINOR_RECONFIG | SHTDN_REASON_FLAG_PLANNED); StephaneLenclud@436: //This shutdown flag corresponds to: "Operating System: Reconfiguration (Planned)". StephaneLenclud@436: } StephaneLenclud@436: }