summaryrefslogtreecommitdiffstats
path: root/src/libs/installer/utils.cpp
diff options
context:
space:
mode:
authorArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-01-25 16:04:04 +0200
committerArttu Tarkiainen <arttu.tarkiainen@qt.io>2022-01-31 14:07:03 +0000
commit0126b55180c6aae94f17e0fcb05549ba031f93dc (patch)
tree9454a154dbf14f1098db6eaa517f27b05dc9d9e5 /src/libs/installer/utils.cpp
parentc23540ea462c5b91f0e41fc8c10e8b7d9a0610bf (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.cpp98
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