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;
99 bool bRet = QProcess::startDetached(command, args);
100 qDebug(log) <<
"exec" << bRet << command << args;
104 return execAdminFallback(program, arguments);
107bool execAdminFallback(
const QString &program,
const QStringList &arguments)
112 char ptsn[ PATH_MAX ];
114 if (::openpty(&masterFD, &slaveFD, ptsn,
nullptr,
nullptr))
117 masterFD = ::posix_openpt(O_RDWR | O_NOCTTY);
121 const QByteArray ttyName = ::ptsname(masterFD);
123 if (::grantpt(masterFD)) {
129 ::unlockpt(masterFD);
131 slaveFD = ::open(ttyName, O_RDWR | O_NOCTTY | O_CLOEXEC);
137 ::fcntl(masterFD, F_SETFD, FD_CLOEXEC);
138 ::fcntl(slaveFD, F_SETFD, FD_CLOEXEC);
140 if (pipe(pipedData) != 0)
143 int flags = ::fcntl(pipedData[0], F_GETFL);
145 ::fcntl(pipedData[0], F_SETFL, flags | O_NONBLOCK);
147 flags = ::fcntl(masterFD, F_GETFL);
149 ::fcntl(masterFD, F_SETFL, flags | O_NONBLOCK);
151 pid_t child = fork();
156 ::close(pipedData[0]);
157 ::close(pipedData[1]);
159 }
else if (child > 0) {
162 ::close(pipedData[1]);
163#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
164 QRegExp re{QLatin1String(
"[Pp]assword.*:")};
166 QRegularExpression re{QLatin1String(
"[Pp]assword.*:")};
175 if (::waitpid(child, &state, WNOHANG) == -1)
178 bytes =
static_cast<int>(::read(masterFD, buf, 1023));
179 if (bytes == -1 && errno == EAGAIN)
181 else if (bytes > 0) {
182 if(!QByteArray(buf, bytes).simplified().isEmpty())
183 data.append(buf, bytes);
187 auto errBytes =
static_cast<int>(::read(pipedData[0], errBuf, 1023));
189 errData.append(errBuf, errBytes);
192 const auto line = QString::fromLatin1(data);
193#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
194 if (re.indexIn(line) != -1)
196 QRegularExpressionMatch match = re.match(line);
200 if(!errData.isEmpty()) {
201 QMessageBox::critical(
nullptr, QObject::tr(
"Critical"),
202 QString::fromLocal8Bit(errData));
207 const auto password = QInputDialog::getText(
209 QObject::tr(
"AdminAuthorization",
211 QObject::tr(
"AdminAuthorization",
212 "Enter your root password to run the program:"),
216 Qt::WindowCloseButtonHint | Qt::WindowStaysOnTopHint);
219 const auto pwd = password.toLatin1();
220 for (
int i = 0; i < 3; ++i) {
221 ::write(masterFD, pwd.data(),
222 static_cast<size_t>(pwd.length()));
223 ::write(masterFD,
"\n", 1);
227 const auto pwd = password.toLatin1();
228 ::write(masterFD, pwd.data(),
static_cast<size_t>(pwd.length()));
229 ::write(masterFD,
"\n", 1);
230 ::read(masterFD, buf,
static_cast<size_t>(pwd.length()) + 1);
237 if (!errData.isEmpty()) {
238 QMessageBox::critical(
nullptr, QObject::tr(
"Critical"),
239 QString::fromLocal8Bit(errData));
245 ::close(pipedData[1]);
248 ::close(pipedData[0]);
250 for (
int sig = 1; sig < NSIG; ++sig)
251 signal(sig, SIG_DFL);
252 signal(SIGHUP, SIG_IGN);
256 ::ioctl(slaveFD, TIOCSCTTY, 1);
257 int pgrp = ::getpid();
258 ::tcsetpgrp(slaveFD, pgrp);
262 ::dup2(pipedData[1], 2);
266 getrlimit(RLIMIT_NOFILE, &rlp);
267 for (
int i = 3; i < static_cast<int>(rlp.rlim_cur); ++i)
271 QString command = QStandardPaths::findExecutable(SU_COMMAND);
272 args.push_back(command);
273 args.push_back(
"-b");
274 args.push_back(
"-p");
275 args.push_back(
"password:");
276 args.push_back(program.toLocal8Bit());
277 for (
const auto &argument : arguments)
278 args.push_back(argument.toLocal8Bit());
284 int nRet = ::system(szCmd.toStdString().c_str());