Files

260 lines
8.9 KiB
C++
Raw Permalink Normal View History

2021-05-21 13:22:26 +02:00
#include <QtCore/QCoreApplication>
#include <QtDBus/QtDBus>
#include <QDebug>
2024-02-18 22:13:16 +01:00
#include <iostream>
constexpr const char *SERVICE_NAME = "org.tom.IsolationRunner";
2021-05-21 13:22:26 +02:00
class Client: public QObject
{
Q_OBJECT
2024-02-18 22:13:16 +01:00
public:
void setVerbose(bool on) {
m_verbose = on;
}
2024-02-19 19:52:24 +01:00
void setApp(const QString &appName, const QString &appPath) {
m_appName = appName;
m_appPath = appPath;
2024-02-18 22:13:16 +01:00
}
2024-02-19 19:52:24 +01:00
void setListDetails(bool getDetails) {
m_listDetails = getDetails;
}
void setAppArguments(const QList<QString> &arguments) {
m_arguments = arguments;
}
2024-02-18 23:42:08 +01:00
2024-02-25 23:29:33 +01:00
bool autodelete() const {
return m_autodelete;
}
void setAutodelete(bool ad) {
m_autodelete = ad;
}
bool lockedDown() const {
return m_lockedDown;
}
void setLockedDown(bool newLockedDown) {
m_lockedDown = newLockedDown;
}
2024-04-21 23:55:14 +02:00
void setEnclosingJailId(const QString &jailId) {
m_enclosingJailId = jailId;
}
2024-02-25 23:29:33 +01:00
2026-04-11 14:54:32 +02:00
void setVpnOVPNPath(const QString &newVpnOVPNPath)
{
m_vpnOVPNPath = newVpnOVPNPath;
}
void setVpnAcPath(const QString &newVpnAcPath)
{
m_vpnAcPath = newVpnAcPath;
}
2021-05-21 13:22:26 +02:00
public slots:
void start() {
struct ShutDown {
2024-02-18 22:13:16 +01:00
~ShutDown() { QCoreApplication::exit(rc); }
int rc = 0;
2021-05-21 13:22:26 +02:00
};
ShutDown shutDownHandler;
// find our remote
2024-02-18 22:13:16 +01:00
auto iface = new QDBusInterface(SERVICE_NAME, "/apps", SERVICE_NAME,
2021-05-21 13:22:26 +02:00
QDBusConnection::sessionBus(), this);
if (!iface->isValid()) {
2024-02-18 22:13:16 +01:00
shutDownHandler.rc = 1;
std::cerr << "Could not connect" << std::endl;
if (m_verbose)
std::cerr << "[" << qPrintable(QDBusConnection::sessionBus().lastError().message()) << "]" << std::endl;
2021-05-21 13:22:26 +02:00
return;
}
2024-02-20 20:27:07 +01:00
QTextStream out(stdout);
2024-02-19 20:17:07 +01:00
QDBusMessage rc;
if (m_listDetails && m_appName.isEmpty() && m_appPath.isEmpty()) {
2024-02-25 19:48:41 +01:00
rc = iface->callWithArgumentList(QDBus::Block, "listProfiles",
QVariantList() << QVariant::fromValue<bool>(m_verbose));
2024-02-20 20:27:07 +01:00
out << "Available profiles:" << Qt::endl << Qt::endl;
2024-02-19 20:17:07 +01:00
}
else {
QVariantList list;
list << m_appName;
if (!m_listDetails) {
// then its a call to 'run2'.
list.append(m_arguments);
list << m_appPath;
2024-02-25 23:29:33 +01:00
list << QVariant::fromValue(m_lockedDown);
list << QVariant::fromValue(m_autodelete);
2024-04-21 23:55:14 +02:00
list << QVariant::fromValue(m_enclosingJailId);
2026-04-11 14:54:32 +02:00
list << QVariant::fromValue(m_vpnAcPath);
list << QVariant::fromValue(m_vpnOVPNPath);
2024-02-19 20:17:07 +01:00
}
rc = iface->callWithArgumentList(QDBus::Block,
m_listDetails ? "details" : "run2", list);
2021-05-21 13:22:26 +02:00
}
2024-02-18 22:13:16 +01:00
if (rc.type() == QDBusMessage::ErrorMessage) {
QTextStream err(stderr);
2024-02-19 20:17:07 +01:00
err << "Failed: " << rc.errorMessage() << Qt::endl;
2024-02-19 10:47:36 +01:00
shutDownHandler.rc = 1;
2024-02-18 22:13:16 +01:00
return;
}
if (rc.type() != QDBusMessage::ReplyMessage) {
qWarning() << "huh? Not a reply received";
return;
}
for (const auto &line : rc.arguments()) {
if (line.canConvert(QMetaType::QString)) {
2024-02-18 23:42:08 +01:00
QString content = line.toString();
if (m_listDetails) {
printDetailsXml(out, content);
return;
}
2024-02-18 22:13:16 +01:00
out << line.toString() << Qt::endl;
continue;
}
// probably a wrapped one then.
auto embedded = line.value<QDBusVariant>().variant();
if (embedded.isValid()) {
2024-02-19 20:17:07 +01:00
if (embedded.canConvert(QMetaType::QStringList)) {
for (const auto &s : embedded.toStringList()) {
out << s << Qt::endl;
}
} else if (embedded.canConvert(QMetaType::QString)) {
out << embedded.toString() << Qt::endl;
}
2024-02-18 22:13:16 +01:00
}
}
2021-05-21 13:22:26 +02:00
}
2024-02-18 22:13:16 +01:00
private:
2024-02-18 23:42:08 +01:00
void printDetailsXml(QTextStream &out, const QString &xml) {
QXmlStreamReader parser(xml);
bool firstDeny = true;
bool firstAllow = true;
2024-02-25 19:48:41 +01:00
QStringView cur;
2024-02-18 23:42:08 +01:00
while (parser.readNextStartElement()) {
2024-02-25 19:48:41 +01:00
if (!cur.isEmpty() && cur != parser.name())
out << Qt::endl;
cur = QStringView();
2024-02-18 23:42:08 +01:00
if (parser.name() == QLatin1String("app")) {
auto att = parser.attributes();
2024-02-25 19:48:41 +01:00
out << "Profile: " << att.value("name") << Qt::endl;
out << " Path: " << att.value("exe") << Qt::endl;
2024-02-18 23:42:08 +01:00
if (m_verbose)
2024-02-25 19:48:41 +01:00
out << "Storage: $HOME/.local/jails/" << att.value("id") << "/" << Qt::endl;
2024-02-18 23:42:08 +01:00
}
else if (parser.name() == QLatin1String("denied")) {
if (firstDeny)
2024-02-25 19:48:41 +01:00
out << "Denied :";
2024-02-18 23:42:08 +01:00
firstDeny = false;
out << " ";
out << parser.readElementText();
2024-02-25 19:48:41 +01:00
cur = parser.name();
2024-02-18 23:42:08 +01:00
}
else if (parser.name() == QLatin1String("allowed")) {
2024-02-25 19:48:41 +01:00
if (firstAllow)
out << "Allowed:";
firstAllow = false;
2024-02-18 23:42:08 +01:00
out << " ";
out << parser.readElementText();
2024-02-25 19:48:41 +01:00
cur = parser.name();
}
else if (parser.name() == QLatin1String("lastRun")) {
auto att = parser.attributes();
auto start = QDateTime::fromString(att.value("start").toString(), Qt::ISODate);
auto convertedStart = start.toLocalTime();
out << "Started: " << convertedStart.toString() << Qt::endl;
if (!att.value("pid").isNull())
out << " [Currently Running] PID: " << att.value("pid").toString() << Qt::endl;
2024-02-18 23:42:08 +01:00
}
}
}
2024-02-18 22:13:16 +01:00
bool m_verbose = false;
2024-02-18 23:42:08 +01:00
bool m_listDetails = false;
2024-02-25 23:29:33 +01:00
bool m_lockedDown = false;
bool m_autodelete = false;
2024-02-19 19:52:24 +01:00
QString m_appName;
QString m_appPath;
2024-04-21 23:55:14 +02:00
QString m_enclosingJailId;
2024-02-19 19:52:24 +01:00
QStringList m_arguments;
2026-04-11 14:54:32 +02:00
// vpn
QString m_vpnOVPNPath;
QString m_vpnAcPath;
2021-05-21 13:22:26 +02:00
};
int main(int x, char **y) {
2024-02-18 22:13:16 +01:00
QCoreApplication app(x, y);
QCommandLineParser parser;
parser.setApplicationDescription("Isolation Application runner");
2024-02-25 19:48:41 +01:00
parser.addPositionalArgument("application", "The app you wish to run or list");
2024-02-18 22:13:16 +01:00
parser.addHelpOption(); // allows users to get an overview of options
2024-02-25 19:48:41 +01:00
QCommandLineOption details(QStringList() << "details" << "l", "list details instead");
parser.addOption(details);
2024-02-18 22:13:16 +01:00
QCommandLineOption verbose(QStringList() << "verbose" << "v", "More verbose output");
parser.addOption(verbose);
2024-02-25 19:48:41 +01:00
QCommandLineOption exe(QStringList() << "exe" << "e", "Full path of exe to run", "PATH");
2024-02-19 19:52:24 +01:00
parser.addOption(exe);
2024-02-25 23:29:33 +01:00
QCommandLineOption lockdown(QStringList() << "secure" << "s", "Run app with minimal permissions");
parser.addOption(lockdown);
QCommandLineOption autodelete(QStringList() << "rm", "Auto delete upon completion");
parser.addOption(autodelete);
2024-04-21 23:55:14 +02:00
QCommandLineOption inJail(QStringList() << "in", "Run exe IN argument jail", "JAIL");
parser.addOption(inJail);
2026-04-11 14:54:32 +02:00
QCommandLineOption vpnConf(QStringList() << "vpn", "A OVPN open vpn config file", "PATH");
parser.addOption(vpnConf);
QCommandLineOption vpnPwdFile(QStringList() << "vpnac", "VPN AccessCredentials file path", "PATH");
parser.addOption(vpnPwdFile);
2024-02-18 22:13:16 +01:00
parser.process(app);
2024-02-19 19:52:24 +01:00
/*
* Users may simply want to start an executable and they pass in that exe
* name as 'appName'. This should obviously be possible.
*
* What should also nicely work, it should be possible to start "socials" as
* an appName and on first run we can pass in the appPath (/bin/firefox) and
* any arguments.
*/
QString appName;
QString appPath;
if (parser.isSet(exe))
appPath = parser.value(exe);
const auto args = parser.positionalArguments();
if (!args.isEmpty())
appName = args.first();
if (appName.isEmpty())
appName = appPath;
2021-05-21 13:22:26 +02:00
2024-02-25 19:48:41 +01:00
if (appName.isEmpty() && !parser.isSet(details))
parser.showHelp(0);
2021-05-21 13:22:26 +02:00
if (!QDBusConnection::sessionBus().isConnected()) {
fprintf(stderr, "Cannot connect to the D-Bus session bus.\n");
return 1;
}
Client client;
2024-02-18 22:13:16 +01:00
client.setVerbose(parser.isSet(verbose));
2024-02-18 23:42:08 +01:00
client.setListDetails(parser.isSet(details));
2024-02-25 23:29:33 +01:00
client.setAutodelete(parser.isSet(autodelete));
client.setLockedDown(parser.isSet(lockdown));
2026-04-11 14:54:32 +02:00
client.setVpnAcPath(parser.value(vpnPwdFile));
client.setVpnOVPNPath(parser.value(vpnConf));
2024-04-21 23:55:14 +02:00
if (parser.isSet(inJail))
client.setEnclosingJailId(parser.value(inJail));
2024-02-19 19:52:24 +01:00
client.setApp(appName, appPath);
client.setAppArguments(args.mid(1));
2021-05-21 13:22:26 +02:00
QTimer::singleShot(0, &client, &Client::start);
return app.exec();
}
#include "client.moc"