35#include <QLoggingCategory>
37#include <QCoreApplication>
38#include <QInputDialog>
41#include <QStandardPaths>
43#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
46#include <QRegularExpression>
47#include <QRegularExpressionMatch>
51#include <sys/resource.h>
56#include <linux/limits.h>
67#include "adminauthorization_p.h"
69#define SU_COMMAND "/usr/bin/sudo"
71static Q_LOGGING_CATEGORY(log,
"RabbitCommon.Admin.Rights")
75bool execAdminFallback(
const QString &program,
const QStringList &arguments);
76const QList<QPair<QString, QStringList> > suFontends = {
77 {
"pkexec", {
"env",
"DISPLAY=" + QString::fromLocal8Bit(qgetenv(
"DISPLAY")),
"XAUTHORITY=" + QString::fromLocal8Bit(qgetenv(
"XAUTHORITY"))}},
82bool CAdminAuthorization::hasAdminRights()
87bool CAdminAuthorization::executeAsAdmin(
const QString &program,
const QStringList &arguments)
89 for(
const auto &su : suFontends) {
90 auto command = QStandardPaths::findExecutable(su.first);
91 if(command.isEmpty())
continue;
93 auto args = su.second;
98 args << program << arguments;
101 bRet = QProcess::startDetached(command, args);
103 bRet = QProcess::execute(command, args);
104 qDebug(log) <<
"exec" << bRet << command << args;
108 return execAdminFallback(program, arguments);
111bool execAdminFallback(
const QString &program,
const QStringList &arguments)
116 char ptsn[ PATH_MAX ];
118 if (::openpty(&masterFD, &slaveFD, ptsn,
nullptr,
nullptr))
121 masterFD = ::posix_openpt(O_RDWR | O_NOCTTY);
125 const QByteArray ttyName = ::ptsname(masterFD);
127 if (::grantpt(masterFD)) {
133 ::unlockpt(masterFD);
135 slaveFD = ::open(ttyName, O_RDWR | O_NOCTTY | O_CLOEXEC);
141 ::fcntl(masterFD, F_SETFD, FD_CLOEXEC);
142 ::fcntl(slaveFD, F_SETFD, FD_CLOEXEC);
144 if (pipe(pipedData) != 0)
147 int flags = ::fcntl(pipedData[0], F_GETFL);
149 ::fcntl(pipedData[0], F_SETFL, flags | O_NONBLOCK);
151 flags = ::fcntl(masterFD, F_GETFL);
153 ::fcntl(masterFD, F_SETFL, flags | O_NONBLOCK);
155 pid_t child = fork();
160 ::close(pipedData[0]);
161 ::close(pipedData[1]);
163 }
else if (child > 0) {
166 ::close(pipedData[1]);
167#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
168 QRegExp re{QLatin1String(
"[Pp]assword.*:")};
170 QRegularExpression re{QLatin1String(
"[Pp]assword.*:")};
179 if (::waitpid(child, &state, WNOHANG) == -1)
182 bytes =
static_cast<int>(::read(masterFD, buf, 1023));
183 if (bytes == -1 && errno == EAGAIN)
185 else if (bytes > 0) {
186 if(!QByteArray(buf, bytes).simplified().isEmpty())
187 data.append(buf, bytes);
191 auto errBytes =
static_cast<int>(::read(pipedData[0], errBuf, 1023));
193 errData.append(errBuf, errBytes);
196 const auto line = QString::fromLatin1(data);
197#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
198 if (re.indexIn(line) != -1)
200 QRegularExpressionMatch match = re.match(line);
204 if(!errData.isEmpty()) {
205 QMessageBox::critical(
nullptr, QObject::tr(
"Critical"),
206 QString::fromLocal8Bit(errData));
211 const auto password = QInputDialog::getText(
213 QObject::tr(
"AdminAuthorization",
215 QObject::tr(
"AdminAuthorization",
216 "Enter your root password to run the program:"),
220 Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
223 const auto pwd = password.toLatin1();
224 for (
int i = 0; i < 3; ++i) {
225 ::write(masterFD, pwd.data(),
226 static_cast<size_t>(pwd.length()));
227 ::write(masterFD,
"\n", 1);
231 const auto pwd = password.toLatin1();
232 ::write(masterFD, pwd.data(),
static_cast<size_t>(pwd.length()));
233 ::write(masterFD,
"\n", 1);
234 ::read(masterFD, buf,
static_cast<size_t>(pwd.length()) + 1);
241 if (!errData.isEmpty()) {
242 QMessageBox::critical(
nullptr, QObject::tr(
"Critical"),
243 QString::fromLocal8Bit(errData));
249 ::close(pipedData[1]);
252 ::close(pipedData[0]);
254 for (
int sig = 1; sig < NSIG; ++sig)
255 signal(sig, SIG_DFL);
256 signal(SIGHUP, SIG_IGN);
260 ::ioctl(slaveFD, TIOCSCTTY, 1);
261 int pgrp = ::getpid();
262 ::tcsetpgrp(slaveFD, pgrp);
266 ::dup2(pipedData[1], 2);
270 getrlimit(RLIMIT_NOFILE, &rlp);
271 for (
int i = 3; i < static_cast<int>(rlp.rlim_cur); ++i)
275 QString command = QStandardPaths::findExecutable(SU_COMMAND);
276 args.push_back(command);
277 args.push_back(
"-b");
278 args.push_back(
"-p");
279 args.push_back(
"password:");
280 args.push_back(program.toLocal8Bit());
281 for (
const auto &argument : arguments)
282 args.push_back(argument.toLocal8Bit());
288 int nRet = ::system(szCmd.toStdString().c_str());