From f13345e0f209edee59d896a21717bd48c48803c3 Mon Sep 17 00:00:00 2001 From: Syping Date: Mon, 14 Sep 2020 08:02:06 +0200 Subject: [PATCH] Token secured remote server for websockify --- SMSubServer.cpp | 119 +++++++++++++++++++++++++++++++++--------------- SMSubServer.h | 12 ++++- main.cpp | 81 ++++++++++++++++++++++++++------ 3 files changed, 160 insertions(+), 52 deletions(-) diff --git a/SMSubServer.cpp b/SMSubServer.cpp index 3160d44..d411284 100644 --- a/SMSubServer.cpp +++ b/SMSubServer.cpp @@ -17,10 +17,12 @@ *****************************************************************************/ #include +#include +#include #include "SMSubServer.h" #include "smsub.h" -SMSubServer::SMSubServer(const QString &socket) +SMSubServer::SMSubServer(SMSubServerSettings *serverSettings, const QString &socket) : serverSettings(serverSettings) { setSocketOptions(QLocalServer::UserAccessOption | QLocalServer::GroupAccessOption); listen(socket); @@ -30,9 +32,17 @@ void SMSubServer::incomingConnection(quintptr socketDescriptor) { QLocalSocket *socket = new QLocalSocket(); socket->setSocketDescriptor(socketDescriptor); - QObject::connect(socket, SIGNAL(readyRead()), this, SLOT(readyRead())); - QObject::connect(socket, SIGNAL(disconnected()), this, SLOT(deleteSocket())); - sockets << socket; + QObject::connect(socket, &QLocalSocket::readyRead, this, &SMSubServer::readyRead); + QObject::connect(socket, &QLocalSocket::disconnected, this, &SMSubServer::deleteSocket); + + // Set authentication state + if (serverSettings->isLocal) { + socket->setProperty("Authenticated", true); + sockets << socket; + } + else { + socket->setProperty("Authenticated", false); + } // Initial open writing socket->write(QString("SMSub Version %1\n").arg(QCoreApplication::applicationVersion()).toUtf8()); @@ -42,41 +52,70 @@ void SMSubServer::readyRead() { // Manage client input QLocalSocket *socket = (QLocalSocket*)sender(); + bool isAuthenticated = socket->property("Authenticated").toBool(); while (socket->canReadLine()) { const QByteArray readData = socket->readLine().trimmed(); - if (readData.startsWith("+dbg")) { - socket->setProperty("ReceiveDbgMsg", true); - socket->write("Debug messages enabled!\n"); + if (likely(isAuthenticated)) { + if (readData.startsWith("+dbg")) { + socket->setProperty("ReceiveDbgMsg", true); + socket->write("Debug messages enabled!\n"); + } + else if (readData.startsWith("-dbg")) { + socket->setProperty("ReceiveDbgMsg", false); + socket->write("Debug messages disabled!\n"); + } + else if (readData.startsWith("+log")) { + socket->setProperty("ReceiveLog", true); + debugOutput(socket, "Log output enabled!"); + } + else if (readData.startsWith("-log")) { + socket->setProperty("ReceiveLog", false); + debugOutput(socket, "Log output disabled!"); + } + else if (readData.startsWith("+reg")) { + if (likely(serverSettings->canRegister)) { + QByteArray authUuid = QUuid::createUuid().toByteArray(QUuid::Id128); + authUuid = QByteArray::fromHex(authUuid).toBase64(QByteArray::OmitTrailingEquals); + emit tokenRegistered(QString::fromUtf8(authUuid)); + socket->write("Token: " + authUuid + '\n'); + } + else { + socket->write("Permission denied!\n"); + } + } + else if (readData.startsWith("kill")) { + emit killRequested(); + debugOutput(socket, "Killing server!"); + } + else if (readData.startsWith("stop")) { + emit stopRequested(); + debugOutput(socket, "Stopping server!"); + } + else if (readData.startsWith("wl")) { + const QByteArray writeData = readData.mid(3); + emit inputWritten(writeData + '\n'); + debugOutput(socket, "Write line \"" + writeData + "\"!"); + } + else if (readData.startsWith("w")) { + const QByteArray writeData = readData.mid(2); + emit inputWritten(writeData); + debugOutput(socket, "Write \"" + writeData + "\"!"); + } } - else if (readData.startsWith("-dbg")) { - socket->setProperty("ReceiveDbgMsg", false); - socket->write("Debug messages disabled!\n"); - } - else if (readData.startsWith("+log")) { - socket->setProperty("ReceiveLog", true); - debugOutput(socket, "Log output enabled!"); - } - else if (readData.startsWith("-log")) { - socket->setProperty("ReceiveLog", false); - debugOutput(socket, "Log output disabled!"); - } - else if (readData.startsWith("kill")) { - emit killRequested(); - debugOutput(socket, "Killing server!"); - } - else if (readData.startsWith("stop")) { - emit stopRequested(); - debugOutput(socket, "Stopping server!"); - } - else if (readData.startsWith("wl")) { - const QByteArray writeData = readData.mid(3); - emit inputWritten(writeData + '\n'); - debugOutput(socket, "Write line \"" + writeData + "\"!"); - } - else if (readData.startsWith("w")) { - const QByteArray writeData = readData.mid(2); - emit inputWritten(writeData); - debugOutput(socket, "Write \"" + writeData + "\"!"); + else { + if (unlikely(tokens.contains(QString::fromUtf8(readData)))) { + socket->setProperty("Authenticated", true); + socket->write("Login successful!\n"); + isAuthenticated = true; + sockets << socket; + } + else { + // Stop receiving data and disconnect socket + QObject::disconnect(socket, &QLocalSocket::readyRead, this, &SMSubServer::readyRead); + socket->write("Incorrect token!\n"); + socket->disconnectFromServer(); + return; + } } } } @@ -117,3 +156,11 @@ void SMSubServer::writeOutput(const QByteArray &output) it++; } } + +void SMSubServer::registerToken(const QString &token) +{ + tokens << token; + QTimer::singleShot(30000, [this, token]() { + tokens.removeAll(token); + }); +} diff --git a/SMSubServer.h b/SMSubServer.h index c5552f5..e39a178 100644 --- a/SMSubServer.h +++ b/SMSubServer.h @@ -23,14 +23,21 @@ #include #include +struct SMSubServerSettings +{ + bool canRegister; + bool isLocal; +}; + class SMSubServer : public QLocalServer { Q_OBJECT public: - SMSubServer(const QString &socket); + SMSubServer(SMSubServerSettings *serverSettings, const QString &socket); public slots: void writeOutput(const QByteArray &output); + void registerToken(const QString &token); private slots: void incomingConnection(quintptr socketDescriptor); @@ -39,9 +46,12 @@ private slots: private: inline void debugOutput(QLocalSocket *socket, const QByteArray &message); + SMSubServerSettings *serverSettings; QVector sockets; + QVector tokens; signals: + void tokenRegistered(const QString &password); void inputWritten(const QByteArray &input); void killRequested(); void stopRequested(); diff --git a/main.cpp b/main.cpp index 85646e1..4f68766 100644 --- a/main.cpp +++ b/main.cpp @@ -45,7 +45,7 @@ void catchUnixSignals(std::initializer_list quitSignals) { sigset_t blocking_mask; sigemptyset(&blocking_mask); - for (auto sig : quitSignals) + for (int sig : quitSignals) sigaddset(&blocking_mask, sig); struct sigaction sa; @@ -53,7 +53,7 @@ void catchUnixSignals(std::initializer_list quitSignals) { sa.sa_mask = blocking_mask; sa.sa_flags = 0; - for (auto sig : quitSignals) + for (int sig : quitSignals) sigaction(sig, &sa, nullptr); } #endif @@ -62,7 +62,7 @@ int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); a.setApplicationName("Server Manager Subprocess"); - a.setApplicationVersion("0.1"); + a.setApplicationVersion("0.2"); #ifdef Q_OS_UNIX catchUnixSignals({SIGQUIT, SIGINT, SIGTERM, SIGHUP}); @@ -82,12 +82,19 @@ int main(int argc, char *argv[]) commandLineParser.addOption(processArguments); #ifdef Q_OS_WIN - QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "IPC socket used for communication.", "sock"); + QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "IPC socket used for local communication.", "sock"); #else - QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "Unix socket used for communication.", "sock"); + QCommandLineOption subprocessSocket(QStringList() << "sock" << "socket", "Unix socket used for local communication.", "sock"); #endif commandLineParser.addOption(subprocessSocket); +#ifdef Q_OS_WIN + QCommandLineOption subprocessRemoteSocket(QStringList() << "rsock" << "rsocket", "IPC socket used for remote communication.", "rsock"); +#else + QCommandLineOption subprocessRemoteSocket(QStringList() << "rsock" << "rsocket", "Unix socket used for remote communication.", "rsock"); +#endif + commandLineParser.addOption(subprocessRemoteSocket); + commandLineParser.process(a); if (unlikely(commandLineParser.isSet(processManifest) && commandLineParser.isSet(processExecutable))) { @@ -163,24 +170,68 @@ int main(int argc, char *argv[]) if (likely(commandLineParser.isSet(subprocessSocket))) { socket = commandLineParser.value(subprocessSocket); } - - SMSubServer subServer(socket); - if (unlikely(!subServer.isListening())) { + else { #ifdef Q_OS_WIN - QTextStream(stderr) << "Failed to start IPC socket!" << endl; + QTextStream(stderr) << "You must define at least a local IPC socket!" << endl; #else - QTextStream(stderr) << "Failed to start Unix socket!" << endl; + QTextStream(stderr) << "You must define at least a local Unix socket!" << endl; #endif return 1; } + SMSubServerSettings localSettings; + localSettings.isLocal = true; + + SMSubServer subLocal(&localSettings, socket); + if (unlikely(!subLocal.isListening())) { +#ifdef Q_OS_WIN + QTextStream(stderr) << "Failed to start local IPC socket!" << endl; +#else + QTextStream(stderr) << "Failed to start local Unix socket!" << endl; +#endif + return 1; + } + + QString rsocket; + if (unlikely(commandLineParser.isSet(subprocessRemoteSocket))) { + rsocket = commandLineParser.value(subprocessRemoteSocket); + } + + SMSubServerSettings remoteSettings; + remoteSettings.canRegister = false; + remoteSettings.isLocal = false; + + SMSubServer subRemote(&remoteSettings, rsocket); + if (unlikely(!rsocket.isEmpty())) { + if (unlikely(!subRemote.isListening())) { +#ifdef Q_OS_WIN + QTextStream(stderr) << "Failed to start remote IPC socket!" << endl; +#else + QTextStream(stderr) << "Failed to start remote Unix socket!" << endl; +#endif + return 1; + } + localSettings.canRegister = true; + } + else { + localSettings.canRegister = false; + } + SMSubProcess subProcess(executable, argumentList, workingDirectory); - QObject::connect(&subProcess, SIGNAL(outputWritten(QByteArray)), &subServer, SLOT(writeOutput(QByteArray))); - QObject::connect(&subServer, SIGNAL(inputWritten(QByteArray)), &subProcess, SLOT(writeInput(QByteArray))); - QObject::connect(&subServer, SIGNAL(killRequested()), &subProcess, SLOT(killProcess())); - QObject::connect(&subServer, SIGNAL(stopRequested()), &subProcess, SLOT(stopProcess())); - QObject::connect(&a, SIGNAL(aboutToQuit()), &subProcess, SLOT(aboutToQuit())); + QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subLocal, &SMSubServer::writeOutput); + QObject::connect(&subLocal, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); + QObject::connect(&subLocal, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(&subLocal, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); + QObject::connect(&a, &QCoreApplication::aboutToQuit, &subProcess, &SMSubProcess::aboutToQuit); + + if (unlikely(!rsocket.isEmpty())) { + QObject::connect(&subLocal, &SMSubServer::tokenRegistered, &subRemote, &SMSubServer::registerToken); + QObject::connect(&subProcess, &SMSubProcess::outputWritten, &subRemote, &SMSubServer::writeOutput); + QObject::connect(&subRemote, &SMSubServer::inputWritten, &subProcess, &SMSubProcess::writeInput); + QObject::connect(&subRemote, &SMSubServer::killRequested, &subProcess, &SMSubProcess::killProcess); + QObject::connect(&subRemote, &SMSubServer::stopRequested, &subProcess, &SMSubProcess::stopProcess); + } subProcess.start();