-
Notifications
You must be signed in to change notification settings - Fork 1
/
platform_lin_suprogram.cpp
155 lines (130 loc) · 4.91 KB
/
platform_lin_suprogram.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#include <QProcess>
#include <QStandardPaths>
#include <QFile>
#include "common.h"
#include "platform_lin_suprogram.h"
// Copied from private Qt implementation at qtbase/src/platformsupport/services/genericunix/qgenericunixservices.cpp
static QString detectDesktopEnvironment()
{
const QString xdgCurrentDesktop = qgetenv("XDG_CURRENT_DESKTOP");
if (!xdgCurrentDesktop.isEmpty())
return xdgCurrentDesktop.toUpper(); // KDE, GNOME, UNITY, LXDE, MATE, XFCE...
// Classic fallbacks
if (!qEnvironmentVariableIsEmpty("KDE_FULL_SESSION"))
return "KDE";
if (!qEnvironmentVariableIsEmpty("GNOME_DESKTOP_SESSION_ID"))
return "GNOME";
// Fallback to checking $DESKTOP_SESSION (unreliable)
const QString desktopSession = qgetenv("DESKTOP_SESSION");
if (desktopSession == "gnome")
return "GNOME";
if (desktopSession == "xfce")
return "XFCE";
return "";
}
SuProgram::SuProgram(QString binaryName, QStringList suArgs, bool splitArgs)
: m_binaryName(binaryName)
, m_suArgs(suArgs)
, m_splitArgs(splitArgs)
{
m_binaryPath = QStandardPaths::findExecutable(m_binaryName);
}
XdgSu::XdgSu()
: SuProgram("xdg-su", {"-c"}, false)
{
}
KdeSu::KdeSu()
: SuProgram("kdesu", {"-c"}, false)
{
// Extract from man:
// Since <kdesu> is no longer installed in <$(kde4-config --prefix)/bin> but in <kde4-config --path libexec>
// and therefore not in your <Path>, you have to use <$(kde4-config --path libexec)kdesu> to launch <kdesu>.
// Now, what we do: first, simple PATH check is performed in SuProgram constructor. Then we try to find kdesu
// according to the KDE documentation and, if found, overwrite the path with the new one.
QProcess kdeConfig;
kdeConfig.start("kde4-config", {"--path", "libexec"}, QIODevice::ReadOnly);
kdeConfig.waitForFinished(3000);
QString kdesuPath = kdeConfig.readAllStandardOutput().trimmed();
if (!kdesuPath.isEmpty())
{
kdesuPath += (kdesuPath.endsWith('/') ? "" : "/");
kdesuPath += "kdesu";
if (QFile::exists(kdesuPath) && QFile::permissions(kdesuPath).testFlag(QFileDevice::ExeUser))
m_binaryPath = kdesuPath;
}
}
GkSu::GkSu()
: SuProgram("gksu", {}, false)
{
}
BeeSu::BeeSu()
: SuProgram("beesu", {}, true)
{
}
bool SuProgram::isPresent() const
{
return (!m_binaryPath.isEmpty());
}
bool XdgSu::isNative() const
{
// xdg-su is considered a universal tool
return true;
}
bool KdeSu::isNative() const
{
// kdesu is native only in KDE
const QString desktopEnvironment = detectDesktopEnvironment();
return (desktopEnvironment == "KDE");
}
bool GkSu::isNative() const
{
// gksu is native for GTK-based DEs; however, for Qt-based DEs (like LXQt) there is no alternative either
const QString desktopEnvironment = detectDesktopEnvironment();
return (!desktopEnvironment.isEmpty() && (desktopEnvironment != "KDE"));
}
bool BeeSu::isNative() const
{
// beesu is developed for Fedora/RedHat, let's consider it native there
QFile redhatRelease("/etc/redhat-release");
if (!redhatRelease.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
QString redhatInfo = redhatRelease.readAll();
return redhatInfo.contains("Red Hat", Qt::CaseInsensitive) || redhatInfo.contains("Fedora", Qt::CaseInsensitive);
}
void SuProgram::restartAsRoot(const QStringList& args)
{
if (m_binaryPath.isEmpty())
return;
int i;
// For execv() we need the list of char* arguments; using QByteArrays as temporary storage
// Store QByteArray objects explicitly to make sure they live long enough, so that their data()'s were valid until execv() call
QList<QByteArray> argsBA;
// First comes the application being started (su-application) with all its arguments (if any)
argsBA << m_binaryPath.toUtf8();
for (i = 0; i < m_suArgs.size(); ++i)
argsBA << m_suArgs[i].toUtf8();
// Now append the passed arguments
// Depending on the su-application, we may need to either pas them separately, or space-join them into one single argument word
if (m_splitArgs)
{
for (i = 0; i < args.size(); ++i)
argsBA << args[i].toUtf8();
}
else
{
QString joined = '\'' + args[0] + '\'';
for (i = 1; i < args.size(); ++i)
joined += " '" + args[i] + "'";
argsBA << joined.toUtf8();
}
// Convert arguments into char*'s and append NULL element
int argsNum = argsBA.size();
char** argsBin = new char*[argsNum + 1];
for (i = 0; i < argsNum; ++i)
argsBin[i] = argsBA[i].data();
argsBin[argsNum] = NULL;
// Replace ourselves with su-application
execv(argsBin[0], argsBin);
// Something went wrong, we should have never returned! Cleaning up
delete[] argsBin;
}