Verified Commit 69539cea authored by Andre Heinecke's avatar Andre Heinecke
Browse files

Prevent process elevation on Windows

On any modern Windows (>=Vista) there is the concept of elevated
security privileges. That means that you can elevate a user
of the Administrator group to have Administrative privileges but
e.g. still the same home directory as the user. This can
lead to subtle issues when Kleopatra / GnuPG creates files when
running elevated and Kleo is then later run not elvated. So
we better check for that and exit early if thats the case.

GnuPG-Bug-Id: T5212
parent 0bd46ea5
Pipeline #46457 passed with stage
in 19 minutes and 23 seconds
......@@ -24,6 +24,7 @@
#include <Libkleo/GnuPG>
#include <utils/archivedefinition.h>
#include "utils/kuniqueservice.h"
#include "utils/userinfo.h"
#include <uiserver/uiserver.h>
#include <uiserver/assuancommand.h>
......@@ -103,6 +104,26 @@ int main(int argc, char **argv)
KLocalizedString::setApplicationDomain("kleopatra");
if (Kleo::userIsElevated()) {
/* This is a safeguard against bugreports that something fails because
* of permission problems on windows. Some users still have the Windows
* Vista behavior of running things as Administrator. This can break
* GnuPG in horrible ways for example if a stale lockfile is left that
* can't be removed without another elevation.
*
* Note: This is not the same as running as root on Linux. Elevated means
* that you are temporarily running with the "normal" user environment but
* with elevated permissions.
* */
KMessageBox::sorry(nullptr, xi18nc("@info",
"<para><application>Kleopatra</application> cannot be run as adminstrator without "
"breaking file permissions in the GnuPG data folder.</para>"
"<para>To manage keys for other users please manage them as a normal user and "
"copy the <filename>AppData\\Roaming\\gnupg</filename> directory with proper permissions.</para>"),
i18nc("@title", "Running as Administrator"));
return EXIT_FAILURE;
}
KUniqueService service;
QObject::connect(&service, &KUniqueService::activateRequested,
&app, &KleopatraApplication::slotActivateRequested);
......
......@@ -72,3 +72,13 @@ QString Kleo::userEmailAddress()
}
return mbox;
}
bool Kleo::userIsElevated()
{
#ifdef Q_OS_WIN
static bool ret = win_user_is_elevated();
return ret;
#else
return false;
#endif
}
......@@ -15,9 +15,18 @@ class QString;
namespace Kleo
{
/* Tries to obtain the users full name from the
* operating system to be useable for Key creation. */
QString userFullName();
/* Tries to obtain the users email from the
* operating system to be useable for Key creation. */
QString userEmailAddress();
/* Checks if the user is running with an elevated security
* token. This is only a concept of Windows and returns
* false on other platforms. */
bool userIsElevated();
}
#endif // __KLEOPATRA_UTILS_USERINFO_H__
......@@ -43,3 +43,72 @@ QString win_get_user_name(EXTENDED_NAME_FORMAT what)
delete[] buf;
return ret.trimmed();
}
static bool has_high_integrity(HANDLE hToken)
{
PTOKEN_MANDATORY_LABEL integrity_label = NULL;
DWORD integrity_level = 0,
size = 0;
if (hToken == NULL || hToken == INVALID_HANDLE_VALUE) {
qCWarning(KLEOPATRA_LOG) << "Invalid parameters.";
return false;
}
/* Get the required size */
if (GetTokenInformation(hToken, TokenIntegrityLevel,
NULL, 0, &size) ||
GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
qCDebug(KLEOPATRA_LOG) << "Failed to get required size.";
return false;
}
integrity_label = (PTOKEN_MANDATORY_LABEL) LocalAlloc(0, size);
if (integrity_label == NULL) {
qCDebug(KLEOPATRA_LOG) << "Failed to allocate label.";
return false;
}
if (!GetTokenInformation(hToken, TokenIntegrityLevel,
integrity_label, size, &size)) {
qCDebug(KLEOPATRA_LOG) << "Failed to get integrity level.";
LocalFree(integrity_label);
return false;
}
/* Get the last integrity level */
integrity_level = *GetSidSubAuthority(integrity_label->Label.Sid,
(DWORD)(UCHAR)(*GetSidSubAuthorityCount(
integrity_label->Label.Sid) - 1));
LocalFree (integrity_label);
return integrity_level >= SECURITY_MANDATORY_HIGH_RID;
}
bool win_user_is_elevated()
{
HANDLE hToken = NULL;
bool ret = false;
if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &hToken)) {
DWORD elevation;
DWORD cbSize = sizeof(DWORD);
/* First get the elevation token and then check if that
* token has high integrity afterwards. */
if (GetTokenInformation (hToken, TokenElevation, &elevation,
sizeof(TokenElevation), &cbSize)) {
qCDebug(KLEOPATRA_LOG) << "Got ElevationToken " << elevation;
ret = elevation;
}
}
/* Elevation will be true and ElevationType TokenElevationTypeFull even
if the token is a user token created by SAFER so we additionally
check the integrity level of the token which will only be high in
the real elevated process and medium otherwise. */
ret = ret && has_high_integrity(hToken);
if (hToken) {
CloseHandle(hToken);
}
return ret;
}
......@@ -18,4 +18,6 @@
QString win_get_user_name(EXTENDED_NAME_FORMAT what);
bool win_user_is_elevated();
#endif // __KLEOPATRA_UTILS_USERINFO_WIN_P_H__
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment