diff options
| author | Egor Tensin <egor@tensin.name> | 2026-06-13 00:36:59 +0200 |
|---|---|---|
| committer | Egor Tensin <egor@tensin.name> | 2026-06-13 00:39:55 +0200 |
| commit | 190ff781eaee33e7a61aab44fc4133718cc0515b (patch) | |
| tree | 469cedfc87734589a4e9a0102f69324b9edb8f16 /src | |
| parent | cmake: upgrade minimum version (diff) | |
| download | privilege-check-190ff781eaee33e7a61aab44fc4133718cc0515b.tar.gz privilege-check-190ff781eaee33e7a61aab44fc4133718cc0515b.zip | |
add .clang-format
Diffstat (limited to 'src')
| -rw-r--r-- | src/cmd_line.hpp | 74 | ||||
| -rw-r--r-- | src/error.hpp | 35 | ||||
| -rw-r--r-- | src/handle.hpp | 45 | ||||
| -rw-r--r-- | src/main.cpp | 315 | ||||
| -rw-r--r-- | src/os.hpp | 36 | ||||
| -rw-r--r-- | src/process.cpp | 72 | ||||
| -rw-r--r-- | src/process.hpp | 40 | ||||
| -rw-r--r-- | src/resource.hpp | 25 | ||||
| -rw-r--r-- | src/sid.cpp | 90 | ||||
| -rw-r--r-- | src/sid.hpp | 15 | ||||
| -rw-r--r-- | src/string.hpp | 209 | ||||
| -rw-r--r-- | src/token.cpp | 227 | ||||
| -rw-r--r-- | src/token.hpp | 48 |
13 files changed, 551 insertions, 680 deletions
diff --git a/src/cmd_line.hpp b/src/cmd_line.hpp index ae96ed5..b1eb2a5 100644 --- a/src/cmd_line.hpp +++ b/src/cmd_line.hpp @@ -8,28 +8,26 @@ #include "error.hpp" #include "string.hpp" +/* clang-format off */ #include <windows.h> #include <shellapi.h> +/* clang-format on */ #include <cstddef> - #include <memory> -#include <stdexcept> #include <sstream> +#include <stdexcept> #include <string> #include <utility> #include <vector> -class CommandLine -{ +class CommandLine { public: - static CommandLine query() - { + static CommandLine query() { return build_from_string(GetCommandLine()); } - static CommandLine build_from_main(int argc, wchar_t* argv[]) - { + static CommandLine build_from_main(int argc, wchar_t* argv[]) { if (argc < 1) throw std::range_error{"invalid argc value"}; @@ -48,33 +46,27 @@ public: CommandLine() = default; - bool has_argv0() const - { + bool has_argv0() const { return !argv0.empty(); } - std::wstring get_argv0() const - { + std::wstring get_argv0() const { return argv0; } - std::wstring escape_argv0() const - { + std::wstring escape_argv0() const { return escape(get_argv0()); } - bool has_args() const - { + bool has_args() const { return !get_args().empty(); } - const std::vector<std::wstring>& get_args() const - { + const std::vector<std::wstring>& get_args() const { return args; } - std::vector<std::wstring> escape_args() const - { + std::vector<std::wstring> escape_args() const { std::vector<std::wstring> safe; safe.reserve(args.size()); for (const auto& arg : args) @@ -82,15 +74,15 @@ public: return safe; } - static constexpr wchar_t sep() { return L' '; } + static constexpr wchar_t sep() { + return L' '; + } - std::wstring join_args() const - { + std::wstring join_args() const { return string::join(sep(), escape_args()); } - std::wstring join() const - { + std::wstring join() const { if (!has_argv0()) throw std::logic_error{"argv[0] isn't defined"}; std::wostringstream oss; @@ -101,8 +93,7 @@ public: } private: - static CommandLine build_from_string(std::wstring src) - { + static CommandLine build_from_string(std::wstring src) { string::trim(src); if (src.empty()) return {}; @@ -127,8 +118,7 @@ private: return {std::move(argv0), std::move(args)}; } - inline std::wstring escape_for_cmd(const std::wstring& arg) - { + inline std::wstring escape_for_cmd(const std::wstring& arg) { static constexpr auto escape_symbol = L'^'; static constexpr auto dangerous_symbols = L"!\"%&()<>^|"; @@ -137,29 +127,25 @@ private: return safe; } - static std::wstring escape(const std::wstring& arg) - { + static std::wstring escape(const std::wstring& arg) { std::wstring safe; safe.reserve(arg.length() + 2); safe.push_back(L'"'); - for (auto it = arg.cbegin(); it != arg.cend(); ++it) - { + for (auto it = arg.cbegin(); it != arg.cend(); ++it) { std::size_t numof_backslashes = 0; for (; it != arg.cend() && *it == L'\\'; ++it) ++numof_backslashes; - if (it == arg.cend()) - { + if (it == arg.cend()) { safe.reserve(safe.capacity() + numof_backslashes); safe.append(2 * numof_backslashes, L'\\'); break; } - switch (*it) - { + switch (*it) { case L'"': safe.reserve(safe.capacity() + numof_backslashes + 1); safe.append(2 * numof_backslashes + 1, L'\\'); @@ -177,22 +163,16 @@ private: return safe; } - struct LocalDelete - { - void operator()(wchar_t* argv[]) const - { + struct LocalDelete { + void operator()(wchar_t* argv[]) const { LocalFree(argv); } }; - CommandLine(std::vector<std::wstring>&& args) - : args{std::move(args)} - { } + CommandLine(std::vector<std::wstring>&& args) : args{std::move(args)} {} CommandLine(std::wstring&& argv0, std::vector<std::wstring>&& args = {}) - : argv0{std::move(argv0)} - , args{std::move(args)} - { } + : argv0{std::move(argv0)}, args{std::move(args)} {} const std::wstring argv0; const std::vector<std::wstring> args; diff --git a/src/error.hpp b/src/error.hpp index 04ec8c9..8a0778c 100644 --- a/src/error.hpp +++ b/src/error.hpp @@ -12,26 +12,23 @@ typedef std::system_error Error; -namespace error -{ - inline Error make(const char* function_name) - { - const auto ec = GetLastError(); - return {static_cast<int>(ec), std::system_category(), function_name}; - } +namespace error { - inline void raise(const char* function_name) - { - throw make(function_name); - } +inline Error make(const char* function_name) { + const auto ec = GetLastError(); + return {static_cast<int>(ec), std::system_category(), function_name}; +} - inline void report(const std::exception& e) - { - MessageBoxA(NULL, e.what(), NULL, MB_OK); - } +inline void raise(const char* function_name) { + throw make(function_name); +} - inline int get_code(const Error& e) - { - return e.code().value(); - } +inline void report(const std::exception& e) { + MessageBoxA(NULL, e.what(), NULL, MB_OK); } + +inline int get_code(const Error& e) { + return e.code().value(); +} + +} // namespace error diff --git a/src/handle.hpp b/src/handle.hpp index 4bc0a97..5839594 100644 --- a/src/handle.hpp +++ b/src/handle.hpp @@ -8,51 +8,41 @@ #include <windows.h> #include <cassert> - #include <memory> #include <utility> -class Handle -{ +class Handle { public: Handle() = default; - explicit Handle(HANDLE raw) - : impl{raw} - { } + explicit Handle(HANDLE raw) : impl{raw} {} - Handle(Handle&& other) noexcept - { + Handle(Handle&& other) noexcept { swap(other); } - Handle& operator=(Handle other) noexcept - { + Handle& operator=(Handle other) noexcept { swap(other); return *this; } - void swap(Handle& other) noexcept - { + void swap(Handle& other) noexcept { using std::swap; swap(impl, other.impl); } - operator HANDLE() const - { + operator HANDLE() const { return impl.get(); } private: - struct Close - { - void operator()(HANDLE raw) const - { + struct Close { + void operator()(HANDLE raw) const { if (raw == NULL || raw == INVALID_HANDLE_VALUE) return; const auto ret = CloseHandle(raw); assert(ret); - (void) ret; + (void)ret; } }; @@ -61,16 +51,15 @@ private: Handle(const Handle&) = delete; }; -inline void swap(Handle& a, Handle& b) noexcept -{ +inline void swap(Handle& a, Handle& b) noexcept { a.swap(b); } -namespace std -{ - template <> - inline void swap(Handle& a, Handle& b) noexcept - { - a.swap(b); - } +namespace std { + +template <> +inline void swap(Handle& a, Handle& b) noexcept { + a.swap(b); } + +} // namespace std diff --git a/src/main.cpp b/src/main.cpp index 4065a5e..8b81587 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -11,242 +11,189 @@ #include "sid.hpp" #include "token.hpp" -#include <commctrl.h> +/* clang-format off */ #include <windows.h> +#include <commctrl.h> #include <windowsx.h> +/* clang-format on */ #include <exception> #include <string> #if defined(_MSC_VER) -#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") +#pragma comment( \ + linker, \ + "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='*' publicKeyToken='6595b64144ccf1df' language='*'\"") #endif -namespace -{ - HWND get_dialog_item(HWND wnd, int id) - { - const auto lbl = GetDlgItem(wnd, id); - if (lbl == NULL) - error::raise("GetDlgItem"); - return lbl; - } +namespace { - bool is_administrator() - { - auto token = token::open_for_current_process( - token::permissions::query() | token::permissions::duplicate()); - if (!token::get_linked(token)) - token = token::get_for_identification(token); +HWND get_dialog_item(HWND wnd, int id) { + const auto lbl = GetDlgItem(wnd, id); + if (lbl == NULL) + error::raise("GetDlgItem"); + return lbl; +} - return token::check_belongs(token, sid::builtin_administrators()); - } +bool is_administrator() { + auto token = token::open_for_current_process(token::permissions::query() | + token::permissions::duplicate()); + if (!token::get_linked(token)) + token = token::get_for_identification(token); - bool is_run_as_administrator() - { - return token::check_belongs(token::dumb(), sid::builtin_administrators()); - } + return token::check_belongs(token, sid::builtin_administrators()); +} - bool is_elevated() - { - return token::query_elevation(token::open_for_current_process()); - } +bool is_run_as_administrator() { + return token::check_belongs(token::dumb(), sid::builtin_administrators()); +} - void decorate_elevate_button(HWND wnd, bool decorate) - { - const auto btn = get_dialog_item(wnd, IDC_BUTTON_ELEVATE); - Button_SetElevationRequiredState(btn, !decorate); - } +bool is_elevated() { + return token::query_elevation(token::open_for_current_process()); +} - DWORD get_integrity_level() - { - return token::query_integrity_level(token::open_for_current_process()); - } +void decorate_elevate_button(HWND wnd, bool decorate) { + const auto btn = get_dialog_item(wnd, IDC_BUTTON_ELEVATE); + Button_SetElevationRequiredState(btn, !decorate); +} - std::wstring get_integrity_level_as_string() - { - return token::integrity_level_to_string(get_integrity_level()); - } +DWORD get_integrity_level() { + return token::query_integrity_level(token::open_for_current_process()); +} - HWND get_label(HWND wnd, int id) - { - return get_dialog_item(wnd, id); - } +std::wstring get_integrity_level_as_string() { + return token::integrity_level_to_string(get_integrity_level()); +} - void set_label(HWND wnd, int id, bool val) - { - SetWindowTextW(get_label(wnd, id), val ? L"True" : L"False"); - } +HWND get_label(HWND wnd, int id) { + return get_dialog_item(wnd, id); +} + +void set_label(HWND wnd, int id, bool val) { + SetWindowTextW(get_label(wnd, id), val ? L"True" : L"False"); +} + +void set_label(HWND wnd, int id, const wchar_t* s) { + SetWindowTextW(get_label(wnd, id), s); +} - void set_label(HWND wnd, int id, const wchar_t* s) - { - SetWindowTextW(get_label(wnd, id), s); +void set_label(HWND wnd, int id, const std::wstring& s) { + SetWindowTextW(get_label(wnd, id), s.c_str()); +} + +BOOL on_init_dialog(HWND wnd, HWND, LPARAM) { + try { + set_label(wnd, IDC_ADMINISTRATOR, is_administrator()); + } catch (const Error& e) { + set_label(wnd, IDC_ADMINISTRATOR, L"N/A"); + error::report(e); } - void set_label(HWND wnd, int id, const std::wstring& s) - { - SetWindowTextW(get_label(wnd, id), s.c_str()); + 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); } - BOOL on_init_dialog(HWND wnd, HWND, LPARAM) - { - try - { - set_label(wnd, IDC_ADMINISTRATOR, is_administrator()); - } - catch (const Error& e) - { - set_label(wnd, IDC_ADMINISTRATOR, L"N/A"); + if (os::is_vista_or_later()) { + try { + const auto elevated = is_elevated(); + set_label(wnd, IDC_ELEVATED, elevated); + decorate_elevate_button(wnd, elevated); + } catch (const Error& e) { + set_label(wnd, IDC_ELEVATED, 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"); + try { + set_label(wnd, IDC_INTEGRITY_LEVEL, get_integrity_level_as_string()); + } 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"); + } - if (os::is_vista_or_later()) - { - try - { - const auto elevated = is_elevated(); - set_label(wnd, IDC_ELEVATED, elevated); - decorate_elevate_button(wnd, elevated); - } - catch (const Error& e) - { - set_label(wnd, IDC_ELEVATED, L"N/A"); - error::report(e); - } + return TRUE; +} - try - { - set_label(wnd, IDC_INTEGRITY_LEVEL, get_integrity_level_as_string()); - } - 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"); - } +void report_already_elevated(HWND wnd) { + MessageBoxW(wnd, + resource::load_string(IDS_ALREADY_ELEVATED_TEXT).c_str(), + resource::load_string(IDS_ALREADY_ELEVATED_CAPTION).c_str(), + MB_OK); +} - return TRUE; - } +void on_button_elevate_click(HWND wnd) { + bool as_admin = false; - void report_already_elevated(HWND wnd) - { - MessageBoxW(wnd, - resource::load_string(IDS_ALREADY_ELEVATED_TEXT).c_str(), - resource::load_string(IDS_ALREADY_ELEVATED_CAPTION).c_str(), - MB_OK); + try { + as_admin = is_run_as_administrator(); + } catch (const Error& e) { + error::report(e); + return; } - void on_button_elevate_click(HWND wnd) - { - bool as_admin = false; + if (as_admin) { + report_already_elevated(wnd); + return; + } - try - { - as_admin = is_run_as_administrator(); - } - catch (const Error& e) - { + try { + process::runas_self(wnd); + } catch (const Error& e) { + if (error::get_code(e) != ERROR_CANCELLED) error::report(e); - return; - } - - if (as_admin) - { - report_already_elevated(wnd); - return; - } - - try - { - process::runas_self(wnd); - } - catch (const Error& e) - { - if (error::get_code(e) != ERROR_CANCELLED) - error::report(e); - return; - } - - EndDialog(wnd, 1); + return; } - void on_command(HWND wnd, int id, HWND, unsigned int) - { - switch (id) - { - case IDC_BUTTON_ELEVATE: - on_button_elevate_click(wnd); - break; + EndDialog(wnd, 1); +} - case IDOK: - case IDCANCEL: - EndDialog(wnd, 0); - break; - } - } +void on_command(HWND wnd, int id, HWND, unsigned int) { + switch (id) { + case IDC_BUTTON_ELEVATE: + on_button_elevate_click(wnd); + break; - void on_close(HWND wnd) - { - EndDialog(wnd, 0); + case IDOK: + case IDCANCEL: + EndDialog(wnd, 0); + break; } +} - 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); +void on_close(HWND wnd) { + EndDialog(wnd, 0); +} - default: - return FALSE; - } +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) -{ - try - { - const auto ret = DialogBoxW( - instance, - MAKEINTRESOURCE(IDD_MAINDIALOG), - NULL, - dialog_main); +} // namespace + +int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) { + try { + const auto ret = DialogBoxW(instance, MAKEINTRESOURCE(IDD_MAINDIALOG), NULL, dialog_main); - switch (ret) - { + switch (ret) { case -1: error::report(error::make("DialogBoxW")); default: return static_cast<int>(ret); } - } - catch (const std::exception& e) - { + } catch (const std::exception& e) { error::report(e); return 1; } @@ -9,27 +9,25 @@ #include <windows.h> -namespace os -{ - inline OSVERSIONINFOW get_version_info() - { - OSVERSIONINFOW info; - ZeroMemory(&info, sizeof(info)); - info.dwOSVersionInfoSize = sizeof(info); +namespace os { - if (!GetVersionExW(&info)) - error::raise("GetVersionExW"); +inline OSVERSIONINFOW get_version_info() { + OSVERSIONINFOW info; + ZeroMemory(&info, sizeof(info)); + info.dwOSVersionInfoSize = sizeof(info); - return info; - } + if (!GetVersionExW(&info)) + error::raise("GetVersionExW"); - inline bool is_vista_or_later(const OSVERSIONINFOW& info) - { - return info.dwMajorVersion >= 6; - } + return info; +} + +inline bool is_vista_or_later(const OSVERSIONINFOW& info) { + return info.dwMajorVersion >= 6; +} - inline bool is_vista_or_later() - { - return is_vista_or_later(get_version_info()); - } +inline bool is_vista_or_later() { + return is_vista_or_later(get_version_info()); } + +} // namespace os diff --git a/src/process.cpp b/src/process.cpp index a2eddc0..b71bff0 100644 --- a/src/process.cpp +++ b/src/process.cpp @@ -3,60 +3,54 @@ // For details, see https://github.com/egor-tensin/privilege-check. // Distributed under the MIT License. +#include "process.hpp" + #include "cmd_line.hpp" #include "error.hpp" -#include "process.hpp" +/* clang-format off */ #include <windows.h> #include <shellapi.h> +/* clang-format on */ #include <array> #include <string> -namespace process -{ - std::wstring get_executable_path() - { - static constexpr DWORD max_path = MAX_PATH; +namespace process { - std::array<wchar_t, max_path> buf; +std::wstring get_executable_path() { + static constexpr DWORD max_path = MAX_PATH; - const auto ret = GetModuleFileNameW(NULL, buf.data(), max_path); + std::array<wchar_t, max_path> buf; - if (ret != ERROR_SUCCESS) - error::raise("GetModuleFileNameW"); + const auto ret = GetModuleFileNameW(NULL, buf.data(), max_path); - return buf.data(); - } + if (ret != ERROR_SUCCESS) + error::raise("GetModuleFileNameW"); - void runas( - const CommandLine& cmd_line, - HWND hwnd, - int nShow) - { - const auto exe_path = cmd_line.has_argv0() - ? cmd_line.get_argv0() - : get_executable_path(); + return buf.data(); +} - SHELLEXECUTEINFOW info; - ZeroMemory(&info, sizeof(info)); - info.cbSize = sizeof(info); - info.lpVerb = L"runas"; - info.lpFile = exe_path.c_str(); - const auto args = cmd_line.join_args(); - if (!args.empty()) - info.lpParameters = args.c_str(); - info.hwnd = hwnd; - info.nShow = nShow; +void runas(const CommandLine& cmd_line, HWND hwnd, int nShow) { + const auto exe_path = cmd_line.has_argv0() ? cmd_line.get_argv0() : get_executable_path(); - if (!ShellExecuteExW(&info)) - error::raise("ShellExecuteExW"); - } + SHELLEXECUTEINFOW info; + ZeroMemory(&info, sizeof(info)); + info.cbSize = sizeof(info); + info.lpVerb = L"runas"; + info.lpFile = exe_path.c_str(); + const auto args = cmd_line.join_args(); + if (!args.empty()) + info.lpParameters = args.c_str(); + info.hwnd = hwnd; + info.nShow = nShow; - void runas_self( - HWND hwnd, - int nShow) - { - runas(CommandLine::query(), hwnd, nShow); - } + if (!ShellExecuteExW(&info)) + error::raise("ShellExecuteExW"); } + +void runas_self(HWND hwnd, int nShow) { + runas(CommandLine::query(), hwnd, nShow); +} + +} // namespace process diff --git a/src/process.hpp b/src/process.hpp index c27dc3e..9ad93d9 100644 --- a/src/process.hpp +++ b/src/process.hpp @@ -5,36 +5,30 @@ #pragma once -#include "error.hpp" #include "cmd_line.hpp" +#include "error.hpp" #include <windows.h> #include <string> -namespace process -{ - inline HMODULE load_exe_module() - { - const auto module = GetModuleHandle(NULL); - if (module == NULL) - error::raise("GetModuleHandle"); - return module; - } +namespace process { - std::wstring get_executable_path(); - - inline std::wstring get_command_line() - { - return GetCommandLine(); - } +inline HMODULE load_exe_module() { + const auto module = GetModuleHandle(NULL); + if (module == NULL) + error::raise("GetModuleHandle"); + return module; +} - void runas( - const CommandLine& cmd_line, - HWND hwnd = NULL, - int nShow = SW_NORMAL); +std::wstring get_executable_path(); - void runas_self( - HWND hwnd = NULL, - int nShow = SW_NORMAL); +inline std::wstring get_command_line() { + return GetCommandLine(); } + +void runas(const CommandLine& cmd_line, HWND hwnd = NULL, int nShow = SW_NORMAL); + +void runas_self(HWND hwnd = NULL, int nShow = SW_NORMAL); + +} // namespace process diff --git a/src/resource.hpp b/src/resource.hpp index 6039fab..1f7b9ad 100644 --- a/src/resource.hpp +++ b/src/resource.hpp @@ -11,24 +11,19 @@ #include <windows.h> #include <cstddef> - #include <string> -namespace resource -{ - inline std::wstring load_string(unsigned int id) - { - wchar_t* s = nullptr; +namespace resource { + +inline std::wstring load_string(unsigned int id) { + wchar_t* s = nullptr; - const auto ret = LoadStringW( - process::load_exe_module(), - id, - reinterpret_cast<wchar_t*>(&s), - 0); + const auto ret = LoadStringW(process::load_exe_module(), id, reinterpret_cast<wchar_t*>(&s), 0); - if (ret <= 0) - error::raise("LoadStringW"); + if (ret <= 0) + error::raise("LoadStringW"); - return {s, static_cast<std::size_t>(ret)}; - } + return {s, static_cast<std::size_t>(ret)}; } + +} // namespace resource diff --git a/src/sid.cpp b/src/sid.cpp index 7a0e252..1a69763 100644 --- a/src/sid.cpp +++ b/src/sid.cpp @@ -3,69 +3,69 @@ // For details, see https://github.com/egor-tensin/privilege-check. // Distributed under the MIT License. -#include "error.hpp" #include "sid.hpp" +#include "error.hpp" + +/* clang-format off */ #include <windows.h> #include <sddl.h> +/* clang-format on */ #include <memory> #include <string> -namespace sid -{ - SidBuffer well_known(WELL_KNOWN_SID_TYPE type) - { - SidBuffer buffer; - DWORD cb = static_cast<DWORD>(buffer.size()); +namespace sid { - if (!CreateWellKnownSid(type, NULL, buffer.data(), &cb)) - error::raise("CreateWellKnownSid"); +SidBuffer well_known(WELL_KNOWN_SID_TYPE type) { + SidBuffer buffer; + DWORD cb = static_cast<DWORD>(buffer.size()); - return buffer; - } + 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; - SidBuffer builtin_administrators() + if (!AllocateAndInitializeSid( + &authority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &sid)) { - /* - void* sid = nullptr; - SID_IDENTIFIER_AUTHORITY authority = SECURITY_NT_AUTHORITY; + error::raise("AllocateAndInitializeSid"); + } - 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 std::unique_ptr<void, FreeSid>{sid}; - */ + return well_known(WinBuiltinAdministratorsSid); +} - return well_known(WinBuiltinAdministratorsSid); - } +namespace { - namespace - { - struct LocalDelete - { - void operator()(wchar_t* s) const - { - LocalFree(s); - } - }; +struct LocalDelete { + void operator()(wchar_t* s) const { + LocalFree(s); } +}; - std::wstring to_string(const SidBuffer& sid) - { - wchar_t* s = nullptr; +} // namespace - if (!ConvertSidToStringSidW(const_cast<unsigned char*>(sid.data()), &s)) - error::raise("ConvertSidToStringSidW"); +std::wstring to_string(const SidBuffer& sid) { + wchar_t* s = nullptr; - return std::unique_ptr<wchar_t, LocalDelete>{s}.get(); - } + if (!ConvertSidToStringSidW(const_cast<unsigned char*>(sid.data()), &s)) + error::raise("ConvertSidToStringSidW"); + + return std::unique_ptr<wchar_t, LocalDelete>{s}.get(); } + +} // namespace sid diff --git a/src/sid.hpp b/src/sid.hpp index 2dc6111..a890e48 100644 --- a/src/sid.hpp +++ b/src/sid.hpp @@ -5,8 +5,10 @@ #pragma once +/* clang-format off */ #include <windows.h> #include <sddl.h> +/* clang-format on */ #include <array> #include <string> @@ -15,11 +17,12 @@ 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); +namespace sid { - SidBuffer builtin_administrators(); +SidBuffer well_known(WELL_KNOWN_SID_TYPE type); - std::wstring to_string(const SidBuffer&); -} +SidBuffer builtin_administrators(); + +std::wstring to_string(const SidBuffer&); + +} // namespace sid diff --git a/src/string.hpp b/src/string.hpp index 24d0425..dee1966 100644 --- a/src/string.hpp +++ b/src/string.hpp @@ -5,155 +5,136 @@ #pragma once +#include <algorithm> #include <cctype> #include <cstddef> - -#include <algorithm> #include <locale> #include <sstream> #include <string> #include <type_traits> #include <vector> -namespace string -{ - template <typename Char> - void ltrim(std::basic_string<Char>& s) - { - s.erase(s.begin(), std::find_if(s.begin(), s.end(), [] (const Char& c) - { - return !std::isspace(c); - })); - } - - template <typename Char> - void rtrim(std::basic_string<Char>& s) - { - s.erase(std::find_if(s.rbegin(), s.rend(), [] (const Char& c) - { - return !std::isspace(c); - }).base(), s.end()); - } +namespace string { - template <typename Char> - void trim(std::basic_string<Char>& s) - { - ltrim(s); - rtrim(s); - } +template <typename Char> +void ltrim(std::basic_string<Char>& s) { + s.erase(s.begin(), + std::find_if(s.begin(), s.end(), [](const Char& c) { return !std::isspace(c); })); +} - template <typename Char, typename Sep, typename InputIterator> - std::basic_string<Char> join( - const Sep& sep, - InputIterator beg, - InputIterator end) - { - std::basic_ostringstream<Char> oss; +template <typename Char> +void rtrim(std::basic_string<Char>& s) { + s.erase( + std::find_if(s.rbegin(), s.rend(), [](const Char& c) { return !std::isspace(c); }).base(), + s.end()); +} - if (beg != end) - { - oss << *beg; - ++beg; - } +template <typename Char> +void trim(std::basic_string<Char>& s) { + ltrim(s); + rtrim(s); +} - for (; beg != end; ++beg) - oss << sep << *beg; +template <typename Char, typename Sep, typename InputIterator> +std::basic_string<Char> join(const Sep& sep, InputIterator beg, InputIterator end) { + std::basic_ostringstream<Char> oss; - return oss.str(); + if (beg != end) { + oss << *beg; + ++beg; } - template <typename Char, typename Sep> - std::basic_string<Char> join( - const Sep& sep, - const std::vector<std::basic_string<Char>>& args) - { - return join<Char>(sep, args.cbegin(), args.cend()); - } + for (; beg != end; ++beg) + oss << sep << *beg; - template <typename Char, typename String, typename = void> - struct StringHelper - { }; + return oss.str(); +} - template <typename Char, typename String> - struct StringHelper<Char, String, typename std::enable_if<std::is_same<typename std::decay<typename std::remove_pointer<String>::type>::type, Char>::value>::type> - { - StringHelper(const Char& c) - : buf{&c} - , len{1} - { } +template <typename Char, typename Sep> +std::basic_string<Char> join(const Sep& sep, const std::vector<std::basic_string<Char>>& args) { + return join<Char>(sep, args.cbegin(), args.cend()); +} - StringHelper(const Char* s) - : buf{s} - , len{std::char_traits<Char>::length(s)} - { } +template <typename Char, typename String, typename = void> +struct StringHelper {}; - const Char* buffer() const { return buf; } +template <typename Char, typename String> +struct StringHelper<Char, + String, + typename std::enable_if<std::is_same< + typename std::decay<typename std::remove_pointer<String>::type>::type, + Char>::value>::type> { + StringHelper(const Char& c) : buf{&c}, len{1} {} - std::size_t length() const { return len; } + StringHelper(const Char* s) : buf{s}, len{std::char_traits<Char>::length(s)} {} - private: - const Char* const buf; - const std::size_t len; - }; + const Char* buffer() const { + return buf; + } - template <typename Char, typename String> - struct StringHelper<Char, String, typename std::enable_if<std::is_same<String, std::basic_string<Char>>::value>::type> - { - StringHelper(const std::basic_string<Char>& s) - : s{s} - { } + std::size_t length() const { + return len; + } - const Char* buffer() const { return s.c_str(); } +private: + const Char* const buf; + const std::size_t len; +}; - std::size_t length() const { return s.length(); } +template <typename Char, typename String> +struct StringHelper< + Char, + String, + typename std::enable_if<std::is_same<String, std::basic_string<Char>>::value>::type> { + StringHelper(const std::basic_string<Char>& s) : s{s} {} - private: - const std::basic_string<Char>& s; - }; + const Char* buffer() const { + return s.c_str(); + } - template <typename Char, typename What, typename By> - void replace( - std::basic_string<Char>& s, - const What& what, - const By& by) - { - std::size_t pos = 0; + std::size_t length() const { + return s.length(); + } - const StringHelper<Char, typename std::decay<What>::type> what_helper{what}; - const StringHelper<Char, typename std::decay<By>::type> by_helper{by}; +private: + const std::basic_string<Char>& s; +}; - const auto what_buf = what_helper.buffer(); - const auto what_len = what_helper.length(); +template <typename Char, typename What, typename By> +void replace(std::basic_string<Char>& s, const What& what, const By& by) { + std::size_t pos = 0; - const auto by_buf = by_helper.buffer(); - const auto by_len = by_helper.length(); + const StringHelper<Char, typename std::decay<What>::type> what_helper{what}; + const StringHelper<Char, typename std::decay<By>::type> by_helper{by}; - while ((pos = s.find(what_buf, pos, what_len)) != std::basic_string<Char>::npos) - { - s.replace(pos, what_len, by_buf, by_len); - pos += by_len; - } + const auto what_buf = what_helper.buffer(); + const auto what_len = what_helper.length(); + + const auto by_buf = by_helper.buffer(); + const auto by_len = by_helper.length(); + + while ((pos = s.find(what_buf, pos, what_len)) != std::basic_string<Char>::npos) { + s.replace(pos, what_len, by_buf, by_len); + pos += by_len; } +} - template <typename Char, typename What> - void prefix_with( - std::basic_string<Char>& s, - const What& what, - const Char& by) - { - const StringHelper<Char, typename std::decay<What>::type> what_helper{what}; +template <typename Char, typename What> +void prefix_with(std::basic_string<Char>& s, const What& what, const Char& by) { + const StringHelper<Char, typename std::decay<What>::type> what_helper{what}; - const auto what_buf = what_helper.buffer(); - const auto what_len = what_helper.length(); + const auto what_buf = what_helper.buffer(); + const auto what_len = what_helper.length(); - std::size_t numof_by = 0; + std::size_t numof_by = 0; - for (std::size_t i = 0; i < what_len; ++i) - numof_by += std::count(s.cbegin(), s.cend(), what_buf[i]); + for (std::size_t i = 0; i < what_len; ++i) + numof_by += std::count(s.cbegin(), s.cend(), what_buf[i]); - s.reserve(s.capacity() + numof_by); + s.reserve(s.capacity() + numof_by); - for (std::size_t i = 0; i < what_len; ++i) - replace(s, what_buf[i], by); - } + for (std::size_t i = 0; i < what_len; ++i) + replace(s, what_buf[i], by); } + +} // namespace string diff --git a/src/token.cpp b/src/token.cpp index f7ad38e..1333290 100644 --- a/src/token.cpp +++ b/src/token.cpp @@ -3,6 +3,8 @@ // For details, see https://github.com/egor-tensin/privilege-check. // Distributed under the MIT License. +#include "token.hpp" + #include "error.hpp" #include "handle.hpp" #include "os.hpp" @@ -15,153 +17,140 @@ #include <utility> #include <vector> -namespace token -{ - Handle open_for_process( - const Handle& process, - DWORD permissions) - { - HANDLE raw; +namespace token { - if (!OpenProcessToken(process, permissions, &raw)) - error::raise("OpenProcessToken"); +Handle open_for_process(const Handle& process, DWORD permissions) { + HANDLE raw; - return Handle{raw}; - } + if (!OpenProcessToken(process, permissions, &raw)) + error::raise("OpenProcessToken"); - Handle open_for_current_process( - DWORD permissions) - { - return open_for_process(Handle{GetCurrentProcess()}, permissions); - } + return Handle{raw}; +} + +Handle open_for_current_process(DWORD permissions) { + return open_for_process(Handle{GetCurrentProcess()}, permissions); +} - bool get_linked(Handle& token) - { - if (!os::is_vista_or_later()) - return false; +bool get_linked(Handle& token) { + if (!os::is_vista_or_later()) + return false; - auto type = TokenElevationTypeDefault; - DWORD cb = 0; + auto type = TokenElevationTypeDefault; + DWORD cb = 0; - if (!GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &cb)) - error::raise("GetTokenInformation"); + if (!GetTokenInformation(token, TokenElevationType, &type, sizeof(type), &cb)) + error::raise("GetTokenInformation"); - if (type != TokenElevationTypeLimited) - return false; + if (type != TokenElevationTypeLimited) + return false; - HANDLE raw; + HANDLE raw; - if (!GetTokenInformation(token, TokenLinkedToken, &raw, sizeof(raw), &cb)) - error::raise("GetTokenInformation"); + if (!GetTokenInformation(token, TokenLinkedToken, &raw, sizeof(raw), &cb)) + error::raise("GetTokenInformation"); - token = Handle{raw}; - return true; - } + token = Handle{raw}; + return true; +} - Handle get_for_identification(const Handle& token) - { - HANDLE raw; +Handle get_for_identification(const Handle& token) { + HANDLE raw; - if (!DuplicateToken(token, SecurityIdentification, &raw)) - error::raise("DuplicateToken"); + if (!DuplicateToken(token, SecurityIdentification, &raw)) + error::raise("DuplicateToken"); - return Handle{raw}; - } + 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; +// +// 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"); - } + 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()); + 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"); + 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); - } + // 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"}, - }; +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"; + static constexpr auto unknown_name = L"Unknown"; - const auto it = names.find(level); + const auto it = names.find(level); - if (it == names.cend()) - return unknown_name; + if (it == names.cend()) + return unknown_name; - return it->second; - } + return it->second; +} - bool check_belongs(const Handle& token, const SidBuffer& sid) - { - BOOL b = FALSE; +bool check_belongs(const Handle& token, const SidBuffer& sid) { + BOOL b = FALSE; - if (!CheckTokenMembership(token, const_cast<unsigned char*>(sid.data()), &b)) - error::raise("CheckTokenMembership"); + if (!CheckTokenMembership(token, const_cast<unsigned char*>(sid.data()), &b)) + error::raise("CheckTokenMembership"); - return b != FALSE; - } + return b != FALSE; +} - bool query_elevation(const Handle& token) - { - TOKEN_ELEVATION elevation; - DWORD cb = 0; +bool query_elevation(const Handle& token) { + TOKEN_ELEVATION elevation; + DWORD cb = 0; - if (!GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &cb)) - error::raise("GetTokenInformation"); + if (!GetTokenInformation(token, TokenElevation, &elevation, sizeof(elevation), &cb)) + error::raise("GetTokenInformation"); - return elevation.TokenIsElevated != 0; - } + return elevation.TokenIsElevated != 0; } + +} // namespace token diff --git a/src/token.hpp b/src/token.hpp index 5ad32bf..2ccee13 100644 --- a/src/token.hpp +++ b/src/token.hpp @@ -12,36 +12,40 @@ #include <string> -namespace token -{ - namespace permissions - { - constexpr DWORD query() { return TOKEN_QUERY; } +namespace token { +namespace permissions { - constexpr DWORD duplicate() { return TOKEN_DUPLICATE; } - } +constexpr DWORD query() { + return TOKEN_QUERY; +} - constexpr DWORD default_permissions = permissions::query(); +constexpr DWORD duplicate() { + return TOKEN_DUPLICATE; +} - // Current thread's primary impersonation token. - inline Handle dumb() { return Handle{NULL}; } +} // namespace permissions - Handle open_for_process( - const Handle& process, - DWORD permissions = default_permissions); +constexpr DWORD default_permissions = permissions::query(); - Handle open_for_current_process( - DWORD permissions = default_permissions); +// Current thread's primary impersonation token. +inline Handle dumb() { + return Handle{NULL}; +} - bool get_linked(Handle& token); +Handle open_for_process(const Handle& process, DWORD permissions = default_permissions); - Handle get_for_identification(const Handle& token); +Handle open_for_current_process(DWORD permissions = default_permissions); - DWORD query_integrity_level(const Handle& token); +bool get_linked(Handle& token); - std::wstring integrity_level_to_string(DWORD); +Handle get_for_identification(const Handle& token); - bool check_belongs(const Handle& token, const SidBuffer& sid); +DWORD query_integrity_level(const Handle& token); - bool query_elevation(const Handle& token); -} +std::wstring integrity_level_to_string(DWORD); + +bool check_belongs(const Handle& token, const SidBuffer& sid); + +bool query_elevation(const Handle& token); + +} // namespace token |
