From e84b4a12fbf62b7867959d5dfd58250cd9181330 Mon Sep 17 00:00:00 2001 From: Kirill Volinsky Date: Sat, 20 Oct 2012 11:11:21 +0000 Subject: PluginUpdater: added uac elevation. but it restarts miranda: close current process and starts new miranda with admins rights. Don't find information how elevate current process git-svn-id: http://svn.miranda-ng.org/main/trunk@1988 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/PluginUpdater/src/Common.h | 11 ++ plugins/PluginUpdater/src/Notifications.cpp | 194 ++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) diff --git a/plugins/PluginUpdater/src/Common.h b/plugins/PluginUpdater/src/Common.h index 1e05b9b336..9efcd8b875 100644 --- a/plugins/PluginUpdater/src/Common.h +++ b/plugins/PluginUpdater/src/Common.h @@ -51,6 +51,17 @@ Boston, MA 02111-1307, USA. #include "resource.h" #include "Notifications.h" +// Enable Visual Style +#if defined _M_IX86 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='x86' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_IA64 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='ia64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#elif defined _M_X64 +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='amd64' publicKeyToken='6595b64144ccf1df' language='*'\"") +#else +#pragma comment(linker,"/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#endif + #define MODNAME "PluginUpdater" #define MODULEA "Plugin Updater" #define MODULEW L"Plugin Updater" diff --git a/plugins/PluginUpdater/src/Notifications.cpp b/plugins/PluginUpdater/src/Notifications.cpp index c11b805789..b265090530 100644 --- a/plugins/PluginUpdater/src/Notifications.cpp +++ b/plugins/PluginUpdater/src/Notifications.cpp @@ -313,6 +313,164 @@ static void ResizeVert(HWND hDlg, int yy) SetWindowPos(hDlg, 0, 0, 0, r.right, r.bottom, SWP_NOMOVE | SWP_NOZORDER); } +// +// FUNCTION: IsRunAsAdmin() +// +// PURPOSE: The function checks whether the current process is run as +// administrator. In other words, it dictates whether the primary access +// token of the process belongs to user account that is a member of the +// local Administrators group and it is elevated. +// +// RETURN VALUE: Returns TRUE if the primary access token of the process +// belongs to user account that is a member of the local Administrators +// group and it is elevated. Returns FALSE if the token does not. +// +// EXCEPTION: If this function fails, it throws a C++ DWORD exception which +// contains the Win32 error code of the failure. +// +// EXAMPLE CALL: +// try +// { +// if (IsRunAsAdmin()) +// wprintf (L"Process is run as administrator\n"); +// else +// wprintf (L"Process is not run as administrator\n"); +// } +// catch (DWORD dwError) +// { +// wprintf(L"IsRunAsAdmin failed w/err %lu\n", dwError); +// } +// +BOOL IsRunAsAdmin() +{ + BOOL fIsRunAsAdmin = FALSE; + DWORD dwError = ERROR_SUCCESS; + PSID pAdministratorsGroup = NULL; + + // Allocate and initialize a SID of the administrators group. + SID_IDENTIFIER_AUTHORITY NtAuthority = SECURITY_NT_AUTHORITY; + if (!AllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &pAdministratorsGroup)) + { + dwError = GetLastError(); + goto Cleanup; + } + + // Determine whether the SID of administrators group is enabled in + // the primary access token of the process. + if (!CheckTokenMembership(NULL, pAdministratorsGroup, &fIsRunAsAdmin)) + { + dwError = GetLastError(); + goto Cleanup; + } + +Cleanup: + // Centralized cleanup for all allocated resources. + if (pAdministratorsGroup) + { + FreeSid(pAdministratorsGroup); + pAdministratorsGroup = NULL; + } + + // Throw the error if something failed in the function. + if (ERROR_SUCCESS != dwError) + { + throw dwError; + } + + return fIsRunAsAdmin; +} + +// +// FUNCTION: IsProcessElevated() +// +// PURPOSE: The function gets the elevation information of the current +// process. It dictates whether the process is elevated or not. Token +// elevation is only available on Windows Vista and newer operating +// systems, thus IsProcessElevated throws a C++ exception if it is called +// on systems prior to Windows Vista. It is not appropriate to use this +// function to determine whether a process is run as administartor. +// +// RETURN VALUE: Returns TRUE if the process is elevated. Returns FALSE if +// it is not. +// +// EXCEPTION: If this function fails, it throws a C++ DWORD exception +// which contains the Win32 error code of the failure. For example, if +// IsProcessElevated is called on systems prior to Windows Vista, the error +// code will be ERROR_INVALID_PARAMETER. +// +// NOTE: TOKEN_INFORMATION_CLASS provides TokenElevationType to check the +// elevation type (TokenElevationTypeDefault / TokenElevationTypeLimited / +// TokenElevationTypeFull) of the process. It is different from +// TokenElevation in that, when UAC is turned off, elevation type always +// returns TokenElevationTypeDefault even though the process is elevated +// (Integrity Level == High). In other words, it is not safe to say if the +// process is elevated based on elevation type. Instead, we should use +// TokenElevation. +// +// EXAMPLE CALL: +// try +// { +// if (IsProcessElevated()) +// wprintf (L"Process is elevated\n"); +// else +// wprintf (L"Process is not elevated\n"); +// } +// catch (DWORD dwError) +// { +// wprintf(L"IsProcessElevated failed w/err %lu\n", dwError); +// } +// +BOOL IsProcessElevated() +{ + BOOL fIsElevated = FALSE; + DWORD dwError = ERROR_SUCCESS; + HANDLE hToken = NULL; + + // Open the primary access token of the process with TOKEN_QUERY. + if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) + { + dwError = GetLastError(); + goto Cleanup; + } + + // Retrieve token elevation information. + TOKEN_ELEVATION elevation; + DWORD dwSize; + if (!GetTokenInformation(hToken, TokenElevation, &elevation, sizeof(elevation), &dwSize)) + { + // When the process is run on operating systems prior to Windows + // Vista, GetTokenInformation returns FALSE with the + // ERROR_INVALID_PARAMETER error code because TokenElevation is + // not supported on those operating systems. + dwError = GetLastError(); + goto Cleanup; + } + + fIsElevated = elevation.TokenIsElevated; + +Cleanup: + // Centralized cleanup for all allocated resources. + if (hToken) + { + CloseHandle(hToken); + hToken = NULL; + } + + // Throw the error if something failed in the function. + if (ERROR_SUCCESS != dwError) + { + throw dwError; + } + + return fIsElevated; +} + INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam) { HWND hwndList = GetDlgItem(hDlg, IDC_LIST_UPDATES); @@ -323,6 +481,10 @@ INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam TranslateDialogDefault( hDlg ); SendMessage(hwndList, LVM_SETEXTENDEDLISTVIEWSTYLE, 0, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES); { + OSVERSIONINFO osver = { sizeof(osver) }; + if (GetVersionEx(&osver) && osver.dwMajorVersion >= 6) + // Running Windows Vista or later (major version >= 6). + Button_SetElevationRequiredState(GetDlgItem(hDlg, IDOK), !IsProcessElevated()); RECT r; GetClientRect(hwndList, &r); @@ -418,6 +580,38 @@ INT_PTR CALLBACK DlgUpdate(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam EnableWindow( GetDlgItem(hDlg, IDOK), FALSE); EnableWindow( GetDlgItem(hDlg, IDC_SELALL), FALSE); EnableWindow( GetDlgItem(hDlg, IDC_SELNONE), FALSE); + + // Check the current process's "run as administrator" status. + // Elevate the process if it is not run as administrator. + if (!IsRunAsAdmin()) + { + wchar_t szPath[MAX_PATH], cmdLine[100]; + GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)); + TCHAR *profilename = Utils_ReplaceVarsT(_T("%miranda_profilename%")); + mir_sntprintf(cmdLine, SIZEOF(cmdLine), _T(" /restart:%d /profile=%s"), GetCurrentProcessId(), profilename); + // Launch itself as administrator. + SHELLEXECUTEINFO sei = { sizeof(sei) }; + sei.lpVerb = L"runas"; + sei.lpFile = szPath; + sei.lpParameters = cmdLine; + sei.hwnd = hDlg; + sei.nShow = SW_NORMAL; + + if (!ShellExecuteEx(&sei)) + { + DWORD dwError = GetLastError(); + if (dwError == ERROR_CANCELLED) + { + // The user refused to allow privileges elevation. + // Do nothing ... + } + } + else + { + DestroyWindow(hDlg); // Quit itself + CallService("CloseAction", 0, 0); + } + } mir_forkthread(ApplyUpdates, hDlg); return TRUE; -- cgit v1.2.3