mirror of
				https://github.com/yuezk/GlobalProtect-openconnect.git
				synced 2025-05-20 07:26:58 -04:00 
			
		
		
		
	Initial commit
This commit is contained in:
		
							
								
								
									
										21
									
								
								GPClient/.qmake.stash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								GPClient/.qmake.stash
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| QMAKE_CXX.QT_COMPILER_STDCXX = 201402L | ||||
| QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 9 | ||||
| QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2 | ||||
| QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0 | ||||
| QMAKE_CXX.COMPILER_MACROS = \ | ||||
|     QT_COMPILER_STDCXX \ | ||||
|     QMAKE_GCC_MAJOR_VERSION \ | ||||
|     QMAKE_GCC_MINOR_VERSION \ | ||||
|     QMAKE_GCC_PATCH_VERSION | ||||
| QMAKE_CXX.INCDIRS = \ | ||||
|     /usr/include/c++/9.2.0 \ | ||||
|     /usr/include/c++/9.2.0/x86_64-pc-linux-gnu \ | ||||
|     /usr/include/c++/9.2.0/backward \ | ||||
|     /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include \ | ||||
|     /usr/local/include \ | ||||
|     /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include-fixed \ | ||||
|     /usr/include | ||||
| QMAKE_CXX.LIBDIRS = \ | ||||
|     /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0 \ | ||||
|     /usr/lib \ | ||||
|     /lib | ||||
							
								
								
									
										
											BIN
										
									
								
								GPClient/GPClient
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								GPClient/GPClient
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										41
									
								
								GPClient/GPClient.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								GPClient/GPClient.pro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| QT       += core gui network websockets dbus webenginewidgets | ||||
|  | ||||
| greaterThan(QT_MAJOR_VERSION, 4): QT += widgets | ||||
|  | ||||
| CONFIG += c++11 | ||||
|  | ||||
| # The following define makes your compiler emit warnings if you use | ||||
| # any Qt feature that has been marked deprecated (the exact warnings | ||||
| # depend on your compiler). Please consult the documentation of the | ||||
| # deprecated API in order to know how to port your code away from it. | ||||
| DEFINES += QT_DEPRECATED_WARNINGS | ||||
|  | ||||
| # You can also make your code fail to compile if it uses deprecated APIs. | ||||
| # In order to do so, uncomment the following line. | ||||
| # You can also select to disable deprecated APIs only up to a certain version of Qt. | ||||
| #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0 | ||||
|  | ||||
| SOURCES += \ | ||||
|     cdpcommand.cpp \ | ||||
|     cdpcommandmanager.cpp \ | ||||
|     enhancedwebview.cpp \ | ||||
|     main.cpp \ | ||||
|     samlloginwindow.cpp \ | ||||
|     gpclient.cpp | ||||
|  | ||||
| HEADERS += \ | ||||
|     cdpcommand.h \ | ||||
|     cdpcommandmanager.h \ | ||||
|     enhancedwebview.h \ | ||||
|     samlloginwindow.h \ | ||||
|     gpclient.h | ||||
|  | ||||
| FORMS += \ | ||||
|     gpclient.ui | ||||
|  | ||||
| DBUS_INTERFACES += ../GPService/gpservice.xml | ||||
|  | ||||
| # Default rules for deployment. | ||||
| qnx: target.path = /tmp/$${TARGET}/bin | ||||
| else: unix:!android: target.path = /opt/$${TARGET}/bin | ||||
| !isEmpty(target.path): INSTALLS += target | ||||
							
								
								
									
										30
									
								
								GPClient/cdpcommand.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								GPClient/cdpcommand.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| #include "cdpcommand.h" | ||||
|  | ||||
| #include <QVariantMap> | ||||
| #include <QJsonDocument> | ||||
| #include <QJsonObject> | ||||
|  | ||||
| CDPCommand::CDPCommand(QObject *parent) : QObject(parent) | ||||
| { | ||||
| } | ||||
|  | ||||
| CDPCommand::CDPCommand(int id, QString cmd, QVariantMap& params) : | ||||
|     QObject(nullptr), | ||||
|     id(id), | ||||
|     cmd(cmd), | ||||
|     params(¶ms) | ||||
| { | ||||
| } | ||||
|  | ||||
| QByteArray CDPCommand::toJson() | ||||
| { | ||||
|     QVariantMap payloadMap; | ||||
|     payloadMap["id"] = id; | ||||
|     payloadMap["method"] = cmd; | ||||
|     payloadMap["params"] = *params; | ||||
|  | ||||
|     QJsonObject payloadJsonObject = QJsonObject::fromVariantMap(payloadMap); | ||||
|     QJsonDocument payloadJson(payloadJsonObject); | ||||
|  | ||||
|     return payloadJson.toJson(); | ||||
| } | ||||
							
								
								
									
										24
									
								
								GPClient/cdpcommand.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								GPClient/cdpcommand.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,24 @@ | ||||
| #ifndef CDPCOMMAND_H | ||||
| #define CDPCOMMAND_H | ||||
|  | ||||
| #include <QObject> | ||||
|  | ||||
| class CDPCommand : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit CDPCommand(QObject *parent = nullptr); | ||||
|     CDPCommand(int id, QString cmd, QVariantMap& params); | ||||
|  | ||||
|     QByteArray toJson(); | ||||
|  | ||||
| signals: | ||||
|     void finished(); | ||||
|  | ||||
| private: | ||||
|     int id; | ||||
|     QString cmd; | ||||
|     QVariantMap *params; | ||||
| }; | ||||
|  | ||||
| #endif // CDPCOMMAND_H | ||||
							
								
								
									
										85
									
								
								GPClient/cdpcommandmanager.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								GPClient/cdpcommandmanager.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,85 @@ | ||||
| #include "cdpcommandmanager.h" | ||||
| #include <QVariantMap> | ||||
|  | ||||
| CDPCommandManager::CDPCommandManager(QObject *parent) | ||||
|     : QObject(parent) | ||||
|     , networkManager(new QNetworkAccessManager) | ||||
|     , socket(new QWebSocket) | ||||
| { | ||||
|     // WebSocket setup | ||||
|     QObject::connect(socket, &QWebSocket::connected, this, &CDPCommandManager::ready); | ||||
|     QObject::connect(socket, &QWebSocket::textMessageReceived, this, &CDPCommandManager::onTextMessageReceived); | ||||
|     QObject::connect(socket, &QWebSocket::disconnected, this, &CDPCommandManager::onSocketDisconnected); | ||||
|     QObject::connect(socket, QOverload<QAbstractSocket::SocketError>::of(&QWebSocket::error), this, &CDPCommandManager::onSocketError); | ||||
| } | ||||
|  | ||||
| CDPCommandManager::~CDPCommandManager() | ||||
| { | ||||
|     delete networkManager; | ||||
|     delete socket; | ||||
| } | ||||
|  | ||||
| void CDPCommandManager::initialize(QString endpoint) | ||||
| { | ||||
|     QNetworkReply *reply = networkManager->get(QNetworkRequest(endpoint)); | ||||
|  | ||||
|     QObject::connect( | ||||
|         reply, &QNetworkReply::finished, | ||||
|         [reply, this]() { | ||||
|             if (reply->error()) { | ||||
|                 qDebug() << "CDP request error"; | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             QJsonDocument doc = QJsonDocument::fromJson(reply->readAll()); | ||||
|             QJsonArray pages = doc.array(); | ||||
|             QJsonObject page = pages.first().toObject(); | ||||
|             QString wsUrl = page.value("webSocketDebuggerUrl").toString(); | ||||
|  | ||||
|             socket->open(wsUrl); | ||||
|         } | ||||
|     ); | ||||
| } | ||||
|  | ||||
| CDPCommand *CDPCommandManager::sendCommand(QString cmd) | ||||
| { | ||||
|     QVariantMap emptyParams; | ||||
|     return sendCommend(cmd, emptyParams); | ||||
| } | ||||
|  | ||||
| CDPCommand *CDPCommandManager::sendCommend(QString cmd, QVariantMap ¶ms) | ||||
| { | ||||
|     int id = ++commandId; | ||||
|     CDPCommand *command = new CDPCommand(id, cmd, params); | ||||
|     socket->sendTextMessage(command->toJson()); | ||||
|     commandPool.insert(id, command); | ||||
|  | ||||
|     return command; | ||||
| } | ||||
|  | ||||
| void CDPCommandManager::onTextMessageReceived(QString message) | ||||
| { | ||||
|     QJsonDocument responseDoc = QJsonDocument::fromJson(message.toUtf8()); | ||||
|     QJsonObject response = responseDoc.object(); | ||||
|  | ||||
|     // Response for method | ||||
|     if (response.contains("id")) { | ||||
|         int id = response.value("id").toInt(); | ||||
|         if (commandPool.contains(id)) { | ||||
|             CDPCommand *command = commandPool.take(id); | ||||
|             command->finished(); | ||||
|         } | ||||
|     } else { // Response for event | ||||
|         emit eventReceived(response.value("method").toString(), response.value("params").toObject()); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void CDPCommandManager::onSocketDisconnected() | ||||
| { | ||||
|     qDebug() << "WebSocket disconnected"; | ||||
| } | ||||
|  | ||||
| void CDPCommandManager::onSocketError(QAbstractSocket::SocketError error) | ||||
| { | ||||
|     qDebug() << "WebSocket error" << error; | ||||
| } | ||||
							
								
								
									
										39
									
								
								GPClient/cdpcommandmanager.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								GPClient/cdpcommandmanager.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| #ifndef CDPCOMMANDMANAGER_H | ||||
| #define CDPCOMMANDMANAGER_H | ||||
|  | ||||
| #include "cdpcommand.h" | ||||
| #include <QObject> | ||||
| #include <QHash> | ||||
| #include <QtWebSockets> | ||||
| #include <QNetworkAccessManager> | ||||
|  | ||||
| class CDPCommandManager : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit CDPCommandManager(QObject *parent = nullptr); | ||||
|     ~CDPCommandManager(); | ||||
|  | ||||
|     void initialize(QString endpoint); | ||||
|  | ||||
|     CDPCommand *sendCommand(QString cmd); | ||||
|     CDPCommand *sendCommend(QString cmd, QVariantMap& params); | ||||
|  | ||||
| signals: | ||||
|     void ready(); | ||||
|     void eventReceived(QString eventName, QJsonObject params); | ||||
|  | ||||
| private: | ||||
|     QNetworkAccessManager *networkManager; | ||||
|     QWebSocket *socket; | ||||
|  | ||||
|     int commandId = 0; | ||||
|     QHash<int, CDPCommand*> commandPool; | ||||
|  | ||||
| private slots: | ||||
|     void onTextMessageReceived(QString message); | ||||
|     void onSocketDisconnected(); | ||||
|     void onSocketError(QAbstractSocket::SocketError error); | ||||
| }; | ||||
|  | ||||
| #endif // CDPCOMMANDMANAGER_H | ||||
							
								
								
									
										37
									
								
								GPClient/enhancedwebview.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								GPClient/enhancedwebview.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| #include "enhancedwebview.h" | ||||
| #include "cdpcommandmanager.h" | ||||
|  | ||||
| #include <QtWebEngineWidgets/QWebEngineView> | ||||
| #include <QProcessEnvironment> | ||||
|  | ||||
| EnhancedWebView::EnhancedWebView(QWidget *parent) | ||||
|     : QWebEngineView(parent) | ||||
|     , cdp(new CDPCommandManager) | ||||
| { | ||||
|     QObject::connect(cdp, &CDPCommandManager::ready, this, &EnhancedWebView::onCDPReady); | ||||
|     QObject::connect(cdp, &CDPCommandManager::eventReceived, this, &EnhancedWebView::onEventReceived); | ||||
| } | ||||
|  | ||||
| EnhancedWebView::~EnhancedWebView() | ||||
| { | ||||
|     delete cdp; | ||||
| } | ||||
|  | ||||
| void EnhancedWebView::initialize() | ||||
| { | ||||
|     QString port = QProcessEnvironment::systemEnvironment().value("QTWEBENGINE_REMOTE_DEBUGGING"); | ||||
|     qDebug() << "port:" << port; | ||||
|     cdp->initialize("http://127.0.0.1:" + port + "/json"); | ||||
| } | ||||
|  | ||||
| void EnhancedWebView::onCDPReady() | ||||
| { | ||||
|     cdp->sendCommand("Network.enable"); | ||||
| } | ||||
|  | ||||
| void EnhancedWebView::onEventReceived(QString eventName, QJsonObject params) | ||||
| { | ||||
|     if (eventName == "Network.responseReceived") { | ||||
|         emit responseReceived(params); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										28
									
								
								GPClient/enhancedwebview.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								GPClient/enhancedwebview.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| #ifndef ENHANCEDWEBVIEW_H | ||||
| #define ENHANCEDWEBVIEW_H | ||||
|  | ||||
| #include "cdpcommandmanager.h" | ||||
|  | ||||
| #include <QtWebEngineWidgets/QWebEngineView> | ||||
|  | ||||
| class EnhancedWebView : public QWebEngineView | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     explicit EnhancedWebView(QWidget *parent = nullptr); | ||||
|     ~EnhancedWebView(); | ||||
|  | ||||
|     void initialize(); | ||||
|  | ||||
| signals: | ||||
|     void responseReceived(QJsonObject params); | ||||
|  | ||||
| private slots: | ||||
|     void onCDPReady(); | ||||
|     void onEventReceived(QString eventName, QJsonObject params); | ||||
|  | ||||
| private: | ||||
|     CDPCommandManager *cdp; | ||||
| }; | ||||
|  | ||||
| #endif // ENHANCEDWEBVIEW_H | ||||
							
								
								
									
										155
									
								
								GPClient/gpclient.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								GPClient/gpclient.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| #include "gpclient.h" | ||||
| #include "ui_gpclient.h" | ||||
| #include "samlloginwindow.h" | ||||
|  | ||||
| GPClient::GPClient(QWidget *parent) | ||||
|     : QMainWindow(parent) | ||||
|     , ui(new Ui::GPClient) | ||||
| { | ||||
|     ui->setupUi(this); | ||||
|  | ||||
|     QObject::connect(this, &GPClient::connectFailed, [this]() { | ||||
|         ui->connectButton->setDisabled(false); | ||||
|         ui->connectButton->setText("Connect"); | ||||
|     }); | ||||
|  | ||||
|     // QNetworkAccessManager setup | ||||
|     networkManager = new QNetworkAccessManager(this); | ||||
|  | ||||
|     // Login window setup | ||||
|     loginWindow = new SAMLLoginWindow(this); | ||||
|     QObject::connect(loginWindow, &SAMLLoginWindow::success, this, &GPClient::onLoginSuccess); | ||||
|     QObject::connect(loginWindow, &SAMLLoginWindow::rejected, this, &GPClient::connectFailed); | ||||
|  | ||||
|     // DBus service setup | ||||
|     vpn = new com::yuezk::qt::GPService("com.yuezk.qt.GPService", "/", QDBusConnection::systemBus(), this); | ||||
|     QObject::connect(vpn, &com::yuezk::qt::GPService::connected, this, &GPClient::onVPNConnected); | ||||
|     QObject::connect(vpn, &com::yuezk::qt::GPService::disconnected, this, &GPClient::onVPNDisconnected); | ||||
|     QObject::connect(vpn, &com::yuezk::qt::GPService::logAvailable, this, &GPClient::onVPNLogAvailable); | ||||
| } | ||||
|  | ||||
| GPClient::~GPClient() | ||||
| { | ||||
|     delete ui; | ||||
|     delete networkManager; | ||||
|     delete reply; | ||||
|     delete loginWindow; | ||||
|     delete vpn; | ||||
| } | ||||
|  | ||||
| void GPClient::on_connectButton_clicked() | ||||
| { | ||||
|     if (ui->connectButton->text() == "Connect") { | ||||
|         QString portal = ui->portalInput->text(); | ||||
|  | ||||
|         ui->connectButton->setDisabled(true); | ||||
|         ui->connectButton->setText("Connecting..."); | ||||
|         samlLogin(portal); | ||||
|     } else { | ||||
|         ui->connectButton->setDisabled(true); | ||||
|         ui->connectButton->setText("Disconnecting..."); | ||||
|  | ||||
|         vpn->disconnect(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void GPClient::preloginResultFinished() | ||||
| { | ||||
|     if (reply->error()) { | ||||
|         qDebug() << "request error"; | ||||
|         emit connectFailed(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     QByteArray bytes = reply->readAll(); | ||||
|     qDebug("response is: %s", bytes.toStdString().c_str()); | ||||
|  | ||||
|     const QString tagMethod = "saml-auth-method"; | ||||
|     const QString tagRequest = "saml-request"; | ||||
|     QString samlMethod; | ||||
|     QString samlRequest; | ||||
|  | ||||
|     QXmlStreamReader xml(bytes); | ||||
|     while (!xml.atEnd()) { | ||||
|         xml.readNext(); | ||||
|         if (xml.tokenType() == xml.StartElement) { | ||||
|             if (xml.name() == tagMethod) { | ||||
|                 samlMethod = xml.readElementText(); | ||||
|             } else if (xml.name() == tagRequest) { | ||||
|                 samlRequest = QByteArray::fromBase64(QByteArray::fromStdString(xml.readElementText().toStdString())); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (samlMethod == nullptr || samlRequest == nullptr) { | ||||
|         qCritical("This does not appear to be a SAML prelogin response (<saml-auth-method> or <saml-request> tags missing)"); | ||||
|         emit connectFailed(); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (samlMethod == "POST") { | ||||
|         // TODO | ||||
|         qInfo("TODO: SAML method is POST"); | ||||
|         emit connectFailed(); | ||||
|     } else if (samlMethod == "REDIRECT") { | ||||
|         qInfo() << "Request URL is: %s" << samlRequest; | ||||
|  | ||||
|         loginWindow->login(samlRequest); | ||||
|         loginWindow->exec(); | ||||
|     } | ||||
|     delete reply; | ||||
| } | ||||
|  | ||||
| void GPClient::onLoginSuccess(QJsonObject loginResult) | ||||
| { | ||||
|     qDebug() << "Login success:" << loginResult; | ||||
|  | ||||
|     QString fullpath = "/ssl-vpn/login.esp"; | ||||
|     QString shortpath = "gateway"; | ||||
|     QString user = loginResult.value("saml-username").toString(); | ||||
|     QString cookieName; | ||||
|     QString cookieValue; | ||||
|     QString cookies[]{"prelogin-cookie", "portal-userauthcookie"}; | ||||
|  | ||||
|     for (int i = 0; i < cookies->length(); i++) { | ||||
|         cookieValue = loginResult.value(cookies[i]).toString(); | ||||
|         if (cookieValue != nullptr) { | ||||
|             cookieName = cookies[i]; | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     QString host = QString("https://%1/%2:%3").arg(loginResult.value("server").toString(), shortpath, cookieName); | ||||
|     qDebug() << "Server:" << host << ", User:" << user << "Cookie:" << cookieValue; | ||||
|     qDebug() << "openconnect --protocol=gp -u" << user << "--passwd-on-stdin" << host; | ||||
|  | ||||
|     vpn->connect(host, user, cookieValue); | ||||
| } | ||||
|  | ||||
| void GPClient::onVPNConnected() | ||||
| { | ||||
|     qDebug() << "VPN connected"; | ||||
|     ui->connectButton->setDisabled(false); | ||||
|     ui->connectButton->setText("Disconnect"); | ||||
| } | ||||
|  | ||||
| void GPClient::onVPNDisconnected() | ||||
| { | ||||
|     qDebug() << "VPN disconnected"; | ||||
|     ui->connectButton->setDisabled(false); | ||||
|     ui->connectButton->setText("Connect"); | ||||
| } | ||||
|  | ||||
| void GPClient::onVPNLogAvailable(QString log) | ||||
| { | ||||
|     qDebug() << log; | ||||
| } | ||||
|  | ||||
| void GPClient::samlLogin(const QString portal) | ||||
| { | ||||
|     const QString preloginUrl = "https://" + portal + "/ssl-vpn/prelogin.esp"; | ||||
|     qDebug("%s", preloginUrl.toStdString().c_str()); | ||||
|  | ||||
|     reply = networkManager->post(QNetworkRequest(preloginUrl), (QByteArray) nullptr); | ||||
|     connect(reply, &QNetworkReply::finished, this, &GPClient::preloginResultFinished); | ||||
| } | ||||
							
								
								
									
										44
									
								
								GPClient/gpclient.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								GPClient/gpclient.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| #ifndef GPCLIENT_H | ||||
| #define GPCLIENT_H | ||||
|  | ||||
| #include "gpservice_interface.h" | ||||
| #include "samlloginwindow.h" | ||||
| #include <QMainWindow> | ||||
| #include <QNetworkAccessManager> | ||||
| #include <QNetworkReply> | ||||
|  | ||||
| QT_BEGIN_NAMESPACE | ||||
| namespace Ui { class GPClient; } | ||||
| QT_END_NAMESPACE | ||||
|  | ||||
| class GPClient : public QMainWindow | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     GPClient(QWidget *parent = nullptr); | ||||
|     ~GPClient(); | ||||
|  | ||||
| signals: | ||||
|     void connectFailed(); | ||||
|  | ||||
| private slots: | ||||
|     void on_connectButton_clicked(); | ||||
|     void preloginResultFinished(); | ||||
|  | ||||
|     void onLoginSuccess(QJsonObject loginResult); | ||||
|  | ||||
|     void onVPNConnected(); | ||||
|     void onVPNDisconnected(); | ||||
|     void onVPNLogAvailable(QString log); | ||||
|  | ||||
| private: | ||||
|     Ui::GPClient *ui; | ||||
|     SAMLLoginWindow *loginWindow; | ||||
|     QNetworkAccessManager *networkManager; | ||||
|     QNetworkReply *reply; | ||||
|     com::yuezk::qt::GPService *vpn; | ||||
|  | ||||
|     void samlLogin(const QString portal); | ||||
| }; | ||||
| #endif // GPCLIENT_H | ||||
							
								
								
									
										82
									
								
								GPClient/gpclient.ui
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								GPClient/gpclient.ui
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| <?xml version="1.0" encoding="UTF-8"?> | ||||
| <ui version="4.0"> | ||||
|  <class>GPClient</class> | ||||
|  <widget class="QMainWindow" name="GPClient"> | ||||
|   <property name="geometry"> | ||||
|    <rect> | ||||
|     <x>0</x> | ||||
|     <y>0</y> | ||||
|     <width>258</width> | ||||
|     <height>316</height> | ||||
|    </rect> | ||||
|   </property> | ||||
|   <property name="windowTitle"> | ||||
|    <string>GPClient</string> | ||||
|   </property> | ||||
|   <widget class="QWidget" name="centralwidget"> | ||||
|    <property name="sizePolicy"> | ||||
|     <sizepolicy hsizetype="Preferred" vsizetype="Preferred"> | ||||
|      <horstretch>0</horstretch> | ||||
|      <verstretch>0</verstretch> | ||||
|     </sizepolicy> | ||||
|    </property> | ||||
|    <property name="layoutDirection"> | ||||
|     <enum>Qt::LeftToRight</enum> | ||||
|    </property> | ||||
|    <layout class="QVBoxLayout" name="verticalLayout_3" stretch="1,0"> | ||||
|     <property name="leftMargin"> | ||||
|      <number>15</number> | ||||
|     </property> | ||||
|     <property name="topMargin"> | ||||
|      <number>15</number> | ||||
|     </property> | ||||
|     <property name="rightMargin"> | ||||
|      <number>15</number> | ||||
|     </property> | ||||
|     <property name="bottomMargin"> | ||||
|      <number>15</number> | ||||
|     </property> | ||||
|     <item> | ||||
|      <layout class="QVBoxLayout" name="verticalLayout" stretch="0"> | ||||
|       <item> | ||||
|        <widget class="QLabel" name="label"> | ||||
|         <property name="text"> | ||||
|          <string>TextLabel</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|     <item> | ||||
|      <layout class="QVBoxLayout" name="verticalLayout_2"> | ||||
|       <property name="bottomMargin"> | ||||
|        <number>0</number> | ||||
|       </property> | ||||
|       <item> | ||||
|        <widget class="QLineEdit" name="portalInput"> | ||||
|         <property name="text"> | ||||
|          <string>vpn.microstrategy.com</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|       <item> | ||||
|        <widget class="QPushButton" name="connectButton"> | ||||
|         <property name="sizePolicy"> | ||||
|          <sizepolicy hsizetype="Expanding" vsizetype="Fixed"> | ||||
|           <horstretch>0</horstretch> | ||||
|           <verstretch>0</verstretch> | ||||
|          </sizepolicy> | ||||
|         </property> | ||||
|         <property name="text"> | ||||
|          <string>Connect</string> | ||||
|         </property> | ||||
|        </widget> | ||||
|       </item> | ||||
|      </layout> | ||||
|     </item> | ||||
|    </layout> | ||||
|   </widget> | ||||
|  </widget> | ||||
|  <resources/> | ||||
|  <connections/> | ||||
| </ui> | ||||
							
								
								
									
										25
									
								
								GPClient/gpservice_interface.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								GPClient/gpservice_interface.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| /* | ||||
|  * This file was generated by qdbusxml2cpp version 0.8 | ||||
|  * Command line was: qdbusxml2cpp -i gpservice_interface.h -p :gpservice_interface.cpp ../GPService/gpservice.xml | ||||
|  * | ||||
|  * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. | ||||
|  * | ||||
|  * This is an auto-generated file. | ||||
|  * This file may have been hand-edited. Look for HAND-EDIT comments | ||||
|  * before re-generating it. | ||||
|  */ | ||||
|  | ||||
| #include "gpservice_interface.h" | ||||
| /* | ||||
|  * Implementation of interface class ComYuezkQtGPServiceInterface | ||||
|  */ | ||||
|  | ||||
| ComYuezkQtGPServiceInterface::ComYuezkQtGPServiceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent) | ||||
|     : QDBusAbstractInterface(service, path, staticInterfaceName(), connection, parent) | ||||
| { | ||||
| } | ||||
|  | ||||
| ComYuezkQtGPServiceInterface::~ComYuezkQtGPServiceInterface() | ||||
| { | ||||
| } | ||||
|  | ||||
							
								
								
									
										71
									
								
								GPClient/gpservice_interface.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								GPClient/gpservice_interface.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| /* | ||||
|  * This file was generated by qdbusxml2cpp version 0.8 | ||||
|  * Command line was: qdbusxml2cpp -p gpservice_interface.h: ../GPService/gpservice.xml | ||||
|  * | ||||
|  * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. | ||||
|  * | ||||
|  * This is an auto-generated file. | ||||
|  * Do not edit! All changes made to it will be lost. | ||||
|  */ | ||||
|  | ||||
| #ifndef GPSERVICE_INTERFACE_H | ||||
| #define GPSERVICE_INTERFACE_H | ||||
|  | ||||
| #include <QtCore/QObject> | ||||
| #include <QtCore/QByteArray> | ||||
| #include <QtCore/QList> | ||||
| #include <QtCore/QMap> | ||||
| #include <QtCore/QString> | ||||
| #include <QtCore/QStringList> | ||||
| #include <QtCore/QVariant> | ||||
| #include <QtDBus/QtDBus> | ||||
|  | ||||
| /* | ||||
|  * Proxy class for interface com.yuezk.qt.GPService | ||||
|  */ | ||||
| class ComYuezkQtGPServiceInterface: public QDBusAbstractInterface | ||||
| { | ||||
|     Q_OBJECT | ||||
| public: | ||||
|     static inline const char *staticInterfaceName() | ||||
|     { return "com.yuezk.qt.GPService"; } | ||||
|  | ||||
| public: | ||||
|     ComYuezkQtGPServiceInterface(const QString &service, const QString &path, const QDBusConnection &connection, QObject *parent = nullptr); | ||||
|  | ||||
|     ~ComYuezkQtGPServiceInterface(); | ||||
|  | ||||
| public Q_SLOTS: // METHODS | ||||
|     inline QDBusPendingReply<> connect(const QString &server, const QString &username, const QString &passwd) | ||||
|     { | ||||
|         QList<QVariant> argumentList; | ||||
|         argumentList << QVariant::fromValue(server) << QVariant::fromValue(username) << QVariant::fromValue(passwd); | ||||
|         return asyncCallWithArgumentList(QStringLiteral("connect"), argumentList); | ||||
|     } | ||||
|  | ||||
|     inline QDBusPendingReply<> disconnect() | ||||
|     { | ||||
|         QList<QVariant> argumentList; | ||||
|         return asyncCallWithArgumentList(QStringLiteral("disconnect"), argumentList); | ||||
|     } | ||||
|  | ||||
|     inline QDBusPendingReply<int> status() | ||||
|     { | ||||
|         QList<QVariant> argumentList; | ||||
|         return asyncCallWithArgumentList(QStringLiteral("status"), argumentList); | ||||
|     } | ||||
|  | ||||
| Q_SIGNALS: // SIGNALS | ||||
|     void connected(); | ||||
|     void disconnected(); | ||||
|     void logAvailable(const QString &log); | ||||
| }; | ||||
|  | ||||
| namespace com { | ||||
|   namespace yuezk { | ||||
|     namespace qt { | ||||
|       typedef ::ComYuezkQtGPServiceInterface GPService; | ||||
|     } | ||||
|   } | ||||
| } | ||||
| #endif | ||||
							
								
								
									
										11
									
								
								GPClient/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								GPClient/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| #include "gpclient.h" | ||||
|  | ||||
| #include <QApplication> | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|     QApplication a(argc, argv); | ||||
|     GPClient w; | ||||
|     w.show(); | ||||
|     return a.exec(); | ||||
| } | ||||
							
								
								
									
										59
									
								
								GPClient/samlloginwindow.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								GPClient/samlloginwindow.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,59 @@ | ||||
| #include "samlloginwindow.h" | ||||
|  | ||||
| #include <QVBoxLayout> | ||||
|  | ||||
| SAMLLoginWindow::SAMLLoginWindow(QWidget *parent) | ||||
|     : QDialog(parent) | ||||
| { | ||||
|     setWindowTitle("SAML Login"); | ||||
|     resize(610, 406); | ||||
|     QVBoxLayout *verticalLayout = new QVBoxLayout(this); | ||||
|     webView = new EnhancedWebView(this); | ||||
|     webView->setUrl(QUrl("about:blank")); | ||||
|     verticalLayout->addWidget(webView); | ||||
|  | ||||
|     webView->initialize(); | ||||
|     QObject::connect(webView, &EnhancedWebView::responseReceived, this, &SAMLLoginWindow::onResponseReceived); | ||||
| } | ||||
|  | ||||
| SAMLLoginWindow::~SAMLLoginWindow() | ||||
| { | ||||
|     delete webView; | ||||
| } | ||||
|  | ||||
| void SAMLLoginWindow::closeEvent(QCloseEvent *event) | ||||
| { | ||||
|     event->accept(); | ||||
|     reject(); | ||||
| } | ||||
|  | ||||
| void SAMLLoginWindow::login(QString url) | ||||
| { | ||||
|     webView->load(QUrl(url)); | ||||
| } | ||||
|  | ||||
| void SAMLLoginWindow::onResponseReceived(QJsonObject params) | ||||
| { | ||||
|     QString type = params.value("type").toString(); | ||||
|     // Skip non-document response | ||||
|     if (type != "Document") { | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     QJsonObject response = params.value("response").toObject(); | ||||
|     QJsonObject headers = response.value("headers").toObject(); | ||||
|  | ||||
|     foreach (const QString& key, headers.keys()) { | ||||
|         if (key.startsWith("saml-") || key == "prelogin-cookie" || key == "portal-userauthcookie") { | ||||
|             samlResult.insert(key, headers.value(key)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Check the SAML result | ||||
|     if (samlResult.contains("saml-username") | ||||
|             && (samlResult.contains("prelogin-cookie") || samlResult.contains("portal-userauthcookie"))) { | ||||
|         samlResult.insert("server", QUrl(response.value("url").toString()).authority()); | ||||
|         emit success(samlResult); | ||||
|         accept(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										33
									
								
								GPClient/samlloginwindow.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								GPClient/samlloginwindow.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,33 @@ | ||||
| #ifndef SAMLLOGINWINDOW_H | ||||
| #define SAMLLOGINWINDOW_H | ||||
|  | ||||
| #include "enhancedwebview.h" | ||||
|  | ||||
| #include <QDialog> | ||||
| #include <QJsonObject> | ||||
| #include <QCloseEvent> | ||||
|  | ||||
| class SAMLLoginWindow : public QDialog | ||||
| { | ||||
|     Q_OBJECT | ||||
|  | ||||
| public: | ||||
|     explicit SAMLLoginWindow(QWidget *parent = nullptr); | ||||
|     ~SAMLLoginWindow(); | ||||
|  | ||||
|     void login(QString url); | ||||
|  | ||||
| signals: | ||||
|     void success(QJsonObject samlResult); | ||||
|  | ||||
| private slots: | ||||
|     void onResponseReceived(QJsonObject params); | ||||
|  | ||||
| private: | ||||
|     EnhancedWebView *webView; | ||||
|     QJsonObject samlResult; | ||||
|  | ||||
|     void closeEvent(QCloseEvent *event); | ||||
| }; | ||||
|  | ||||
| #endif // SAMLLOGINWINDOW_H | ||||
							
								
								
									
										21
									
								
								GPService/.qmake.stash
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								GPService/.qmake.stash
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| QMAKE_CXX.QT_COMPILER_STDCXX = 201402L | ||||
| QMAKE_CXX.QMAKE_GCC_MAJOR_VERSION = 9 | ||||
| QMAKE_CXX.QMAKE_GCC_MINOR_VERSION = 2 | ||||
| QMAKE_CXX.QMAKE_GCC_PATCH_VERSION = 0 | ||||
| QMAKE_CXX.COMPILER_MACROS = \ | ||||
|     QT_COMPILER_STDCXX \ | ||||
|     QMAKE_GCC_MAJOR_VERSION \ | ||||
|     QMAKE_GCC_MINOR_VERSION \ | ||||
|     QMAKE_GCC_PATCH_VERSION | ||||
| QMAKE_CXX.INCDIRS = \ | ||||
|     /usr/include/c++/9.2.0 \ | ||||
|     /usr/include/c++/9.2.0/x86_64-pc-linux-gnu \ | ||||
|     /usr/include/c++/9.2.0/backward \ | ||||
|     /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include \ | ||||
|     /usr/local/include \ | ||||
|     /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0/include-fixed \ | ||||
|     /usr/include | ||||
| QMAKE_CXX.LIBDIRS = \ | ||||
|     /usr/lib/gcc/x86_64-pc-linux-gnu/9.2.0 \ | ||||
|     /usr/lib \ | ||||
|     /lib | ||||
							
								
								
									
										
											BIN
										
									
								
								GPService/GPService
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								GPService/GPService
									
									
									
									
									
										Executable file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										30
									
								
								GPService/GPService.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								GPService/GPService.pro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,30 @@ | ||||
| QT += dbus | ||||
| QT -= gui | ||||
|  | ||||
| CONFIG += c++11 console | ||||
| CONFIG -= app_bundle | ||||
|  | ||||
| # The following define makes your compiler emit warnings if you use | ||||
| # any Qt feature that has been marked deprecated (the exact warnings | ||||
| # depend on your compiler). Please consult the documentation of the | ||||
| # deprecated API in order to know how to port your code away from it. | ||||
| DEFINES += QT_DEPRECATED_WARNINGS | ||||
|  | ||||
| # You can also make your code fail to compile if it uses deprecated APIs. | ||||
| # In order to do so, uncomment the following line. | ||||
| # You can also select to disable deprecated APIs only up to a certain version of Qt. | ||||
| #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0 | ||||
|  | ||||
| HEADERS += \ | ||||
|     gpservice.h | ||||
|  | ||||
| SOURCES += \ | ||||
|         gpservice.cpp \ | ||||
|         main.cpp | ||||
|  | ||||
| DBUS_ADAPTORS += gpservice.xml | ||||
|  | ||||
| # Default rules for deployment. | ||||
| qnx: target.path = /tmp/$${TARGET}/bin | ||||
| else: unix:!android: target.path = /opt/$${TARGET}/bin | ||||
| !isEmpty(target.path): INSTALLS += target | ||||
							
								
								
									
										235
									
								
								GPService/gpservice.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										235
									
								
								GPService/gpservice.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,235 @@ | ||||
| #include "gpservice.h" | ||||
| #include "gpservice_adaptor.h" | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
| #include <fcntl.h> | ||||
| #include <signal.h> | ||||
| #include <sys/stat.h> | ||||
| #include <sys/wait.h> | ||||
| #include <sys/ioctl.h> | ||||
| #include <linux/if_tun.h> | ||||
| #include <net/if.h> | ||||
| #include <pwd.h> | ||||
| #include <grp.h> | ||||
|  | ||||
| #include <QFileInfo> | ||||
| #include <QDebug> | ||||
| #include <QtDBus> | ||||
| #include <QIODevice> | ||||
| #include <QProcess> | ||||
| #include <QDateTime> | ||||
| #include <QVariant> | ||||
|  | ||||
| struct { | ||||
|     uid_t tun_owner; | ||||
|     gid_t tun_group; | ||||
| } tun_user; | ||||
|  | ||||
| class SandboxProcess : public QProcess | ||||
| { | ||||
| protected: | ||||
|     void setupChildProcess() override; | ||||
| }; | ||||
|  | ||||
| void SandboxProcess::setupChildProcess() | ||||
| { | ||||
|     /*if (initgroups (NM_OPENCONNECT_USER, tun_user.tun_group) || | ||||
|             setgid (tun_user.tun_group) || | ||||
|             setuid (tun_user.tun_owner)) { | ||||
|         qDebug() << "Failed to drop privileges when spawning openconnect"; | ||||
|     }*/ | ||||
| } | ||||
|  | ||||
| GPService::GPService(QObject *parent) | ||||
|     : QObject(parent) | ||||
|     , openconnect(new SandboxProcess) | ||||
| { | ||||
|     new GPServiceAdaptor(this); | ||||
|     QDBusConnection dbus = QDBusConnection::systemBus(); | ||||
|     dbus.registerObject("/", this); | ||||
|     dbus.registerService("com.yuezk.qt.GPService"); | ||||
| } | ||||
|  | ||||
| void GPService::connect(QString server, QString username, QString passwd) | ||||
| { | ||||
|     qDebug() << server << username << passwd; | ||||
|  | ||||
|     if (status() != QProcess::NotRunning) { | ||||
|         log("Openconnect has already started on PID " + QString::number(openconnect->processId()) + ", nothing changed."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     QString bin = findBinary(); | ||||
|  | ||||
|     if (bin == nullptr) { | ||||
|         log("Could not found openconnect binary, make sure openconnect is installed, exiting."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     char *tunName = "tun0"; // createPersistentTundev(); | ||||
|     // Failed to create device | ||||
|     if (tunName == nullptr) { | ||||
|         log("Could not create tun, exiting."); | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     qDebug() << tunName; | ||||
|  | ||||
|     // openconnect --protocol=gp -i vpn0 -s 'sudo -E /etc/vpnc/vpnc-script' -u "zyue@microstrategy.com" --passwd-on-stdin "https://vpn.microstrategy.com/gateway:prelogin-cookie" | ||||
|     QStringList args; | ||||
|     args << "--protocol=gp" | ||||
|         // << "-i" << tunName | ||||
|         // << "-s" << "sudo -E /etc/vpnc/vpnc-script" | ||||
|         // << "-U" << NM_OPENCONNECT_USER | ||||
|      << "-u" << username | ||||
|      << "--passwd-on-stdin" | ||||
|      << server; | ||||
|  | ||||
|     openconnect->start(bin, args); | ||||
|     openconnect->write(passwd.toUtf8()); | ||||
|     openconnect->closeWriteChannel(); | ||||
|  | ||||
|     QObject::connect(openconnect, &QProcess::started, [this]() { | ||||
|         log("Openconnect started successfully, PID=" + QString::number(openconnect->processId())); | ||||
|     }); | ||||
|  | ||||
|     QObject::connect(openconnect, &QProcess::errorOccurred, [tunName, this](QProcess::ProcessError error) { | ||||
|         log("Error occurred: Openconnect started failed"); | ||||
|         destroyPersistentTundev(tunName); | ||||
|         emit disconnected(); | ||||
|     }); | ||||
|  | ||||
|     QObject::connect(openconnect, &QProcess::readyReadStandardOutput, [this] () { | ||||
|         QString output = openconnect->readAllStandardOutput(); | ||||
|  | ||||
|         log(output); | ||||
|         if (output.startsWith("Connected as")) { | ||||
|             emit connected(); | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     QObject::connect(openconnect, &QProcess::readyReadStandardError, [this] () { | ||||
|         log(openconnect->readAllStandardError()); | ||||
|     }); | ||||
|  | ||||
|     QObject::connect(openconnect, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), [tunName, this](int exitCode, QProcess::ExitStatus exitStatus) { | ||||
|         log("Openconnect process exited with code " + QString::number(exitCode) + " and exit status " + QVariant::fromValue(exitStatus).toString()); | ||||
|         destroyPersistentTundev(tunName); | ||||
|         emit disconnected(); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| void GPService::disconnect() | ||||
| { | ||||
|     if (openconnect->state() != QProcess::NotRunning) { | ||||
|         openconnect->terminate(); | ||||
|     } | ||||
| } | ||||
|  | ||||
| int GPService::status() | ||||
| { | ||||
|     return openconnect->state(); | ||||
| } | ||||
|  | ||||
| void GPService::log(QString msg) | ||||
| { | ||||
|     // 2020-02-12 15:33:45.120: log messsage | ||||
|     QString record = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss.zzz") + ": " + msg; | ||||
|     qDebug() << record; | ||||
|     emit logAvailable(record); | ||||
| } | ||||
|  | ||||
| QString GPService::findBinary() | ||||
| { | ||||
|     for (int i = 0; i < binaryPaths->length(); i++) { | ||||
|         if (QFileInfo::exists(binaryPaths[i])) { | ||||
|             return binaryPaths[i]; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return nullptr; | ||||
| } | ||||
|  | ||||
| char *GPService::createPersistentTundev() | ||||
| { | ||||
|     struct passwd *pw; | ||||
|     struct ifreq ifr; | ||||
|     int fd; | ||||
|     int i; | ||||
|  | ||||
|     pw = getpwnam(NM_OPENCONNECT_USER); | ||||
|     if (!pw) | ||||
|         return nullptr; | ||||
|  | ||||
|     tun_user.tun_owner = pw->pw_uid; | ||||
|     tun_user.tun_group = pw->pw_gid; | ||||
|  | ||||
|     fd = open("/dev/net/tun", O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         qDebug("Failed to open /dev/net/tun"); | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     memset(&ifr, 0, sizeof(ifr)); | ||||
|     ifr.ifr_flags = IFF_TUN | IFF_NO_PI; | ||||
|  | ||||
|     for (i = 0; i < 256; i++) { | ||||
|         sprintf(ifr.ifr_name, "gpvpn%d", i); | ||||
|  | ||||
|         int retcode = ioctl(fd, TUNSETIFF, (void *)&ifr); | ||||
|  | ||||
|         if (!retcode) { | ||||
|             break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (i == 256) { | ||||
|         qDebug("Failed to create tun"); | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     if (ioctl(fd, TUNSETOWNER, tun_user.tun_owner) < 0) { | ||||
|         qDebug("TUNSETOWNER"); | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     if (ioctl(fd, TUNSETPERSIST, 1)) { | ||||
|         qDebug("TUNSETPERSIST"); | ||||
|         return nullptr; | ||||
|     } | ||||
|     close(fd); | ||||
|     qDebug("Created tundev %s\n", ifr.ifr_name); | ||||
|     return strdup(ifr.ifr_name); | ||||
| } | ||||
|  | ||||
| void GPService::destroyPersistentTundev(char *tun_name) | ||||
| { | ||||
|     struct ifreq ifr; | ||||
|     int fd; | ||||
|  | ||||
|     fd = open("/dev/net/tun", O_RDWR); | ||||
|     if (fd < 0) { | ||||
|         qDebug() << "Failed to open /dev/net/tun"; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     memset(&ifr, 0, sizeof(ifr)); | ||||
|     ifr.ifr_flags = IFF_TUN | IFF_NO_PI; | ||||
|     strcpy(ifr.ifr_name, tun_name); | ||||
|  | ||||
|     if (ioctl(fd, TUNSETIFF, (void *)&ifr) < 0) { | ||||
|         qDebug() << "TUNSETIFF"; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     if (ioctl(fd, TUNSETPERSIST, 0)) { | ||||
|         qDebug() << "TUNSETPERSIST"; | ||||
|         return; | ||||
|     } | ||||
|  | ||||
|     qDebug() << "Destroyed  tundev %s\n" << tun_name; | ||||
|     close(fd); | ||||
| } | ||||
							
								
								
									
										44
									
								
								GPService/gpservice.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								GPService/gpservice.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| #ifndef GLOBALPROTECTSERVICE_H | ||||
| #define GLOBALPROTECTSERVICE_H | ||||
|  | ||||
| #include <QObject> | ||||
| #include <QProcess> | ||||
|  | ||||
| #define NM_OPENCONNECT_USER "nm-openconnect" | ||||
|  | ||||
| static const QString binaryPaths[] { | ||||
|     "/usr/bin/openconnect", | ||||
|     "/usr/sbin/openconnect", | ||||
|     "/usr/local/bin/openconnect", | ||||
|     "/usr/local/sbin/openconnect", | ||||
|     "/opt/bin/openconnect", | ||||
|     "/opt/sbin/openconnect" | ||||
| }; | ||||
|  | ||||
| class GPService : public QObject | ||||
| { | ||||
|     Q_OBJECT | ||||
|     Q_CLASSINFO("D-Bus Interface", "com.yuezk.qt.GPService") | ||||
| public: | ||||
|     explicit GPService(QObject *parent = nullptr); | ||||
|  | ||||
| signals: | ||||
|     void connected(); | ||||
|     void disconnected(); | ||||
|     void logAvailable(QString log); | ||||
|  | ||||
| public slots: | ||||
|     void connect(QString server, QString username, QString passwd); | ||||
|     void disconnect(); | ||||
|     int status(); | ||||
|  | ||||
| private: | ||||
|     QProcess *openconnect; | ||||
|  | ||||
|     void log(QString msg); | ||||
|     static QString findBinary(); | ||||
|     static char *createPersistentTundev(); | ||||
|     static void destroyPersistentTundev(char *tun_name); | ||||
| }; | ||||
|  | ||||
| #endif // GLOBALPROTECTSERVICE_H | ||||
							
								
								
									
										22
									
								
								GPService/gpservice.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								GPService/gpservice.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> | ||||
| <node> | ||||
|   <interface name="com.yuezk.qt.GPService"> | ||||
|     <signal name="connected"> | ||||
|     </signal> | ||||
|     <signal name="disconnected"> | ||||
|     </signal> | ||||
|     <signal name="logAvailable"> | ||||
|       <arg name="log" type="s" /> | ||||
|     </signal> | ||||
|     <method name="connect"> | ||||
|       <arg name="server" type="s" direction="in"/> | ||||
|       <arg name="username" type="s" direction="in"/> | ||||
|       <arg name="passwd" type="s" direction="in"/> | ||||
|     </method> | ||||
|     <method name="disconnect"> | ||||
|     </method> | ||||
|     <method name="status"> | ||||
|       <arg type="i" direction="out"/> | ||||
|     </method> | ||||
|   </interface> | ||||
| </node> | ||||
							
								
								
									
										55
									
								
								GPService/gpservice_adaptor.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								GPService/gpservice_adaptor.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,55 @@ | ||||
| /* | ||||
|  * This file was generated by qdbusxml2cpp version 0.8 | ||||
|  * Command line was: qdbusxml2cpp -i gpservice_adaptor.h -a :gpservice_adaptor.cpp gpservice.xml | ||||
|  * | ||||
|  * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. | ||||
|  * | ||||
|  * This is an auto-generated file. | ||||
|  * Do not edit! All changes made to it will be lost. | ||||
|  */ | ||||
|  | ||||
| #include "gpservice_adaptor.h" | ||||
| #include <QtCore/QMetaObject> | ||||
| #include <QtCore/QByteArray> | ||||
| #include <QtCore/QList> | ||||
| #include <QtCore/QMap> | ||||
| #include <QtCore/QString> | ||||
| #include <QtCore/QStringList> | ||||
| #include <QtCore/QVariant> | ||||
|  | ||||
| /* | ||||
|  * Implementation of adaptor class GPServiceAdaptor | ||||
|  */ | ||||
|  | ||||
| GPServiceAdaptor::GPServiceAdaptor(QObject *parent) | ||||
|     : QDBusAbstractAdaptor(parent) | ||||
| { | ||||
|     // constructor | ||||
|     setAutoRelaySignals(true); | ||||
| } | ||||
|  | ||||
| GPServiceAdaptor::~GPServiceAdaptor() | ||||
| { | ||||
|     // destructor | ||||
| } | ||||
|  | ||||
| void GPServiceAdaptor::connect(const QString &server, const QString &username, const QString &passwd) | ||||
| { | ||||
|     // handle method call com.yuezk.qt.GPService.connect | ||||
|     QMetaObject::invokeMethod(parent(), "connect", Q_ARG(QString, server), Q_ARG(QString, username), Q_ARG(QString, passwd)); | ||||
| } | ||||
|  | ||||
| void GPServiceAdaptor::disconnect() | ||||
| { | ||||
|     // handle method call com.yuezk.qt.GPService.disconnect | ||||
|     QMetaObject::invokeMethod(parent(), "disconnect"); | ||||
| } | ||||
|  | ||||
| int GPServiceAdaptor::status() | ||||
| { | ||||
|     // handle method call com.yuezk.qt.GPService.status | ||||
|     int out0; | ||||
|     QMetaObject::invokeMethod(parent(), "status", Q_RETURN_ARG(int, out0)); | ||||
|     return out0; | ||||
| } | ||||
|  | ||||
							
								
								
									
										66
									
								
								GPService/gpservice_adaptor.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								GPService/gpservice_adaptor.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| /* | ||||
|  * This file was generated by qdbusxml2cpp version 0.8 | ||||
|  * Command line was: qdbusxml2cpp -a gpservice_adaptor.h: gpservice.xml | ||||
|  * | ||||
|  * qdbusxml2cpp is Copyright (C) 2020 The Qt Company Ltd. | ||||
|  * | ||||
|  * This is an auto-generated file. | ||||
|  * This file may have been hand-edited. Look for HAND-EDIT comments | ||||
|  * before re-generating it. | ||||
|  */ | ||||
|  | ||||
| #ifndef GPSERVICE_ADAPTOR_H | ||||
| #define GPSERVICE_ADAPTOR_H | ||||
|  | ||||
| #include <QtCore/QObject> | ||||
| #include <QtDBus/QtDBus> | ||||
| QT_BEGIN_NAMESPACE | ||||
| class QByteArray; | ||||
| template<class T> class QList; | ||||
| template<class Key, class Value> class QMap; | ||||
| class QString; | ||||
| class QStringList; | ||||
| class QVariant; | ||||
| QT_END_NAMESPACE | ||||
|  | ||||
| /* | ||||
|  * Adaptor class for interface com.yuezk.qt.GPService | ||||
|  */ | ||||
| class GPServiceAdaptor: public QDBusAbstractAdaptor | ||||
| { | ||||
|     Q_OBJECT | ||||
|     Q_CLASSINFO("D-Bus Interface", "com.yuezk.qt.GPService") | ||||
|     Q_CLASSINFO("D-Bus Introspection", "" | ||||
| "  <interface name=\"com.yuezk.qt.GPService\">\n" | ||||
| "    <signal name=\"connected\"/>\n" | ||||
| "    <signal name=\"disconnected\"/>\n" | ||||
| "    <signal name=\"logAvailable\">\n" | ||||
| "      <arg type=\"s\" name=\"log\"/>\n" | ||||
| "    </signal>\n" | ||||
| "    <method name=\"connect\">\n" | ||||
| "      <arg direction=\"in\" type=\"s\" name=\"server\"/>\n" | ||||
| "      <arg direction=\"in\" type=\"s\" name=\"username\"/>\n" | ||||
| "      <arg direction=\"in\" type=\"s\" name=\"passwd\"/>\n" | ||||
| "    </method>\n" | ||||
| "    <method name=\"disconnect\"/>\n" | ||||
| "    <method name=\"status\">\n" | ||||
| "      <arg direction=\"out\" type=\"i\"/>\n" | ||||
| "    </method>\n" | ||||
| "  </interface>\n" | ||||
|         "") | ||||
| public: | ||||
|     GPServiceAdaptor(QObject *parent); | ||||
|     virtual ~GPServiceAdaptor(); | ||||
|  | ||||
| public: // PROPERTIES | ||||
| public Q_SLOTS: // METHODS | ||||
|     void connect(const QString &server, const QString &username, const QString &passwd); | ||||
|     void disconnect(); | ||||
|     int status(); | ||||
| Q_SIGNALS: // SIGNALS | ||||
|     void connected(); | ||||
|     void disconnected(); | ||||
|     void logAvailable(const QString &log); | ||||
| }; | ||||
|  | ||||
| #endif | ||||
							
								
								
									
										19
									
								
								GPService/main.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								GPService/main.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| #include <QCoreApplication> | ||||
| #include <QtDBus> | ||||
|  | ||||
| #include "gpservice.h" | ||||
|  | ||||
| int main(int argc, char *argv[]) | ||||
| { | ||||
|     QCoreApplication a(argc, argv); | ||||
|  | ||||
|     if (!QDBusConnection::systemBus().isConnected()) { | ||||
|         qWarning("Cannot connect to the D-Bus session bus.\n" | ||||
|                  "Please check your system settings and try again.\n"); | ||||
|         return 1; | ||||
|     } | ||||
|  | ||||
|     new GPService; | ||||
|  | ||||
|     return a.exec(); | ||||
| } | ||||
							
								
								
									
										5
									
								
								GlobalProtect-openconnect.pro
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										5
									
								
								GlobalProtect-openconnect.pro
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| TEMPLATE = subdirs | ||||
|  | ||||
| SUBDIRS += \ | ||||
|     GPClient \ | ||||
|     GPService | ||||
		Reference in New Issue
	
	Block a user