diff options
author | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2022-01-25 16:04:04 +0200 |
---|---|---|
committer | Arttu Tarkiainen <arttu.tarkiainen@qt.io> | 2022-01-31 14:07:03 +0000 |
commit | 0126b55180c6aae94f17e0fcb05549ba031f93dc (patch) | |
tree | 9454a154dbf14f1098db6eaa517f27b05dc9d9e5 /src/libs/installer/utils.cpp | |
parent | c23540ea462c5b91f0e41fc8c10e8b7d9a0610bf (diff) |
Gain admin rights when user is missing privilege to create symlinks
On Windows, the non-admin users cannot create symbolic links by default.
Extracting archives containing symlinks would fail if the installer was
no started as administrator. Catch the case and auto-elevate installer
to extract such archives.
Do not elevate installer if the current user has the privilege for
symlink creation, or if the Developer mode is enabled, allowing
unprivileged creation of symlinks.
Task-number: QTIFW-2428
Change-Id: I0b6b1079daabb9727055dce8a9475c203d7e92b0
Reviewed-by: Katja Marttila <katja.marttila@qt.io>
Diffstat (limited to 'src/libs/installer/utils.cpp')
-rw-r--r-- | src/libs/installer/utils.cpp | 98 |
1 files changed, 97 insertions, 1 deletions
diff --git a/src/libs/installer/utils.cpp b/src/libs/installer/utils.cpp index 7506a13fe..5294d00f6 100644 --- a/src/libs/installer/utils.cpp +++ b/src/libs/installer/utils.cpp @@ -1,6 +1,6 @@ /************************************************************************** ** -** Copyright (C) 2021 The Qt Company Ltd. +** Copyright (C) 2022 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Installer Framework. @@ -29,6 +29,7 @@ #include "utils.h" #include "fileutils.h" +#include "qsettingswrapper.h" #include <QCoreApplication> #include <QDateTime> @@ -323,6 +324,21 @@ QStringList QInstaller::parseCommandLineArgs(int argc, char **argv) } #endif +/*! + On Windows checks if the user account has the privilege required to create a symbolic links. + Returns \c true if the privilege is held, \c false otherwise. + + On Unix platforms always returns \c true. +*/ +bool QInstaller::canCreateSymbolicLinks() +{ +#ifdef Q_OS_WIN + return ((setPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME, true) + && checkPrivilege(SE_CREATE_SYMBOLIC_LINK_NAME)) || developerModeEnabled()); +#endif + return true; +} + #ifdef Q_OS_WIN // taken from qprocess_win.cpp static QString qt_create_commandline(const QString &program, const QStringList &arguments) @@ -401,4 +417,84 @@ QString QInstaller::windowsErrorString(int errorCode) return ret; } +/*! + \internal + + Sets the enabled state of \a privilege to \a enable for this process. + The privilege must be held by the current login user. Returns \c true + on success, \c false on failure. +*/ +bool QInstaller::setPrivilege(const wchar_t *privilege, bool enable) +{ + LUID luid; + TOKEN_PRIVILEGES privileges; + HANDLE token; + HANDLE process = GetCurrentProcess(); + + if (!OpenProcessToken(process, TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &token)) + return false; + + if (!LookupPrivilegeValue(nullptr, privilege, &luid)) + return false; + + privileges.PrivilegeCount = 1; + privileges.Privileges[0].Luid = luid; + if (enable) + privileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + else + privileges.Privileges[0].Attributes = 0; + + if (!AdjustTokenPrivileges(token, FALSE, &privileges, + sizeof(TOKEN_PRIVILEGES), nullptr, nullptr)) { + return false; + } + if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) + return false; + + return true; +} + +/*! + \internal + + Returns \c true if the specified \a privilege is enabled for the client + process, \c false otherwise. +*/ +bool QInstaller::checkPrivilege(const wchar_t *privilege) +{ + LUID luid; + PRIVILEGE_SET privileges; + HANDLE token; + HANDLE process = GetCurrentProcess(); + + if (!OpenProcessToken(process, TOKEN_QUERY, &token)) + return false; + + if (!LookupPrivilegeValue(nullptr, privilege, &luid)) + return false; + + privileges.PrivilegeCount = 1; + privileges.Control = PRIVILEGE_SET_ALL_NECESSARY; + privileges.Privilege[0].Luid = luid; + privileges.Privilege[0].Attributes = SE_PRIVILEGE_ENABLED; + + BOOL result; + PrivilegeCheck(token, &privileges, &result); + + return result; +} + +/*! + \internal + + Returns \c true if the 'Developer mode' is enabled on system. +*/ +bool QInstaller::developerModeEnabled() +{ + QSettingsWrapper appModelUnlock(QLatin1String("HKLM\\SOFTWARE\\Microsoft\\Windows\\" + "CurrentVersion\\AppModelUnlock"), QSettingsWrapper::NativeFormat); + + return appModelUnlock.value(QLatin1String("AllowDevelopmentWithoutDevLicense"), false).toBool(); +} + #endif |