-
-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathmain.cpp
More file actions
145 lines (129 loc) · 5.92 KB
/
Copy pathmain.cpp
File metadata and controls
145 lines (129 loc) · 5.92 KB
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
/*****************************************************************************
* main.cpp
*****************************************************************************
* Copyright (C) 2022 MX Authors
*
* Authors: Adrian <adrian@mxlinux.org>
* MX Linux <http://mxlinux.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MX Viewer is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MX Viewer. If not, see <http://www.gnu.org/licenses/>.
****************************************************************************/
#include "mainwindow.h"
#include "version.h"
#include <unistd.h>
QPair<int, int> getUserIDs()
{
QPair<uint, uint> id;
QProcess proc;
proc.start("logname", {}, QIODevice::ReadOnly);
proc.waitForFinished();
QString logname = QString::fromLatin1(proc.readAllStandardOutput().trimmed());
proc.start("id", {"-u", logname}, QIODevice::ReadOnly);
proc.waitForFinished();
id.first = proc.readAllStandardOutput().trimmed().toUInt();
proc.start("id", {"-g", logname}, QIODevice::ReadOnly);
proc.waitForFinished();
id.second = proc.readAllStandardOutput().trimmed().toUInt();
return id;
}
// Drop rights of the program to regular user or 'nobody' if logname return root id or gid
// Used to drop rights to 'nobody', but normal user rights might be needed to write cache and cookies.
bool dropElevatedPrivileges(bool force_nobody)
{
if (getuid() != 0 && geteuid() != 0) {
return true;
}
// ref:
// https://www.safaribooksonline.com/library/view/secure-programming-cookbook/0596003943/ch01s03.html#secureprgckbk-CHP-1-SECT-3.3
auto [id, gid] = getUserIDs();
const int nobody = 65534; // nobody (uid 65534), nogroup (gid 65534)
if (id == 0 || gid == 0 || force_nobody) {
id = gid = nobody;
}
if (setgid(gid) != 0) {
return false;
}
if (setuid(id) != 0) {
return false;
}
// On systems with defined _POSIX_SAVED_IDS in the unistd.h file, it should be
// impossible to regain elevated privs after the setuid() call, above. Test, try to regain elev priv:
if (setuid(0) != -1 || seteuid(0) != -1) {
return false; // and the calling fn should EXIT/abort the program
}
// change cwd, for good measure (if unable to, treat as overall failure)
if (chdir("/tmp") != 0) {
qDebug() << "Can't change working directory to /tmp";
return false;
}
return true;
}
int main(int argc, char *argv[])
{
QApplication::setHighDpiScaleFactorRoundingPolicy(Qt::HighDpiScaleFactorRoundingPolicy::PassThrough);
QGuiApplication::setQuitOnLastWindowClosed(true);
QApplication app(argc, argv);
QApplication::setWindowIcon(QIcon::fromTheme(QApplication::applicationName()));
QApplication::setApplicationVersion(VERSION);
QApplication::setOrganizationName("MX-Linux");
QCommandLineParser parser;
parser.setApplicationDescription(
QObject::tr("This tool will display the URL content in a window, window title is optional"));
parser.addHelpOption();
parser.addVersionOption();
parser.addOption({{"f", "full-screen"}, QObject::tr("Start program in full-screen mode")});
parser.addOption({{"i", "disable-images"}, QObject::tr("Disable load images automatically from websites")});
parser.addOption({{"j", "disable-js"}, QObject::tr("Disable JavaScript")});
if (getuid() == 0 || geteuid() == 0) {
parser.addOption(
{{"n", "force-nobody"},
QObject::tr("Drop program's rights to 'nobody'. By default, if run as root, the rights are "
"dropped to normal user. This option might provide additional protection, but the program "
"would not be able to write its cache and cookies to the user directory, so it might break "
"some functionality.")});
}
parser.addOption({{"s", "enable-spatial-navigation"}, QObject::tr("Enable spatial navigation with keyboard")});
parser.addPositionalArgument(QObject::tr("URL"),
QObject::tr("URL of the page you want to load")
+ "\ne.g., https://google.com, google.com, file:///home/user/file.html");
parser.addPositionalArgument(QObject::tr("Title"), QObject::tr("Window title for the viewer"), "[title]");
parser.process(app);
bool force_nobody = (getuid() == 0 || geteuid() == 0) ? parser.isSet("force-nobody") : false;
if (!dropElevatedPrivileges(force_nobody)) {
qDebug() << "Could not drop elevated privileges";
exit(EXIT_FAILURE);
}
QTranslator qtTran;
if (qtTran.load(QLocale::system(), "qt", "_", QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
QApplication::installTranslator(&qtTran);
}
QTranslator qtBaseTran;
if (qtBaseTran.load("qtbase_" + QLocale::system().name(), QLibraryInfo::path(QLibraryInfo::TranslationsPath))) {
QApplication::installTranslator(&qtBaseTran);
}
QTranslator appTran;
if (appTran.load(QApplication::applicationName() + "_" + QLocale::system().name(),
"/usr/share/" + QApplication::applicationName() + "/locale")) {
QApplication::installTranslator(&appTran);
}
auto *window = new MainWindow(parser);
window->show();
// Ensure proper cleanup on application exit
QObject::connect(&app, &QApplication::aboutToQuit, [window]() {
if (window && !window->isHidden()) {
window->close();
}
});
return QApplication::exec();
}