aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2016-09-16 01:47:56 +0300
committerEgor Tensin <Egor.Tensin@gmail.com>2016-09-16 01:47:56 +0300
commitfbd6445c68745d484d5df8c75b0c12054185958f (patch)
treec8eb6da6b89d88f530647f408fd2c47669e1bb27 /src
parent.hpp instead of .h for C++ headers (diff)
downloadprivilege-check-fbd6445c68745d484d5df8c75b0c12054185958f.tar.gz
privilege-check-fbd6445c68745d484d5df8c75b0c12054185958f.zip
move source files to src/
Diffstat (limited to 'src')
-rw-r--r--src/error.hpp26
-rw-r--r--src/handle.hpp64
-rw-r--r--src/main.cpp210
-rw-r--r--src/main.rc112
-rw-r--r--src/os.hpp30
-rw-r--r--src/process.hpp40
-rw-r--r--src/resource_ids.h23
-rw-r--r--src/sid.hpp68
-rw-r--r--src/token.hpp175
9 files changed, 748 insertions, 0 deletions
diff --git a/src/error.hpp b/src/error.hpp
new file mode 100644
index 0000000..2ea7f85
--- /dev/null
+++ b/src/error.hpp
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <Windows.h>
+
+#include <system_error>
+
+typedef std::system_error Error;
+
+namespace error
+{
+ inline void raise(const char* function_name)
+ {
+ const auto ec = GetLastError();
+ throw std::system_error(ec, std::system_category(), function_name);
+ }
+
+ void report(const Error& e)
+ {
+ MessageBoxA(NULL, e.what(), NULL, MB_OK);
+ }
+
+ int get_code(const Error& e)
+ {
+ return e.code().value();
+ }
+}
diff --git a/src/handle.hpp b/src/handle.hpp
new file mode 100644
index 0000000..5f83f24
--- /dev/null
+++ b/src/handle.hpp
@@ -0,0 +1,64 @@
+#pragma once
+
+#include <Windows.h>
+
+#include <cassert>
+
+#include <memory>
+#include <utility>
+
+class Handle
+{
+public:
+ Handle() = default;
+
+ explicit Handle(HANDLE raw)
+ : impl{raw}
+ { }
+
+ Handle(Handle&& other) noexcept
+ {
+ swap(other);
+ }
+
+ Handle& operator=(Handle other) noexcept
+ {
+ swap(other);
+ return *this;
+ }
+
+ void swap(Handle& other) noexcept
+ {
+ using std::swap;
+ swap(impl, other.impl);
+ }
+
+ operator HANDLE() const
+ {
+ return impl.get();
+ }
+
+private:
+ struct Close
+ {
+ void operator()(HANDLE raw) const
+ {
+ if (raw == NULL || raw == INVALID_HANDLE_VALUE)
+ return;
+ const auto ret = CloseHandle(raw);
+ assert(ret);
+ }
+ };
+
+ std::unique_ptr<void, Close> impl;
+
+ Handle(const Handle&) = delete;
+};
+
+namespace std
+{
+ void swap(Handle& a, Handle& b) noexcept
+ {
+ a.swap(b);
+ }
+}
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100644
index 0000000..1777d79
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,210 @@
+#include "error.hpp"
+#include "os.hpp"
+#include "process.hpp"
+#include "resource_ids.h"
+#include "sid.hpp"
+#include "token.hpp"
+
+#include <Windows.h>
+#include <CommCtrl.h>
+#include <windowsx.h>
+
+#include <string>
+
+#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"")
+
+bool is_user_in_administrators()
+{
+ const auto token = token::impersonate(
+ token::get_linked(
+ token::open_for_current_process(token::permissions::query() | token::permissions::duplicate())));
+
+ return token::belongs(token, sid::builtin_administrators());
+}
+
+bool is_run_as_administrator()
+{
+ return token::belongs(token::dumb(), sid::builtin_administrators());
+}
+
+bool is_elevated()
+{
+ return token::is_elevated(token::open_for_current_process());
+}
+
+void set_label(HWND root, int id, bool val)
+{
+ const auto label = GetDlgItem(root, id);
+ SetWindowTextW(label, val ? L"True" : L"False");
+}
+
+void set_label(HWND root, int id, const wchar_t* s)
+{
+ const auto label = GetDlgItem(root, id);
+ SetWindowTextW(label, s);
+}
+
+void set_label(HWND root, int id, const std::wstring& s)
+{
+ const auto label = GetDlgItem(root, id);
+ SetWindowTextW(label, s.c_str());
+}
+
+BOOL on_init_dialog(HWND wnd, HWND, LPARAM)
+{
+ try
+ {
+ set_label(wnd, IDC_ADMINISTRATOR, is_user_in_administrators());
+ }
+ catch (const Error& e)
+ {
+ set_label(wnd, IDC_ADMINISTRATOR, L"N/A");
+ error::report(e);
+ }
+
+ try
+ {
+ set_label(wnd, IDC_RUN_AS_ADMINISTRATOR, is_run_as_administrator());
+ }
+ catch (const Error& e)
+ {
+ set_label(wnd, IDC_RUN_AS_ADMINISTRATOR, L"N/A");
+ error::report(e);
+ }
+
+ if (os::is_vista_or_later())
+ {
+ try
+ {
+ const auto elevated = is_elevated();
+ set_label(wnd, IDC_ELEVATED, elevated);
+
+ const auto elevate_button = GetDlgItem(wnd, IDC_BUTTON_ELEVATE);
+ Button_SetElevationRequiredState(elevate_button, !elevated);
+ }
+ catch (const Error& e)
+ {
+ set_label(wnd, IDC_ELEVATED, L"N/A");
+ error::report(e);
+ }
+
+ try
+ {
+ set_label(wnd, IDC_INTEGRITY_LEVEL, token::integrity_level_to_string(
+ token::query_integrity_level(token::open_for_current_process())));
+ }
+ catch (const Error& e)
+ {
+ set_label(wnd, IDC_INTEGRITY_LEVEL, L"N/A");
+ error::report(e);
+ }
+ }
+ else
+ {
+ set_label(wnd, IDC_ELEVATED, L"N/A");
+ set_label(wnd, IDC_INTEGRITY_LEVEL, L"N/A");
+ }
+
+ return TRUE;
+}
+
+void on_button_elevate_click(HWND wnd)
+{
+ bool as_admin = false;
+
+ try
+ {
+ as_admin = is_run_as_administrator();
+ }
+ catch (const Error& e)
+ {
+ error::report(e);
+ return;
+ }
+
+ if (as_admin)
+ {
+ MessageBoxW(wnd, L"Already elevated!", L"Elevation", MB_OK);
+ return;
+ }
+
+ try
+ {
+ process::runas(process::get_executable_path());
+ }
+ catch (const Error& e)
+ {
+ if (error::get_code(e) != ERROR_CANCELLED)
+ error::report(e);
+ return;
+ }
+
+ EndDialog(wnd, 1);
+}
+
+void on_command(HWND wnd, int id, HWND, unsigned int)
+{
+ switch (id)
+ {
+ case IDC_BUTTON_ELEVATE:
+ on_button_elevate_click(wnd);
+ break;
+
+ case IDOK:
+ case IDCANCEL:
+ EndDialog(wnd, 0);
+ break;
+ }
+}
+
+void on_close(HWND wnd)
+{
+ EndDialog(wnd, 0);
+}
+
+INT_PTR CALLBACK dialog_main(
+ HWND wnd,
+ UINT msg,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ switch (msg)
+ {
+ HANDLE_MSG(wnd, WM_INITDIALOG, on_init_dialog);
+ HANDLE_MSG(wnd, WM_COMMAND, on_command);
+ HANDLE_MSG(wnd, WM_CLOSE, on_close);
+
+ default:
+ return FALSE;
+ }
+}
+
+int APIENTRY wWinMain(
+ HINSTANCE instance,
+ HINSTANCE,
+ wchar_t*,
+ int)
+{
+ const auto ret = DialogBoxW(
+ instance,
+ MAKEINTRESOURCE(IDD_MAINDIALOG),
+ NULL,
+ dialog_main);
+
+ switch (ret)
+ {
+ case -1:
+ try
+ {
+ error::raise("DialogBoxW");
+ }
+ catch (const Error& e)
+ {
+ error::report(e);
+ return 1;
+ }
+
+ default:
+ return static_cast<int>(ret);
+ }
+}
diff --git a/src/main.rc b/src/main.rc
new file mode 100644
index 0000000..70c04e5
--- /dev/null
+++ b/src/main.rc
@@ -0,0 +1,112 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource_ids.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+// English (United States) resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_MAINDIALOG DIALOGEX 0, 0, 120, 79
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Privilege test"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ LTEXT "Administrator?",IDC_STATIC,7,7,75,12
+ RTEXT "",IDC_ADMINISTRATOR,85,7,28,12
+ LTEXT "Run as administrator?",IDC_STATIC,7,19,75,12
+ RTEXT "",IDC_RUN_AS_ADMINISTRATOR,85,19,28,12
+ LTEXT "Elevated?",IDC_STATIC,7,31,75,12
+ RTEXT "",IDC_ELEVATED,85,31,28,12
+ LTEXT "Integrity level:",IDC_STATIC,7,43,75,12
+ RTEXT "",IDC_INTEGRITY_LEVEL,85,43,28,15
+ PUSHBUTTON "Elevate",IDC_BUTTON_ELEVATE,63,58,50,14
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// DESIGNINFO
+//
+
+#ifdef APSTUDIO_INVOKED
+GUIDELINES DESIGNINFO
+BEGIN
+ IDD_MAINDIALOG, DIALOG
+ BEGIN
+ LEFTMARGIN, 7
+ RIGHTMARGIN, 113
+ VERTGUIDE, 82
+ VERTGUIDE, 85
+ TOPMARGIN, 7
+ BOTTOMMARGIN, 72
+ HORZGUIDE, 19
+ HORZGUIDE, 31
+ HORZGUIDE, 43
+ HORZGUIDE, 58
+ END
+END
+#endif // APSTUDIO_INVOKED
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource_ids.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (United States) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/src/os.hpp b/src/os.hpp
new file mode 100644
index 0000000..1a3c52d
--- /dev/null
+++ b/src/os.hpp
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "error.hpp"
+
+#include <Windows.h>
+
+namespace os
+{
+ OSVERSIONINFOW get_version_info()
+ {
+ OSVERSIONINFOW info;
+ ZeroMemory(&info, sizeof(info));
+ info.dwOSVersionInfoSize = sizeof(info);
+
+ if (!GetVersionExW(&info))
+ error::raise("GetVersionExW");
+
+ return info;
+ }
+
+ bool is_vista_or_later(const OSVERSIONINFOW& info)
+ {
+ return info.dwMajorVersion >= 6;
+ }
+
+ bool is_vista_or_later()
+ {
+ return is_vista_or_later(get_version_info());
+ }
+}
diff --git a/src/process.hpp b/src/process.hpp
new file mode 100644
index 0000000..864d452
--- /dev/null
+++ b/src/process.hpp
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "error.hpp"
+
+#include <Windows.h>
+#include <shellapi.h>
+
+#include <array>
+#include <string>
+
+namespace process
+{
+ std::wstring get_executable_path()
+ {
+ static constexpr DWORD max_path = MAX_PATH;
+
+ std::array<wchar_t, max_path> buf;
+
+ const auto ret = GetModuleFileNameW(NULL, buf.data(), max_path);
+
+ if (GetLastError() != ERROR_SUCCESS)
+ error::raise("GetModuleFileNameW");
+
+ return buf.data();
+ }
+
+ void runas(const std::wstring& exe_path, HWND hwnd = NULL, int nShow = SW_NORMAL)
+ {
+ SHELLEXECUTEINFOW info;
+ ZeroMemory(&info, sizeof(info));
+ info.cbSize = sizeof(info);
+ info.lpVerb = L"runas";
+ info.lpFile = exe_path.c_str();
+ info.hwnd = hwnd;
+ info.nShow = nShow;
+
+ if (!ShellExecuteExW(&info))
+ error::raise("ShellExecuteExW");
+ }
+}
diff --git a/src/resource_ids.h b/src/resource_ids.h
new file mode 100644
index 0000000..4c6d90f
--- /dev/null
+++ b/src/resource_ids.h
@@ -0,0 +1,23 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by resource.rc
+//
+#define IDD_MAINDIALOG 100
+#define IDC_BUTTON_ELEVATE 1000
+#define IDC_ADMINISTRATOR 1001
+#define IDC_RUN_AS_ADMINISTRATOR 1002
+#define IDC_ELEVATED 1003
+#define IDC_INTEGRITY_LEVEL 1004
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1005
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/src/sid.hpp b/src/sid.hpp
new file mode 100644
index 0000000..15ce73b
--- /dev/null
+++ b/src/sid.hpp
@@ -0,0 +1,68 @@
+#pragma once
+
+#include "error.hpp"
+
+#include <Windows.h>
+#include <sddl.h>
+
+#include <array>
+#include <memory>
+#include <string>
+
+constexpr DWORD max_sid_size = SECURITY_MAX_SID_SIZE;
+typedef std::array<unsigned char, max_sid_size> SidBuffer;
+
+namespace sid
+{
+ SidBuffer well_known(WELL_KNOWN_SID_TYPE type)
+ {
+ SidBuffer buffer;
+ DWORD cb = static_cast<DWORD>(buffer.size());
+
+ if (!CreateWellKnownSid(type, NULL, buffer.data(), &cb))
+ error::raise("CreateWellKnownSid");
+
+ return buffer;
+ }
+
+ SidBuffer builtin_administrators()
+ {
+ /*
+ void* sid = nullptr;
+ SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY;
+
+ if (!AllocateAndInitializeSid(
+ &authority,
+ 2,
+ SECURITY_BUILTIN_DOMAIN_RID,
+ DOMAIN_ALIAS_RID_ADMINS,
+ 0, 0, 0, 0, 0, 0,
+ &sid))
+ {
+ error::raise("AllocateAndInitializeSid");
+ }
+
+ return std::unique_ptr<void, FreeSid>{sid};
+ */
+
+ return well_known(WinBuiltinAdministratorsSid);
+ }
+
+ struct DeleteSidString
+ {
+ void operator()(wchar_t* s) const
+ {
+ LocalFree(s);
+ }
+ };
+
+ std::wstring to_string(const SidBuffer& sid)
+ {
+ wchar_t* s = nullptr;
+
+ if (!ConvertSidToStringSidW(const_cast<unsigned char*>(sid.data()), &s))
+ error::raise("ConvertSidToStringSidW");
+
+ return std::unique_ptr<wchar_t, DeleteSidString>{s}.get();
+ }
+}
diff --git a/src/token.hpp b/src/token.hpp
new file mode 100644
index 0000000..5669970
--- /dev/null
+++ b/src/token.hpp
@@ -0,0 +1,175 @@
+#pragma once
+
+#include "error.hpp"
+#include "handle.hpp"
+#include "os.hpp"
+#include "sid.hpp"
+
+#include <Windows.h>
+
+#include <string>
+#include <unordered_map>
+#include <utility>
+#include <vector>
+
+namespace token
+{
+ namespace permissions
+ {
+ constexpr DWORD query() { return TOKEN_QUERY; }
+
+ constexpr DWORD duplicate() { return TOKEN_DUPLICATE; }
+ }
+
+ constexpr DWORD default_permissions = permissions::query();
+
+ // Current thread's primary impersonation token.
+ Handle dumb() { return Handle{NULL}; }
+
+ Handle open_for_process(
+ const Handle& process,
+ DWORD permissions = default_permissions)
+ {
+ HANDLE raw;
+
+ if (!OpenProcessToken(process, permissions, &raw))
+ error::raise("OpenProcessToken");
+
+ return Handle{raw};
+ }
+
+ Handle open_for_current_process(
+ DWORD permissions = default_permissions)
+ {
+ return open_for_process(Handle{GetCurrentProcess()}, permissions);
+ }
+
+ Handle get_linked(Handle&& token)
+ {
+ if (!os::is_vista_or_later())
+ return std::move(token);
+
+ auto type = TokenElevationTypeDefault;
+ DWORD cb = 0;
+
+ if (!GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &cb))
+ error::raise("GetTokenInformation");
+
+ if (type != TokenElevationTypeLimited)
+ return std::move(token);
+
+ HANDLE raw;
+
+ if (!GetTokenInformation(token, TokenLinkedToken, &raw, sizeof(raw), &cb))
+ error::raise("GetTokenInformation");
+
+ return Handle{raw};
+ }
+
+ Handle impersonate(const Handle& token)
+ {
+ HANDLE raw;
+
+ if (!DuplicateToken(token, SecurityIdentification, &raw))
+ error::raise("DuplicateToken");
+
+ return Handle{raw};
+ }
+
+ //
+ // FUNCTION: query_integrity_level()
+ //
+ // RETURN VALUE: Returns the integrity level of the current process. It is
+ // usually one of these values:
+ //
+ // SECURITY_MANDATORY_UNTRUSTED_RID (SID: S-1-16-0x0)
+ // Means untrusted level. It is used by processes started by the
+ // Anonymous group. Blocks most write access.
+ //
+ // SECURITY_MANDATORY_LOW_RID (SID: S-1-16-0x1000)
+ // Means low integrity level. It is used by Protected Mode Internet
+ // Explorer. Blocks write acess to most objects (such as files and
+ // registry keys) on the system.
+ //
+ // SECURITY_MANDATORY_MEDIUM_RID (SID: S-1-16-0x2000)
+ // Means medium integrity level. It is used by normal applications
+ // being launched while UAC is enabled.
+ //
+ // SECURITY_MANDATORY_HIGH_RID (SID: S-1-16-0x3000)
+ // Means high integrity level. It is used by administrative applications
+ // launched through elevation when UAC is enabled, or normal
+ // applications if UAC is disabled and the user is an administrator.
+ //
+ // SECURITY_MANDATORY_SYSTEM_RID (SID: S-1-16-0x4000)
+ // Means system integrity level. It is used by services and other
+ // system-level applications (such as Wininit, Winlogon, Smss, etc.)
+ //
+ DWORD query_integrity_level(const Handle& token)
+ {
+ DWORD cb = 0;
+
+ if (!GetTokenInformation(token, TokenIntegrityLevel, NULL, 0, &cb))
+ {
+ switch (GetLastError())
+ {
+ case ERROR_INSUFFICIENT_BUFFER:
+ break;
+ default:
+ error::raise("GetTokenInformation");
+ }
+ }
+
+ std::vector<unsigned char> buf(cb);
+ const auto token_level = reinterpret_cast<TOKEN_MANDATORY_LABEL*>(buf.data());
+
+ if (!GetTokenInformation(token, TokenIntegrityLevel, token_level, cb, &cb))
+ error::raise("GetTokenInformation");
+
+ // Integrity Level SIDs are in the form of S-1-16-0xXXXX. (e.g.
+ // S-1-16-0x1000 stands for low integrity level SID). There is one and
+ // only one subauthority.
+ return *GetSidSubAuthority(token_level->Label.Sid, 0);
+ }
+
+ std::wstring integrity_level_to_string(DWORD level)
+ {
+ static const std::unordered_map<DWORD, const wchar_t*> names =
+ {
+ {SECURITY_MANDATORY_UNTRUSTED_RID, L"Untrusted"},
+ {SECURITY_MANDATORY_LOW_RID, L"Low"},
+ {SECURITY_MANDATORY_MEDIUM_RID, L"Medium"},
+ {SECURITY_MANDATORY_HIGH_RID, L"High"},
+ {SECURITY_MANDATORY_SYSTEM_RID, L"System"},
+ };
+
+ static constexpr auto unknown_name = L"Unknown";
+
+ const auto it = names.find(level);
+
+ if (it == names.cend())
+ return unknown_name;
+
+ return it->second;
+ }
+
+ bool belongs(const Handle& token, const SidBuffer& sid)
+ {
+ BOOL b = FALSE;
+
+ if (!CheckTokenMembership(token, const_cast<unsigned char*>(sid.data()), &b))
+ error::raise("CheckTokenMembership");
+
+ return b != FALSE;
+ }
+
+ bool is_elevated(const Handle& token)
+ {
+ TOKEN_ELEVATION elevation;
+ DWORD cb = 0;
+
+ if (!GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &cb))
+ error::raise("GetTokenInformation");
+
+ return elevation.TokenIsElevated != 0;
+ }
+}