RabbitCommon v2.2.6
Loading...
Searching...
No Matches
adminauthorization_x11.cpp
1
35#include "adminauthorization_p.h"
36
37#include <QDebug>
38#include <QFile>
39#include <QCoreApplication>
40#include <QInputDialog>
41#include <QMessageBox>
42
43#include <cstdlib>
44#include <sys/resource.h>
45#include <unistd.h>
46#include <fcntl.h>
47
48#ifdef Q_OS_LINUX
49#include <linux/limits.h>
50#include <pty.h>
51#else
52#include <util.h>
53#endif
54
55#include <sys/ioctl.h>
56#include <sys/types.h>
57#include <sys/wait.h>
58#include <QProcess>
59#include <QStandardPaths>
60#include <cerrno>
61
62using namespace RabbitCommon;
63
64#define SU_COMMAND "/usr/bin/sudo"
65
66namespace {
67
68bool execAdminFallback(const QString &program, const QStringList &arguments);
69const QList<QPair<QString, QStringList>> suFontends = {
70 {QStringLiteral("kdesu"), {QStringLiteral("-c")}},
71 {QStringLiteral("gksu"), {}}
72};
73
74}
75
77{
78 return getuid() == 0;
79}
80
81bool CAdminAuthorization::executeAsAdmin(const QString &program, const QStringList &arguments)
82{
83#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0))
84 for(const auto &su : qAsConst(suFontends)) {
85#else
86 for(const auto &su : suFontends) {
87#endif
88 auto command = QStandardPaths::findExecutable(su.first);
89 if(!command.isEmpty()) {
90 auto args = su.second;
91
92 QStringList tmpList{program};
93 tmpList.append(arguments);
94 args.append(QLatin1Char('\"') + tmpList.join(QStringLiteral("\" \"")) + QLatin1Char('\"'));
95
96 return QProcess::startDetached(command, args);
97 }
98 }
99
100 return execAdminFallback(program, arguments);
101}
102
103namespace {
104
105bool execAdminFallback(const QString &program, const QStringList &arguments)
106{
107 // as we cannot pipe the password to su in QProcess, we need to setup a pseudo-terminal for it
108 int masterFD = -1;
109 int slaveFD = -1;
110 char ptsn[ PATH_MAX ];
111
112 if (::openpty(&masterFD, &slaveFD, ptsn, nullptr, nullptr))
113 return false;
114
115 masterFD = ::posix_openpt(O_RDWR | O_NOCTTY);
116 if (masterFD < 0)
117 return false;
118
119 const QByteArray ttyName = ::ptsname(masterFD);
120
121 if (::grantpt(masterFD)) {
122 ::close(masterFD);
123 return false;
124 }
125
126 ::revoke(ttyName);
127 ::unlockpt(masterFD);
128
129 slaveFD = ::open(ttyName, O_RDWR | O_NOCTTY | O_CLOEXEC);
130 if (slaveFD < 0) {
131 ::close(masterFD);
132 return false;
133 }
134
135 ::fcntl(masterFD, F_SETFD, FD_CLOEXEC);
136 ::fcntl(slaveFD, F_SETFD, FD_CLOEXEC);
137 int pipedData[2];
138 if (pipe(pipedData) != 0)
139 return false;
140
141 int flags = ::fcntl(pipedData[0], F_GETFL);
142 if (flags != -1)
143 ::fcntl(pipedData[0], F_SETFL, flags | O_NONBLOCK);
144
145 flags = ::fcntl(masterFD, F_GETFL);
146 if (flags != -1)
147 ::fcntl(masterFD, F_SETFL, flags | O_NONBLOCK);
148
149 pid_t child = fork();
150
151 if (child < -1) {
152 ::close(masterFD);
153 ::close(slaveFD);
154 ::close(pipedData[0]);
155 ::close(pipedData[1]);
156 return false;
157 }
158
159 // parent process
160 else if (child > 0) {
161 ::close(slaveFD);
162 //close writing end of pipe
163 ::close(pipedData[1]);
164
165 QRegExp re{QLatin1String("[Pp]assword.*:")};
166 QByteArray data;
167 QByteArray errData;
168 int bytes = 0;
169 char buf[1024];
170 char errBuf[1024];
171 while (bytes >= 0) {
172 int state;
173 if (::waitpid(child, &state, WNOHANG) == -1)
174 break;
175
176 bytes = static_cast<int>(::read(masterFD, buf, 1023));
177 if (bytes == -1 && errno == EAGAIN)
178 bytes = 0;
179 else if (bytes > 0) {
180 if(!QByteArray(buf, bytes).simplified().isEmpty())
181 data.append(buf, bytes);
182 else
183 bytes = 0;
184 }
185 auto errBytes = static_cast<int>(::read(pipedData[0], errBuf, 1023));
186 if (errBytes > 0)
187 errData.append(errBuf, errBytes);
188
189 if (bytes > 0) {
190 const auto line = QString::fromLatin1(data);
191 if (re.indexIn(line) != -1) {
192 if(!errData.isEmpty()) {
193 QMessageBox::critical(nullptr, QObject::tr("Critical"),
194 QString::fromLocal8Bit(errData));
195 errData.clear();
196 }
197
198 bool ok = false;
199 const auto password = QInputDialog::getText(nullptr,
200 QCoreApplication::translate("AdminAuthorization",
201 "Enter Password"),
202 QCoreApplication::translate("AdminAuthorization",
203 "Enter your root password to run the program:"),
204 QLineEdit::Password,
205 QString(),
206 &ok,
207 Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
208
209 if (!ok) {
210 const auto pwd = password.toLatin1();
211 for (int i = 0; i < 3; ++i) {
212 ::write(masterFD, pwd.data(), static_cast<size_t>(pwd.length()));
213 ::write(masterFD, "\n", 1);
214 }
215 return false;
216 }
217 const auto pwd = password.toLatin1();
218 ::write(masterFD, pwd.data(), static_cast<size_t>(pwd.length()));
219 ::write(masterFD, "\n", 1);
220 ::read(masterFD, buf, static_cast<size_t>(pwd.length()) + 1);
221 }
222 }
223 if (bytes == 0)
224 ::usleep(100000);
225 }
226
227 if (!errData.isEmpty()) {
228 QMessageBox::critical(nullptr, QObject::tr("Critical"),
229 QString::fromLocal8Bit(errData));
230 return false;
231 }
232
233 int status;
234 ::wait(&status);
235 ::close(pipedData[1]);
236 return true;
237 } else {
238 ::close(pipedData[0]);
239 // Reset signal handlers
240 for (int sig = 1; sig < NSIG; ++sig)
241 signal(sig, SIG_DFL);
242 signal(SIGHUP, SIG_IGN);
243
244 ::setsid();
245
246 ::ioctl(slaveFD, TIOCSCTTY, 1);
247 int pgrp = ::getpid();
248 ::tcsetpgrp(slaveFD, pgrp);
249
250 ::dup2(slaveFD, 0);
251 ::dup2(slaveFD, 1);
252 ::dup2(pipedData[1], 2);
253
254 // close all file descriptors
255 struct rlimit rlp;
256 getrlimit(RLIMIT_NOFILE, &rlp);
257 for (int i = 3; i < static_cast<int>(rlp.rlim_cur); ++i)
258 ::close(i);
259
260 QList<QByteArray> args;
261 args.push_back(SU_COMMAND);
262 args.push_back("-b");
263 args.push_back("-p");
264 args.push_back("password:");
265 args.push_back(program.toLocal8Bit());
266 for (const auto &argument : arguments)
267 args.push_back(argument.toLocal8Bit());
268 QString szCmd;
269 for(auto &b: args)
270 {
271 szCmd += QString(b) + " ";
272 }
273 ::system(szCmd.toStdString().c_str());
274 /*
275 int i = 0;
276 char **argp = reinterpret_cast<char **>(::malloc(static_cast<ulong>(args.count()) * sizeof(char *)));
277 for (auto &arg : args)
278 argp[i] = arg.data();
279 argp[i] = nullptr;
280
281 ::unsetenv("LANG");
282 ::unsetenv("LC_ALL");
283
284 ::execv(SU_COMMAND, argp);//*/
285
286 _exit(EXIT_FAILURE);
287 return false;
288 }
289}
290
291}
292
bool hasAdminRights() override
Tests whether this program already has elevated rights or not.
bool executeAsAdmin(const QString &program, const QStringList &arguments) override
Runs a program with the given arguments with elevated rights.