[prev in list] [next in list] [prev in thread] [next in thread]
List: kde-commits
Subject: [plasma-nm] vpn: add OpenConnect VPN plugin
From: Lukáš Tinkl <lukas () kde ! org>
Date: 2013-06-11 14:13:46
Message-ID: 20130611141346.7F2F8A605A () git ! kde ! org
[Download RAW message or body]
Git commit 5cab9552630928d9ed8c3f5ec85cfa0fe894e323 by Lukáš Tinkl.
Committed on 11/06/2013 at 16:13.
Pushed by lukas into branch 'master'.
add OpenConnect VPN plugin
M +1 -0 vpn/CMakeLists.txt
A +43 -0 vpn/openconnect/CMakeLists.txt
A +38 -0 vpn/openconnect/FindOpenConnect.cmake
A +89 -0 vpn/openconnect/README
A +47 -0 vpn/openconnect/nm-openconnect-service.h [License: GPL (v2+)]
A +647 -0 vpn/openconnect/openconnectauth.cpp [License: BSD]
A +67 -0 vpn/openconnect/openconnectauth.h [License: BSD]
A +201 -0 vpn/openconnect/openconnectauth.ui
A +196 -0 vpn/openconnect/openconnectauthworkerthread.cpp [License: BSD]
A +80 -0 vpn/openconnect/openconnectauthworkerthread.h [License: BSD]
A +159 -0 vpn/openconnect/openconnectprop.ui
A +90 -0 vpn/openconnect/openconnectui.cpp [License: BSD]
A +47 -0 vpn/openconnect/openconnectui.h [License: BSD]
A +110 -0 vpn/openconnect/openconnectwidget.cpp [License: BSD]
A +46 -0 vpn/openconnect/openconnectwidget.h [License: BSD]
A +97 -0 vpn/openconnect/plasmanm_openconnectui.desktop [TRAILING SPACE] ** \
[TRAILING SPACE] **
The files marked with ** at the end have a problem. either the file contains a \
trailing space or the file contains a call to a potentially dangerous code. Please \
read: http://community.kde.org/Sysadmin/CommitHooks#Email_notifications Either fix \
the trailing space or review the dangerous code.
http://commits.kde.org/plasma-nm/5cab9552630928d9ed8c3f5ec85cfa0fe894e323
diff --git a/vpn/CMakeLists.txt b/vpn/CMakeLists.txt
index 9d28dd7..040b01b 100644
--- a/vpn/CMakeLists.txt
+++ b/vpn/CMakeLists.txt
@@ -3,3 +3,4 @@ add_subdirectory(openvpn)
add_subdirectory(l2tp)
add_subdirectory(pptp)
add_subdirectory(openswan)
+add_subdirectory(openconnect)
diff --git a/vpn/openconnect/CMakeLists.txt b/vpn/openconnect/CMakeLists.txt
new file mode 100644
index 0000000..2d2edb6
--- /dev/null
+++ b/vpn/openconnect/CMakeLists.txt
@@ -0,0 +1,43 @@
+set (MINIMUM_OPENCONNECT_VERSION_REQUIRED "3.99")
+
+set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH})
+
+macro_optional_find_package(OpenConnect ${MINIMUM_OPENCONNECT_VERSION_REQUIRED})
+if (OPENCONNECT_FOUND)
+ if (${OPENCONNECT_VERSION} VERSION_LESS "3.99")
+ macro_optional_find_package(OpenSSL)
+ macro_log_feature(OPENSSL_FOUND "OpenSSL headers" "Encryption suite" \
"http://www.openssl.org" FALSE "" "Needed for OpenConnect support in Network \
Management") + if (OPENSSL_FOUND)
+ set (MINIMUM_OPENCONNECT_VERSION_REQUIRED "3.03")
+ set (maybe_OPENSSL_LIBRARIES ${OPENSSL_LIBRARIES})
+ endif()
+ endif()
+
+ if (${OPENCONNECT_VERSION} VERSION_GREATER \
${MINIMUM_OPENCONNECT_VERSION_REQUIRED} OR + ${OPENCONNECT_VERSION} \
VERSION_EQUAL ${MINIMUM_OPENCONNECT_VERSION_REQUIRED}) +
+ set(openconnect_SRCS
+ openconnectui.cpp
+ openconnectwidget.cpp
+ openconnectauth.cpp
+ openconnectauthworkerthread.cpp
+ )
+
+ kde4_add_ui_files(openconnect_SRCS openconnectprop.ui openconnectauth.ui)
+
+ kde4_add_plugin(plasmanm_openconnectui ${openconnect_SRCS})
+
+ target_link_libraries(plasmanm_openconnectui plasmanm-internal \
NetworkManagerQt ${KDE4_KIO_LIBS} ${OPENCONNECT_LIBRARIES} \
${maybe_OPENSSL_LIBRARIES}) + install(TARGETS plasmanm_openconnectui \
DESTINATION ${PLUGIN_INSTALL_DIR}) +
+ install( FILES plasmanm_openconnectui.desktop DESTINATION \
${SERVICES_INSTALL_DIR}) + else()
+ message("ERROR: OpenConnection version '${OPENCONNECT_VERSION}' does not \
match minimum required (${MINIMUM_OPENCONNECT_VERSION_REQUIRED})") + \
message("OpenConnect plugin will not be built") + set(OPENCONNECT_FOUND False)
+ endif()
+else (OPENCONNECT_FOUND)
+ message("OpenConnect plugin will not be built")
+endif (OPENCONNECT_FOUND)
+
+macro_log_feature(OPENCONNECT_FOUND "OpenConnect headers and library" "Cisco \
AnyConnect compatible VPN client" "http://www.infradead.org/openconnect.html" FALSE \
${MINIMUM_OPENCONNECT_VERSION_REQUIRED} "Needed for OpenConnect support in Plasma \
NM")
diff --git a/vpn/openconnect/FindOpenConnect.cmake \
b/vpn/openconnect/FindOpenConnect.cmake new file mode 100644
index 0000000..c772883
--- /dev/null
+++ b/vpn/openconnect/FindOpenConnect.cmake
@@ -0,0 +1,38 @@
+# - Try to find OpenConnect
+# Once done this will define
+#
+# OPENCONNECT_FOUND - system has OpenConnect
+# OPENCONNECT_INCLUDE_DIRS - the OpenConnect include directories
+# OPENCONNECT_LIBRARIES - the libraries needed to use OpenConnect
+# OPENCONNECT_CFLAGS - Compiler switches required for using OpenConnect
+# OPENCONNECT_VERSION - version number of OpenConnect
+
+# Copyright (c) 2011, Ilia Kats <ilia-kats@gmx.net>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+IF (OPENCONNECT_INCLUDE_DIRS)
+ # in cache already
+ SET(OpenConnect_FIND_QUIETLY TRUE)
+ENDIF (OPENCONNECT_INCLUDE_DIRS)
+
+IF (NOT WIN32)
+ # use pkg-config to get the directories and then use these values
+ # in the FIND_PATH() and FIND_LIBRARY() calls
+ find_package(PkgConfig)
+ pkg_search_module(OPENCONNECT openconnect)
+ENDIF (NOT WIN32)
+
+IF (OPENCONNECT_FOUND)
+ IF (NOT OpenConnect_FIND_QUIETLY)
+ MESSAGE(STATUS "Found OpenConnect ${OPENCONNECT_VERSION}: \
${OPENCONNECT_LIBRARIES}") + ENDIF (NOT OpenConnect_FIND_QUIETLY)
+ELSE (OPENCONNECT_FOUND)
+ IF (OpenConnect_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could NOT find OpenConnect, check FindPkgConfig output \
above!") + ENDIF (OpenConnect_FIND_REQUIRED)
+ENDIF (OPENCONNECT_FOUND)
+
+MARK_AS_ADVANCED(OPENCONNECT_INCLUDE_DIRS OPENCONNECT_LIBRARIES \
OPENCONNECT_STATIC_LIBRARIES)
diff --git a/vpn/openconnect/README b/vpn/openconnect/README
new file mode 100644
index 0000000..3008214
--- /dev/null
+++ b/vpn/openconnect/README
@@ -0,0 +1,89 @@
+README taken with slight modifications from the network-manager-openconnect
+auth dialog
+
+AnyConnect works over HTTPS; authentication is through HTTP forms and
+POST responses. Once you've filled in the forms that the server demands,
+you're rewarded with an HTTP cookie which is handed on to OpenConnect to
+actually make the connection.
+
+The auth-dialog handles the arbitrary forms as the server presents them,
+and spits out the cookie after a successful authentication. It's just a
+really simple web-browser, effectively. (It has its own HTTP client
+implementation instead of using libsoup because it needs to be able to
+support certificates from a TPM, and to work around Cisco bugs).
+
+To make it slightly more fun, you have a *choice* of servers; an
+AnyConnect VPN is provisioned with an XML file that gives various pieces
+of configuration for the client. We ignore most of the XML file, except
+the list of available VPN server addresses.
+
+So this is a brief flow of what the auth-dialog does...
+
+ 1. Choose a server to connect to.
+
+ If we already have the XML configuration file for this VPN, you get
+ to choose a server from the list. Otherwise, you only have the host
+ that you configured in the VPN setup.
+
+ The auth-dialog will give you the choice of automatically connecting
+ to the last server you used. It does so by storing the boolean
+ 'autoconnect' option, as well as the address of the last successful
+ server, in "secrets" that NetworkManager stores for it, but which
+ aren't actually used by OpenConnect itself at all.
+
+ 2. Offer your SSL certificate and fill in all the forms it presents.
+
+ The server will present a sequence of forms which are filled in just
+ like normal web forms. At this point, the auth-dialog is just acting
+ like a really simple web browser. It uses the same trick with fake
+ secrets to remember the answers for any multiple-choice selection,
+ or input elements of type 'text'. Input elements of type 'password'
+ are not currently saved, but probably should be.
+
+ The choices and input boxes that we fill in at this point may not be
+ limited to *just* authenticating ourselves. You may also get to make
+ choices which affect your resulting connectivity. Some networks
+ offer the choice of full-tunnel or split-tunnel routing, IPv6 or
+ Legacy-only connectivity, etc. (The routing configuration is not
+ handled by the auth-dialog; that just manifests itself in the IP
+ configuration which is given to OpenConnect by the server, much
+ later when the connection is actually made.)
+
+(
+ 2 . Run the "Cisco Secure Desktop"[sic] trojan.
+
+ In some cases you are required to download a strange executable from
+ the server and run it. It is supposed to perform various "checks" on
+ your system and report its results to the server. The authentication
+ sequence is kept in a holding pattern with HTTP refresh responses
+ until the "trojan" has done its job.
+
+ Most people seem to bypass this crap and run a local tool of their
+ own devising to report the "correct" results. It's just another
+ simple HTTP POST, although the exact results that are expected may
+ vary from one server/configuration to another.
+
+ Try not to think about it. It will only make you sad.
+)
+
+ 3. Note the 'webvpn' cookie.
+
+ Once authentication is complete, the server's HTTP response will
+ include a 'webvpn' cookie.
+
+ This cookie is one of the three *real* secrets which are actually
+ passed to OpenConnect to make the connection. The other two are
+ the address of the server we finally ended up talking to (after
+ the user's initial choice and any HTTP redirects), and a hash of
+ the server's SSL certificate (to prevent MiTM attacks).
+
+ 4. Check the XML configuration file.
+
+ With a successful authentication, we are *also* given the SHA1 of
+ the current XML configuration for this VPN connection. If it differs
+ from what we have, we are expected to fetch the new one. We store
+ this, base64-encoded, in yet another fake "secret".
+
+ 5. Dump all the "secrets" to NetworkManager.
+
+ Finally, we write the secrets into the setting, so that NM can use them.
diff --git a/vpn/openconnect/nm-openconnect-service.h \
b/vpn/openconnect/nm-openconnect-service.h new file mode 100644
index 0000000..4b45f20
--- /dev/null
+++ b/vpn/openconnect/nm-openconnect-service.h
@@ -0,0 +1,47 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * 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 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright 2008 - 2009 Intel Corporation. //krazy:exclude=copyright
+ *
+ * Based on nm-openconnect-vpnc.h:
+ * Copyright 2005 - 2008 Red Hat, Inc. //krazy:exclude=copyright
+ * Copyright 2007 - 2008 Novell, Inc. //krazy:exclude=copyright
+ */
+
+#ifndef NM_OPENCONNECT_SERVICE_H
+#define NM_OPENCONNECT_SERVICE_H
+
+#define NM_DBUS_SERVICE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect"
+#define NM_DBUS_INTERFACE_OPENCONNECT "org.freedesktop.NetworkManager.openconnect"
+#define NM_DBUS_PATH_OPENCONNECT "/org/freedesktop/NetworkManager/openconnect"
+
+#define NM_OPENCONNECT_KEY_GATEWAY "gateway"
+#define NM_OPENCONNECT_KEY_COOKIE "cookie"
+#define NM_OPENCONNECT_KEY_GWCERT "gwcert"
+#define NM_OPENCONNECT_KEY_AUTHTYPE "authtype"
+#define NM_OPENCONNECT_KEY_USERCERT "usercert"
+#define NM_OPENCONNECT_KEY_CACERT "cacert"
+#define NM_OPENCONNECT_KEY_PRIVKEY "userkey"
+#define NM_OPENCONNECT_KEY_MTU "mtu"
+#define NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID "pem_passphrase_fsid"
+#define NM_OPENCONNECT_KEY_PROXY "proxy"
+#define NM_OPENCONNECT_KEY_CSD_ENABLE "enable_csd_trojan"
+#define NM_OPENCONNECT_KEY_CSD_WRAPPER "csd_wrapper"
+
+#define NM_OPENCONNECT_USER "nm-openconnect"
+
+#endif /* NM_OPENCONNECT_PLUGIN_H */
diff --git a/vpn/openconnect/openconnectauth.cpp \
b/vpn/openconnect/openconnectauth.cpp new file mode 100644
index 0000000..bd98460
--- /dev/null
+++ b/vpn/openconnect/openconnectauth.cpp
@@ -0,0 +1,647 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+Copyright 2013 Lukáš Tinkl <ltinkl@redhat.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "openconnectauth.h"
+#include "openconnectauthworkerthread.h"
+#include "ui_openconnectauth.h"
+
+#include <KDialog>
+#include <QPushButton>
+#include <QString>
+#include <QLabel>
+#include <QEventLoop>
+#include <QFormLayout>
+#include <KLineEdit>
+#include <KDialogButtonBox>
+#include <KPushButton>
+#include <KComboBox>
+#include <KDebug>
+#include <QDomDocument>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QCryptographicHash>
+#include <QFile>
+
+#include "nm-openconnect-service.h"
+
+#include <cstdarg>
+
+extern "C"
+{
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+}
+
+// name/address: IP/domain name of the host (OpenConnect accepts both, so no \
difference here) +// group: user group on the server
+typedef struct {
+ QString name;
+ QString group;
+ QString address;
+} VPNHost;
+
+class OpenconnectAuthWidgetPrivate
+{
+public:
+ Ui_OpenconnectAuth ui;
+ NetworkManager::VpnSetting::Ptr setting;
+ struct openconnect_info *vpninfo;
+ QStringList certificateFingerprints;
+ NMStringMap secrets;
+ QMutex mutex;
+ QWaitCondition workerWaiting;
+ OpenconnectAuthWorkerThread *worker;
+ QList<VPNHost> hosts;
+ bool userQuit;
+ int cancelPipes[2];
+ QList<QPair<QString, int> > serverLog;
+
+ enum LogLevels {Error = 0, Info, Debug, Trace};
+};
+
+
+OpenconnectAuthWidget::OpenconnectAuthWidget(const NetworkManager::VpnSetting::Ptr \
&setting, QWidget * parent) + : SettingWidget(setting, parent), d_ptr(new \
OpenconnectAuthWidgetPrivate) +{
+ Q_D(OpenconnectAuthWidget);
+ d->setting = setting;
+ d->ui.setupUi(this);
+ d->userQuit = false;
+ if (pipe2(d->cancelPipes, O_NONBLOCK|O_CLOEXEC)) {
+ // Should never happen. Just don't do real cancellation if it does
+ d->cancelPipes[0] = -1;
+ d->cancelPipes[1] = -1;
+ }
+
+ connect(d->ui.cmbLogLevel, SIGNAL(currentIndexChanged(int)), this, \
SLOT(logLevelChanged(int))); + connect(d->ui.viewServerLog, SIGNAL(toggled(bool)), \
this, SLOT(viewServerLogToggled(bool))); + connect(d->ui.btnConnect, \
SIGNAL(clicked()), this, SLOT(connectHost())); + connect(d->ui.cmbHosts, \
SIGNAL(currentIndexChanged(int)), this, SLOT(connectHost())); +
+ d->ui.cmbLogLevel->setCurrentIndex(OpenconnectAuthWidgetPrivate::Debug);
+ d->ui.btnConnect->setIcon(KIcon("network-connect"));
+ d->ui.viewServerLog->setChecked(false);
+
+ d->worker = new OpenconnectAuthWorkerThread(&d->mutex, &d->workerWaiting, \
&d->userQuit, d->cancelPipes[0]); +
+ // gets the pointer to struct openconnect_info (defined in openconnect.h), which \
contains data that OpenConnect needs, + // and which needs to be populated with \
settings we get from NM, like host, certificate or private key + d->vpninfo = \
d->worker->getOpenconnectInfo(); +
+ connect(d->worker, SIGNAL(validatePeerCert(QString,QString,QString,bool*)), \
this, SLOT(validatePeerCert(QString,QString,QString,bool*))); + connect(d->worker, \
SIGNAL(processAuthForm(oc_auth_form*)), this, SLOT(processAuthForm(oc_auth_form*))); \
+ connect(d->worker, SIGNAL(updateLog(QString,int)), this, \
SLOT(updateLog(QString,int))); + connect(d->worker, \
SIGNAL(writeNewConfig(QString)), this, SLOT(writeNewConfig(QString))); + \
connect(d->worker, SIGNAL(cookieObtained(int)), this, SLOT(workerFinished(int))); +
+ readConfig();
+ readSecrets();
+}
+
+OpenconnectAuthWidget::~OpenconnectAuthWidget()
+{
+ Q_D(OpenconnectAuthWidget);
+ d->userQuit = true;
+ if (write(d->cancelPipes[1], "x", 1)) {
+ // not a lot we can do
+ }
+ d->workerWaiting.wakeAll();
+ d->worker->wait();
+ ::close(d->cancelPipes[0]);
+ ::close(d->cancelPipes[1]);
+ deleteAllFromLayout(d->ui.loginBoxLayout);
+ delete d->worker;
+ delete d;
+}
+
+void OpenconnectAuthWidget::readConfig()
+{
+ Q_D(OpenconnectAuthWidget);
+
+ const NMStringMap dataMap = d->setting->data();
+
+ if (!dataMap[NM_OPENCONNECT_KEY_GATEWAY].isEmpty()) {
+ const QString gw = dataMap[NM_OPENCONNECT_KEY_GATEWAY];
+ VPNHost host;
+ const int index = gw.indexOf(QLatin1Char('/'));
+ if (index > -1) {
+ host.name = host.address = gw.left(index);
+ host.group = gw.right(gw.length() - index - 1);
+ } else {
+ host.name = host.address = gw;
+ }
+ d->hosts.append(host);
+ }
+ if (!dataMap[NM_OPENCONNECT_KEY_CACERT].isEmpty()) {
+ const QByteArray crt = \
QFile::encodeName(dataMap[NM_OPENCONNECT_KEY_CACERT]); + \
openconnect_set_cafile(d->vpninfo, strdup(crt.data())); + }
+ if (dataMap[NM_OPENCONNECT_KEY_CSD_ENABLE] == "yes") {
+ char *wrapper;
+ wrapper = 0;
+ if (!dataMap[NM_OPENCONNECT_KEY_CSD_WRAPPER].isEmpty()) {
+ const QByteArray wrapperScript = \
QFile::encodeName(dataMap[NM_OPENCONNECT_KEY_CSD_WRAPPER]); + wrapper = \
strdup(wrapperScript.data()); + }
+ openconnect_setup_csd(d->vpninfo, getuid(), 1, wrapper);
+ }
+ if (!dataMap[NM_OPENCONNECT_KEY_PROXY].isEmpty()) {
+ const QByteArray proxy = \
QFile::encodeName(dataMap[NM_OPENCONNECT_KEY_PROXY]); + \
openconnect_set_http_proxy(d->vpninfo, strdup(proxy.data())); + }
+ if (!dataMap[NM_OPENCONNECT_KEY_USERCERT].isEmpty()) {
+ const QByteArray crt = \
QFile::encodeName(dataMap[NM_OPENCONNECT_KEY_USERCERT]); + const QByteArray \
key = QFile::encodeName(dataMap[NM_OPENCONNECT_KEY_PRIVKEY]); + \
openconnect_set_client_cert (d->vpninfo, strdup(crt.data()), strdup(key.data())); +
+ if (!crt.isEmpty() && dataMap[NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID] == \
"yes") { + openconnect_passphrase_from_fsid(d->vpninfo);
+ }
+ }
+}
+
+void OpenconnectAuthWidget::readSecrets()
+{
+ Q_D(OpenconnectAuthWidget);
+
+ d->secrets = d->setting->secrets();
+
+ if (!d->secrets[NM_OPENCONNECT_KEY_GWCERT].isEmpty()) {
+ d->certificateFingerprints.append(d->secrets[NM_OPENCONNECT_KEY_GWCERT]);
+ }
+
+ if (!d->secrets["xmlconfig"].isEmpty()) {
+
+ QByteArray config = \
QByteArray::fromBase64(d->secrets["xmlconfig"].toAscii()); +
+ QCryptographicHash hash(QCryptographicHash::Sha1);
+ hash.addData(config.data(), config.size());
+ const char *sha1_text = hash.result().toHex();
+ openconnect_set_xmlsha1 (d->vpninfo, (char *)sha1_text, \
strlen(sha1_text)+1); +
+ QDomDocument xmlconfig;
+ xmlconfig.setContent(config);
+ const QDomNode anyConnectProfile = \
xmlconfig.elementsByTagName(QLatin1String("AnyConnectProfile")).at(0); + bool \
matchedGw = false; + const QDomNode serverList = \
anyConnectProfile.firstChildElement(QLatin1String("ServerList")); + for \
(QDomElement entry = serverList.firstChildElement(QLatin1String("HostEntry")); \
!entry.isNull(); entry = entry.nextSiblingElement(QLatin1String("HostEntry"))) { + \
VPNHost host; + host.name = \
entry.firstChildElement(QLatin1String("HostName")).text(); + host.group = \
entry.firstChildElement(QLatin1String("UserGroup")).text(); + host.address \
= entry.firstChildElement(QLatin1String("HostAddress")).text(); + // We \
added the originally configured host in readConfig(). But if + // it \
matches one of the ones in the XML config (as presumably it + // should), \
remove the original and use the one with the pretty name. + if (!matchedGw \
&& host.address == d->hosts.at(0).address) { + d->hosts.removeFirst();
+ matchedGw = true;
+ }
+ d->hosts.append(host);
+ }
+ }
+
+ for (int i = 0; i < d->hosts.size(); i++) {
+ d->ui.cmbHosts->addItem(d->hosts.at(i).name, i);
+ if (d->secrets["lasthost"] == d->hosts.at(i).name || d->secrets["lasthost"] \
== d->hosts.at(i).address) + d->ui.cmbHosts->setCurrentIndex(i);
+ }
+
+ if (d->secrets["autoconnect"] == "yes") {
+ d->ui.chkAutoconnect->setChecked(true);
+ connectHost();
+ }
+ if (!d->secrets["certsigs"].isEmpty()) {
+ d->certificateFingerprints.append(d->secrets["certsigs"].split('\t'));
+ }
+ d->certificateFingerprints.removeDuplicates();
+}
+
+void OpenconnectAuthWidget::acceptDialog()
+{
+ KDialog *dialog = qobject_cast<KDialog*>(parentWidget());
+ if (dialog) {
+ dialog->accept();
+ }
+}
+
+// This starts the worker thread, which connects to the selected AnyConnect host
+// and retrieves the login form
+void OpenconnectAuthWidget::connectHost()
+{
+ Q_D(OpenconnectAuthWidget);
+ d->userQuit = true;
+ if (write(d->cancelPipes[1], "x", 1)) {
+ // not a lot we can do
+ }
+ d->workerWaiting.wakeAll();
+ d->worker->wait();
+ d->userQuit = false;
+
+ /* Suck out the cancel byte(s) */
+ char buf;
+ while (read(d->cancelPipes[0], &buf, 1) == 1)
+ ;
+ deleteAllFromLayout(d->ui.loginBoxLayout);
+ int i = d->ui.cmbHosts->currentIndex();
+ if (i == -1)
+ return;
+ i = d->ui.cmbHosts->itemData(i).toInt();
+ const VPNHost &host = d->hosts.at(i);
+ if (openconnect_parse_url(d->vpninfo, host.address.toAscii().data())) {
+ kWarning() << "Failed to parse server URL" << host.address;
+ openconnect_set_hostname(d->vpninfo, strdup(host.address.toAscii().data()));
+ }
+ if (!openconnect_get_urlpath(d->vpninfo) && !host.group.isEmpty())
+ openconnect_set_urlpath(d->vpninfo, strdup(host.group.toAscii().data()));
+ d->secrets["lasthost"] = host.name;
+ addFormInfo(QLatin1String("dialog-information"), i18n("Contacting host, please \
wait...")); + d->worker->start();
+}
+
+QVariantMap OpenconnectAuthWidget::setting(bool agentOwned) const
+{
+ Q_D(const OpenconnectAuthWidget);
+ Q_UNUSED(agentOwned)
+
+ NMStringMap secrets;
+ QVariantMap secretData;
+
+ secrets.unite(d->secrets);
+ QString host(openconnect_get_hostname(d->vpninfo));
+ QString port = QString::number(openconnect_get_port(d->vpninfo));
+ secrets.insert(QLatin1String(NM_OPENCONNECT_KEY_GATEWAY), host + ':' + port);
+
+ secrets.insert(QLatin1String(NM_OPENCONNECT_KEY_COOKIE), \
QLatin1String(openconnect_get_cookie(d->vpninfo))); + \
openconnect_clear_cookie(d->vpninfo); +
+ OPENCONNECT_X509 *cert = openconnect_get_peer_cert(d->vpninfo);
+ char fingerprint[41];
+ openconnect_get_cert_sha1(d->vpninfo, cert, fingerprint);
+ secrets.insert(QLatin1String(NM_OPENCONNECT_KEY_GWCERT), \
QLatin1String(fingerprint)); + secrets.insert(QLatin1String("certsigs"), \
d->certificateFingerprints.join("\t")); + \
secrets.insert(QLatin1String("autoconnect"), d->ui.chkAutoconnect->isChecked() ? \
"yes" : "no"); +
+ NMStringMap::iterator i = secrets.begin();
+ while (i != secrets.end()) {
+ if (i.value().isEmpty())
+ i = secrets.erase(i);
+ else
+ i++;
+ }
+
+ secretData.insert("secrets", QVariant::fromValue<NMStringMap>(secrets));
+ return secretData;
+}
+
+void OpenconnectAuthWidget::writeNewConfig(const QString & buf)
+{
+ Q_D(OpenconnectAuthWidget);
+ d->secrets["xmlconfig"] = buf;
+}
+
+void OpenconnectAuthWidget::updateLog(const QString &message, const int &level)
+{
+ Q_D(OpenconnectAuthWidget);
+ QPair<QString, int> pair;
+ pair.first = message;
+ if (pair.first.endsWith(QLatin1String("\n")))
+ pair.first.chop(1);
+ switch (level)
+ {
+ case PRG_ERR:
+ pair.second = OpenconnectAuthWidgetPrivate::Error;
+ break;
+ case PRG_INFO:
+ pair.second = OpenconnectAuthWidgetPrivate::Info;
+ break;
+ case PRG_DEBUG:
+ pair.second = OpenconnectAuthWidgetPrivate::Debug;
+ break;
+ case PRG_TRACE:
+ pair.second = OpenconnectAuthWidgetPrivate::Trace;
+ break;
+ }
+ if (pair.second <= d->ui.cmbLogLevel->currentIndex()) {
+ d->ui.serverLog->append(pair.first);
+ }
+
+ d->serverLog.append(pair);
+ if (d->serverLog.size() > 100) {
+ d->serverLog.removeFirst();
+ }
+}
+
+void OpenconnectAuthWidget::logLevelChanged(int newLevel)
+{
+ Q_D(OpenconnectAuthWidget);
+ d->ui.serverLog->clear();
+ QList<QPair<QString, int> >::const_iterator i;
+
+ for (i = d->serverLog.constBegin(); i != d->serverLog.constEnd(); ++i) {
+ QPair<QString, int> pair = *i;
+ if(pair.second <= newLevel) {
+ d->ui.serverLog->append(pair.first);
+ }
+ }
+}
+
+void OpenconnectAuthWidget::addFormInfo(const QString &iconName, const QString \
&message) +{
+ Q_D(OpenconnectAuthWidget);
+ QHBoxLayout *layout = new QHBoxLayout();
+ QLabel *icon = new QLabel(this);
+ QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(icon->sizePolicy().hasHeightForWidth());
+ icon->setSizePolicy(sizePolicy);
+ icon->setMinimumSize(QSize(16, 16));
+ icon->setMaximumSize(QSize(16, 16));
+ layout->addWidget(icon);
+
+ QLabel *text = new QLabel(this);
+ text->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+ text->setWordWrap(false);
+ layout->addWidget(text);
+
+ icon->setPixmap(KIcon(iconName).pixmap(QSize(16,16)));
+ text->setText(message);
+
+ d->ui.loginBoxLayout->addLayout(layout);
+}
+
+void OpenconnectAuthWidget::processAuthForm(struct oc_auth_form *form)
+{
+ Q_D(OpenconnectAuthWidget);
+ deleteAllFromLayout(d->ui.loginBoxLayout);
+ if (form->banner) {
+ addFormInfo(QLatin1String("dialog-information"), form->banner);
+ }
+ if (form->message) {
+ addFormInfo(QLatin1String("dialog-information"), form->message);
+ }
+ if (form->error) {
+ addFormInfo(QLatin1String("dialog-error"), form->error);
+ }
+
+ struct oc_form_opt *opt;
+ QFormLayout *layout = new QFormLayout();
+ QSizePolicy policy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ QCheckBox *togglePasswordMode = new QCheckBox(this);
+ togglePasswordMode->setText(i18n("&Show password"));
+ togglePasswordMode->setChecked(false);
+ connect(togglePasswordMode, SIGNAL(toggled(bool)), this, \
SLOT(passwordModeToggled(bool))); + int passwordnumber = 0;
+ bool focusSet = false;
+ for (opt = form->opts; opt; opt = opt->next) {
+ if (opt->type == OC_FORM_OPT_HIDDEN)
+ continue;
+ QLabel *text = new QLabel(this);
+ text->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+ text->setText(QString(opt->label));
+ QWidget *widget = 0;
+ const QString key = \
QString("form:%1:%2").arg(QLatin1String(form->auth_id)).arg(QLatin1String(opt->name));
+ const QString value = d->secrets.value(key);
+ if (opt->type == OC_FORM_OPT_PASSWORD || opt->type == OC_FORM_OPT_TEXT) {
+ KLineEdit *le = new KLineEdit(this);
+ if (opt->type == OC_FORM_OPT_PASSWORD) {
+ le->setPasswordMode(true);
+ passwordnumber++;
+ }
+ else {
+ le->setText(value);
+ }
+ if (!focusSet && le->text().isEmpty()) {
+ le->setFocus(Qt::OtherFocusReason);
+ focusSet = true;
+ }
+ widget = qobject_cast<QWidget*>(le);
+ } else if (opt->type == OC_FORM_OPT_SELECT) {
+ KComboBox *cmb = new KComboBox(this);
+ struct oc_form_opt_select *sopt = reinterpret_cast<oc_form_opt_select \
*>(opt); + for (int i = 0; i < sopt->nr_choices; i++) {
+ cmb->addItem(QString::fromUtf8(sopt->choices[i].label), \
QString::fromUtf8(sopt->choices[i].name)); + if (value == \
QString::fromUtf8(sopt->choices[i].name)) + \
cmb->setCurrentIndex(i); + }
+ widget = qobject_cast<QWidget*>(cmb);
+ }
+ if (widget) {
+ widget->setProperty("openconnect_opt", (quintptr)opt);
+ widget->setSizePolicy(policy);
+ layout->addRow(text, widget);
+ }
+ }
+ d->ui.loginBoxLayout->addLayout(layout);
+ d->ui.loginBoxLayout->addWidget(togglePasswordMode);
+ if (passwordnumber == 0)
+ togglePasswordMode->setVisible(false);
+ KDialogButtonBox *box = new KDialogButtonBox(this);
+ QPushButton *btn = box->addButton(QDialogButtonBox::Ok);
+ btn->setText(i18n("Login"));
+ btn->setDefault(true);
+ d->ui.loginBoxLayout->addWidget(box);
+ box->setProperty("openconnect_form", (quintptr)form);
+
+ connect(box, SIGNAL(accepted()), this, SLOT(formLoginClicked()));
+}
+
+void OpenconnectAuthWidget::validatePeerCert(const QString &fingerprint,
+ const QString &peerCert, const QString \
&reason, bool *accepted) +{
+ Q_D(OpenconnectAuthWidget);
+
+ if (!d->certificateFingerprints.contains(fingerprint)) {
+ QWidget *widget = new QWidget();
+ QVBoxLayout *verticalLayout;
+ QHBoxLayout *horizontalLayout;
+ QLabel *icon;
+ QLabel *infoText;
+ KTextBrowser *certificate;
+
+ verticalLayout = new QVBoxLayout(widget);
+ horizontalLayout = new QHBoxLayout(widget);
+ icon = new QLabel(widget);
+ QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
+ sizePolicy.setHorizontalStretch(0);
+ sizePolicy.setVerticalStretch(0);
+ sizePolicy.setHeightForWidth(icon->sizePolicy().hasHeightForWidth());
+ icon->setSizePolicy(sizePolicy);
+ icon->setMinimumSize(QSize(48, 48));
+ icon->setMaximumSize(QSize(48, 48));
+
+ horizontalLayout->addWidget(icon);
+
+ infoText = new QLabel(widget);
+ infoText->setAlignment(Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter);
+
+ horizontalLayout->addWidget(infoText);
+
+ verticalLayout->addLayout(horizontalLayout);
+
+ certificate = new KTextBrowser(widget);
+ certificate->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ certificate->setOpenLinks(false);
+
+ verticalLayout->addWidget(certificate);
+
+ icon->setPixmap(KIcon("dialog-information").pixmap(QSize(48,48)));
+ infoText->setText(i18n("Check failed for certificate from VPN server \
\"%1\".\n" + "Reason: %2\nAccept it anyway?", \
openconnect_get_hostname(d->vpninfo),reason)); + infoText->setWordWrap(true);
+ certificate->setText(peerCert);
+
+ QWeakPointer<KDialog> dialog = new KDialog(this);
+ dialog.data()->setWindowModality(Qt::WindowModal);
+ dialog.data()->setButtons(KDialog::Yes | KDialog::No);
+ dialog.data()->setMainWidget(widget);
+ if(dialog.data()->exec() == KDialog::Yes) {
+ d->certificateFingerprints.append(fingerprint);
+ *accepted = true;
+ } else {
+ *accepted = false;
+ }
+ if (dialog) {
+ dialog.data()->deleteLater();
+ }
+ widget->deleteLater();
+ } else {
+ *accepted = true;
+ }
+ d->mutex.lock();
+ d->workerWaiting.wakeAll();
+ d->mutex.unlock();
+}
+
+// Writes the user input from the form into the oc_auth_form structs we got from
+// libopenconnect, and wakes the worker thread up to try to log in and obtain a
+// cookie with this data
+void OpenconnectAuthWidget::formLoginClicked()
+{
+ Q_D(OpenconnectAuthWidget);
+ int lastIndex = d->ui.loginBoxLayout->count() - 1;
+ QLayout *layout = d->ui.loginBoxLayout->itemAt(lastIndex - 2)->layout();
+ struct oc_auth_form *form = (struct oc_auth_form *) \
d->ui.loginBoxLayout->itemAt(lastIndex)->widget()->property("openconnect_form").value<quintptr>();
+
+ for (int i = 0; i < layout->count(); i++) {
+ QLayoutItem *item = layout->itemAt(i);
+ QWidget *widget = item->widget();
+ if (widget && widget->property("openconnect_opt").isValid()) {
+ struct oc_form_opt *opt = (struct oc_form_opt *) \
widget->property("openconnect_opt").value<quintptr>(); + QString key = \
QString("form:%1:%2").arg(QLatin1String(form->auth_id)).arg(QLatin1String(opt->name));
+ if (opt->type == OC_FORM_OPT_PASSWORD || opt->type == OC_FORM_OPT_TEXT) \
{ + KLineEdit *le = qobject_cast<KLineEdit*>(widget);
+ QByteArray text = le->text().toUtf8();
+ opt->value = strdup(text.data());
+ if (opt->type == OC_FORM_OPT_TEXT) {
+ d->secrets.insert(key,le->text());
+ }
+ } else if (opt->type == OC_FORM_OPT_SELECT) {
+ KComboBox *cbo = qobject_cast<KComboBox*>(widget);
+ QByteArray text = \
cbo->itemData(cbo->currentIndex()).toString().toAscii(); + opt->value \
= strdup(text.data()); + \
d->secrets.insert(key,cbo->itemData(cbo->currentIndex()).toString()); + }
+ }
+ }
+ deleteAllFromLayout(d->ui.loginBoxLayout);
+ d->workerWaiting.wakeAll();
+}
+
+void OpenconnectAuthWidget::workerFinished(const int &ret)
+{
+ Q_D(OpenconnectAuthWidget);
+ if (ret < 0) {
+ QString message;
+ QList<QPair<QString, int> >::const_iterator i;
+ for (i = d->serverLog.constEnd()-1; i >= d->serverLog.constBegin(); --i) {
+ QPair<QString, int> pair = *i;
+ if(pair.second <= OpenconnectAuthWidgetPrivate::Error) {
+ message = pair.first;
+ break;
+ }
+ }
+ if (message.isEmpty())
+ message = i18n("Connection attempt was unsuccessful.");
+ deleteAllFromLayout(d->ui.loginBoxLayout);
+ addFormInfo(QLatin1String("dialog-error"), message);
+ } else {
+ deleteAllFromLayout(d->ui.loginBoxLayout);
+ acceptDialog();
+ }
+}
+
+void OpenconnectAuthWidget::deleteAllFromLayout(QLayout *layout)
+{
+ while (QLayoutItem *item = layout->takeAt(0)) {
+ if (QLayout *itemLayout = item->layout()) {
+ deleteAllFromLayout(itemLayout);
+ itemLayout->deleteLater();
+ }
+ else
+ item->widget()->deleteLater();
+ delete item;
+ }
+ layout->invalidate();
+}
+
+void OpenconnectAuthWidget::viewServerLogToggled(bool toggled)
+{
+ Q_D(OpenconnectAuthWidget);
+ d->ui.lblLogLevel->setVisible(toggled);
+ d->ui.cmbLogLevel->setVisible(toggled);
+ if (toggled) {
+ QLayoutItem *item = d->ui.verticalLayout->takeAt(4);
+ if (item) {
+ delete item;
+ }
+ QSizePolicy policy = d->ui.serverLogBox->sizePolicy();
+ policy.setVerticalPolicy(QSizePolicy::Expanding);
+ d->ui.serverLogBox->setSizePolicy(policy);
+ d->ui.serverLog->setVisible(true);
+ } else {
+ QSpacerItem *verticalSpacer = new QSpacerItem(0, 0, QSizePolicy::Minimum, \
QSizePolicy::Expanding); + d->ui.verticalLayout->addItem(verticalSpacer);
+ d->ui.serverLog->setVisible(false);
+ QSizePolicy policy = d->ui.serverLogBox->sizePolicy();
+ policy.setVerticalPolicy(QSizePolicy::Fixed);
+ d->ui.serverLogBox->setSizePolicy(policy);
+ }
+}
+
+void OpenconnectAuthWidget::passwordModeToggled(bool toggled)
+{
+ Q_D(OpenconnectAuthWidget);
+ int lastIndex = d->ui.loginBoxLayout->count() - 1;
+ QLayout *layout = d->ui.loginBoxLayout->itemAt(lastIndex - 2)->layout();
+ for (int i = 0; i < layout->count(); i++) {
+ QLayoutItem *item = layout->itemAt(i);
+ QWidget *widget = item->widget();
+ if (widget && widget->property("openconnect_opt").isValid()) {
+ struct oc_form_opt *opt = (struct oc_form_opt *) \
widget->property("openconnect_opt").value<quintptr>(); + if (opt->type == \
OC_FORM_OPT_PASSWORD) { + KLineEdit *le = \
qobject_cast<KLineEdit*>(widget); + le->setPasswordMode(!toggled);
+ }
+ }
+ }
+}
diff --git a/vpn/openconnect/openconnectauth.h b/vpn/openconnect/openconnectauth.h
new file mode 100644
index 0000000..50ff893
--- /dev/null
+++ b/vpn/openconnect/openconnectauth.h
@@ -0,0 +1,67 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+Copyright 2013 Lukáš Tinkl <ltinkl@redhat.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef OPENCONNECTAUTH_H
+#define OPENCONNECTAUTH_H
+
+#include "settingwidget.h"
+
+#include <NetworkManagerQt/VpnSetting>
+
+#include <QString>
+
+class QLayout;
+struct openconnect_info;
+struct oc_auth_form;
+
+class OpenconnectAuthWidgetPrivate;
+
+class OpenconnectAuthWidget : public SettingWidget
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(OpenconnectAuthWidget)
+public:
+ explicit OpenconnectAuthWidget(const NetworkManager::VpnSetting::Ptr &setting, \
QWidget * parent = 0); + ~OpenconnectAuthWidget();
+ virtual void readSecrets();
+ void readConfig();
+ virtual QVariantMap setting(bool agentOwned = false) const;
+
+private:
+ OpenconnectAuthWidgetPrivate * d_ptr;
+ void acceptDialog();
+ void addFormInfo(const QString &, const QString &);
+ void deleteAllFromLayout(QLayout *);
+
+private slots:
+ void writeNewConfig(const QString &);
+ void validatePeerCert(const QString &, const QString &, const QString &, bool*);
+ void processAuthForm(struct oc_auth_form *);
+ void updateLog(const QString &, const int &);
+ void logLevelChanged(int);
+ void formLoginClicked();
+ void workerFinished(const int&);
+ void viewServerLogToggled(bool);
+ void passwordModeToggled(bool);
+ void connectHost();
+};
+
+#endif // OPENCONNECTAUTH_H
diff --git a/vpn/openconnect/openconnectauth.ui b/vpn/openconnect/openconnectauth.ui
new file mode 100644
index 0000000..538d109
--- /dev/null
+++ b/vpn/openconnect/openconnectauth.ui
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OpenconnectAuth</class>
+ <widget class="QWidget" name="OpenconnectAuth">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>341</width>
+ <height>297</height>
+ </rect>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>OpenConnect VPN Authentication</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMinimumSize</enum>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>VPN Host</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="KComboBox" name="cmbHosts"/>
+ </item>
+ <item>
+ <widget class="KPushButton" name="btnConnect">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Fixed" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="toolTip">
+ <string>Connect</string>
+ </property>
+ <property name="autoDefault">
+ <bool>false</bool>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>false</bool>
+ </property>
+ <property name="isDragEnabled" stdset="0">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QCheckBox" name="chkAutoconnect">
+ <property name="text">
+ <string>Automatically start connecting next time</string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="loginBox">
+ <property name="minimumSize">
+ <size>
+ <width>0</width>
+ <height>0</height>
+ </size>
+ </property>
+ <property name="title">
+ <string notr="true"/>
+ </property>
+ <layout class="QVBoxLayout" name="loginBoxLayout"/>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="serverLogBox">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Preferred" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QVBoxLayout" name="logLayout">
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item>
+ <widget class="QCheckBox" name="viewServerLog">
+ <property name="text">
+ <string>View Log</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="lblLogLevel">
+ <property name="text">
+ <string>Log Level:</string>
+ </property>
+ <property name="alignment">
+ <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="KComboBox" name="cmbLogLevel">
+ <item>
+ <property name="text">
+ <string>Error</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Info</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string comment="like in Debug log level">Debug</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Trace</string>
+ </property>
+ </item>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="KTextBrowser" name="serverLog">
+ <property name="enabled">
+ <bool>true</bool>
+ </property>
+ <property name="frameShape">
+ <enum>QFrame::StyledPanel</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>QFrame::Sunken</enum>
+ </property>
+ <property name="acceptRichText">
+ <bool>false</bool>
+ </property>
+ <property name="textInteractionFlags">
+ <set>Qt::TextSelectableByMouse</set>
+ </property>
+ <property name="openLinks">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>KTextBrowser</class>
+ <extends>QTextBrowser</extends>
+ <header>ktextbrowser.h</header>
+ </customwidget>
+ <customwidget>
+ <class>KComboBox</class>
+ <extends>QComboBox</extends>
+ <header>kcombobox.h</header>
+ </customwidget>
+ <customwidget>
+ <class>KPushButton</class>
+ <extends>QPushButton</extends>
+ <header>kpushbutton.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/vpn/openconnect/openconnectauthworkerthread.cpp \
b/vpn/openconnect/openconnectauthworkerthread.cpp new file mode 100644
index 0000000..6f604b0
--- /dev/null
+++ b/vpn/openconnect/openconnectauthworkerthread.cpp
@@ -0,0 +1,196 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "openconnectauthworkerthread.h"
+
+#include <QThread>
+#include <QMutex>
+#include <QWaitCondition>
+#include <QString>
+#include <QByteArray>
+
+extern "C"
+{
+#include <openconnect.h>
+#include <stdlib.h>
+#if !OPENCONNECT_CHECK_VER(1,5)
+#include <openssl/ssl.h>
+#include <openssl/bio.h>
+#include <openssl/ossl_typ.h>
+#endif
+#include <errno.h>
+}
+
+#include <cstdarg>
+
+class OpenconnectAuthStaticWrapper
+{
+public:
+ static int writeNewConfig(void *obj, char *str, int num)
+ {
+ if (obj)
+ return static_cast<OpenconnectAuthWorkerThread*>(obj)->writeNewConfig(str, \
num); + return -1;
+ }
+ static int validatePeerCert(void *obj, OPENCONNECT_X509 *cert, const char *str)
+ {
+ if (obj)
+ return static_cast<OpenconnectAuthWorkerThread*>(obj)->validatePeerCert(cert, \
str); + return -1;
+ }
+ static int processAuthForm(void *obj, struct oc_auth_form *form)
+ {
+ if (obj)
+ return static_cast<OpenconnectAuthWorkerThread*>(obj)->processAuthFormP(form);
+ return -1;
+ }
+ static void writeProgress(void *obj, int level, const char *str, ...)
+ {
+ if (obj) {
+ va_list argPtr;
+ va_start(argPtr, str);
+ static_cast<OpenconnectAuthWorkerThread*>(obj)->writeProgress(level, \
str, argPtr); + va_end(argPtr);
+ }
+ }
+};
+
+OpenconnectAuthWorkerThread::OpenconnectAuthWorkerThread(QMutex *mutex, \
QWaitCondition *waitForUserInput, bool *userDecidedToQuit, int cancelFd) + : \
QThread(), m_mutex(mutex), m_waitForUserInput(waitForUserInput), \
m_userDecidedToQuit(userDecidedToQuit) +{
+ m_openconnectInfo = openconnect_vpninfo_new((char*)"OpenConnect VPN Agent \
(PlasmaNM - running on KDE)", + \
OpenconnectAuthStaticWrapper::validatePeerCert, + \
OpenconnectAuthStaticWrapper::writeNewConfig, + \
OpenconnectAuthStaticWrapper::processAuthForm, + \
OpenconnectAuthStaticWrapper::writeProgress, + \
this); +#if OPENCONNECT_CHECK_VER(1,4)
+ openconnect_set_cancel_fd(m_openconnectInfo, cancelFd);
+#else
+ // Silence warning about unused parameter
+ Q_UNUSED(cancelFd);
+#endif
+}
+
+OpenconnectAuthWorkerThread::~OpenconnectAuthWorkerThread()
+{
+ openconnect_vpninfo_free(m_openconnectInfo);
+}
+
+void OpenconnectAuthWorkerThread::run()
+{
+ openconnect_init_ssl();
+ int ret = openconnect_obtain_cookie(m_openconnectInfo);
+ if (*m_userDecidedToQuit)
+ return;
+ emit cookieObtained(ret);
+}
+
+struct openconnect_info* OpenconnectAuthWorkerThread::getOpenconnectInfo()
+{
+ return m_openconnectInfo;
+}
+
+int OpenconnectAuthWorkerThread::writeNewConfig(char *buf, int buflen)
+{
+ Q_UNUSED(buflen)
+ if (*m_userDecidedToQuit)
+ return -EINVAL;
+ emit writeNewConfig(QString(QByteArray(buf).toBase64()));
+ return 0;
+}
+
+#if !OPENCONNECT_CHECK_VER(1,5)
+static char *openconnect_get_cert_details(struct openconnect_info *vpninfo,
+ OPENCONNECT_X509 *cert)
+{
+ Q_UNUSED(vpninfo)
+
+ BIO *bp = BIO_new(BIO_s_mem());
+ BUF_MEM *certinfo;
+ char zero = 0;
+ char *ret;
+
+ X509_print_ex(bp, cert, 0, 0);
+ BIO_write(bp, &zero, 1);
+ BIO_get_mem_ptr(bp, &certinfo);
+
+ ret = strdup(certinfo->data);
+ BIO_free(bp);
+
+ return ret;
+}
+#endif
+
+int OpenconnectAuthWorkerThread::validatePeerCert(OPENCONNECT_X509 *cert, const char \
*reason) +{
+ if (*m_userDecidedToQuit)
+ return -EINVAL;
+ char fingerprint[41];
+ int ret = 0;
+
+ ret = openconnect_get_cert_sha1(m_openconnectInfo, cert, fingerprint);
+ if (ret)
+ return ret;
+
+ char *details = openconnect_get_cert_details(m_openconnectInfo, cert);
+
+ bool accepted = false;
+ m_mutex->lock();
+ QString qFingerprint(fingerprint);
+ QString qCertinfo(details);
+ QString qReason(reason);
+ emit validatePeerCert(qFingerprint, qCertinfo, qReason, &accepted);
+ m_waitForUserInput->wait(m_mutex);
+ m_mutex->unlock();
+ ::free(details);
+ if (*m_userDecidedToQuit)
+ return -EINVAL;
+
+ if (accepted)
+ return 0;
+ else
+ return -EINVAL;
+
+}
+
+int OpenconnectAuthWorkerThread::processAuthFormP(struct oc_auth_form *form)
+{
+ if (*m_userDecidedToQuit)
+ return -1;
+
+ m_mutex->lock();
+ emit processAuthForm(form);
+ m_waitForUserInput->wait(m_mutex);
+ m_mutex->unlock();
+ if (*m_userDecidedToQuit)
+ return -1;
+
+ return 0;
+}
+
+void OpenconnectAuthWorkerThread::writeProgress(int level, const char *fmt, va_list \
argPtr) +{
+ if (*m_userDecidedToQuit)
+ return;
+ QString msg;
+ msg.vsprintf(fmt, argPtr);
+ emit updateLog(msg, level);
+}
diff --git a/vpn/openconnect/openconnectauthworkerthread.h \
b/vpn/openconnect/openconnectauthworkerthread.h new file mode 100644
index 0000000..bceea8a
--- /dev/null
+++ b/vpn/openconnect/openconnectauthworkerthread.h
@@ -0,0 +1,80 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef OPENCONNECTAUTHWORKERTHREAD_H
+#define OPENCONNECTAUTHWORKERTHREAD_H
+
+extern "C" {
+#include <openconnect.h>
+}
+
+#if OPENCONNECT_API_VERSION_MAJOR == 1
+#define openconnect_vpninfo_new openconnect_vpninfo_new_with_cbdata
+#define openconnect_init_ssl openconnect_init_openssl
+#endif
+
+#ifndef OPENCONNECT_CHECK_VER
+#define OPENCONNECT_CHECK_VER(x,y) 0
+#endif
+
+#if !OPENCONNECT_CHECK_VER(1,5)
+struct x509_st;
+#define OPENCONNECT_X509 struct x509_st
+#define OPENCONNECT_OPENSSL
+#endif
+
+#include <QThread>
+
+class QMutex;
+class QWaitCondition;
+struct openconnect_info;
+
+class OpenconnectAuthWorkerThread : public QThread
+{
+ Q_OBJECT
+ friend class OpenconnectAuthStaticWrapper;
+public:
+ OpenconnectAuthWorkerThread(QMutex *, QWaitCondition *, bool *, int);
+ ~OpenconnectAuthWorkerThread();
+ struct openconnect_info* getOpenconnectInfo();
+
+signals:
+ void validatePeerCert(const QString &, const QString &, const QString &, bool*);
+ void processAuthForm(struct oc_auth_form *);
+ void updateLog(const QString &, const int&);
+ void writeNewConfig(const QString &);
+ void cookieObtained(const int&);
+
+protected:
+ void run();
+
+private:
+ int writeNewConfig(char *, int);
+ int validatePeerCert(OPENCONNECT_X509 *, const char *);
+ int processAuthFormP(struct oc_auth_form *);
+ void writeProgress(int level, const char *, va_list);
+
+ QMutex *m_mutex;
+ QWaitCondition *m_waitForUserInput;
+ bool *m_userDecidedToQuit;
+ struct openconnect_info *m_openconnectInfo;
+};
+
+#endif
diff --git a/vpn/openconnect/openconnectprop.ui b/vpn/openconnect/openconnectprop.ui
new file mode 100644
index 0000000..939f04e
--- /dev/null
+++ b/vpn/openconnect/openconnectprop.ui
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>OpenconnectProp</class>
+ <widget class="QWidget" name="OpenconnectProp">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>306</width>
+ <height>327</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>OpenConnect Settings</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QGroupBox" name="grp_general">
+ <property name="title">
+ <string comment="like in General settings">General</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout">
+ <property name="fieldGrowthPolicy">
+ <enum>QFormLayout::ExpandingFieldsGrow</enum>
+ </property>
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_4">
+ <property name="text">
+ <string>&Gateway:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leGateway</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="KLineEdit" name="leGateway"/>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>&CA Certificate:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leCaCertificate</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="1">
+ <widget class="KUrlRequester" name="leCaCertificate"/>
+ </item>
+ <item row="2" column="0">
+ <widget class="QLabel" name="label_2">
+ <property name="text">
+ <string>&Proxy:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leProxy</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="2" column="1">
+ <widget class="KLineEdit" name="leProxy"/>
+ </item>
+ <item row="4" column="0">
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>CSD &Wrapper Script:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leCsdWrapperScript</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="3" column="0" colspan="2">
+ <widget class="QCheckBox" name="chkAllowTrojan">
+ <property name="text">
+ <string>Allow Cisco Secure Desktop &trojan</string>
+ </property>
+ </widget>
+ </item>
+ <item row="4" column="1">
+ <widget class="KUrlRequester" name="leCsdWrapperScript"/>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QGroupBox" name="groupBox">
+ <property name="title">
+ <string>Certificate Authentication</string>
+ </property>
+ <layout class="QFormLayout" name="formLayout_2">
+ <item row="0" column="0">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>&User Certificate:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leUserCert</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="1" column="0">
+ <widget class="QLabel" name="label_6">
+ <property name="text">
+ <string>Private &Key:</string>
+ </property>
+ <property name="buddy">
+ <cstring>leUserPrivateKey</cstring>
+ </property>
+ </widget>
+ </item>
+ <item row="0" column="1">
+ <widget class="KUrlRequester" name="leUserCert"/>
+ </item>
+ <item row="1" column="1">
+ <widget class="KUrlRequester" name="leUserPrivateKey"/>
+ </item>
+ <item row="2" column="0" colspan="2">
+ <widget class="QCheckBox" name="chkUseFsid">
+ <property name="text">
+ <string>Use &FSID for key passphrase</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>0</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </widget>
+ <customwidgets>
+ <customwidget>
+ <class>KUrlRequester</class>
+ <extends>QFrame</extends>
+ <header>kurlrequester.h</header>
+ </customwidget>
+ <customwidget>
+ <class>KLineEdit</class>
+ <extends>KLineEdit</extends>
+ <header>klineedit.h</header>
+ </customwidget>
+ </customwidgets>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/vpn/openconnect/openconnectui.cpp b/vpn/openconnect/openconnectui.cpp
new file mode 100644
index 0000000..fdcc485
--- /dev/null
+++ b/vpn/openconnect/openconnectui.cpp
@@ -0,0 +1,90 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+Copyright 2013 Lukas Tinkl <ltinkl@redhat.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "openconnectui.h"
+
+#include <KPluginFactory>
+
+#include "openconnectwidget.h"
+#include "openconnectauth.h"
+
+K_PLUGIN_FACTORY(OpenconnectUiPluginFactory, registerPlugin<OpenconnectUiPlugin>();)
+K_EXPORT_PLUGIN(OpenconnectUiPluginFactory("plasmanm_openconnectui"))
+
+OpenconnectUiPlugin::OpenconnectUiPlugin(QObject * parent, const QVariantList &) : \
VpnUiPlugin(parent) +{
+
+}
+
+OpenconnectUiPlugin::~OpenconnectUiPlugin()
+{
+
+}
+
+SettingWidget * OpenconnectUiPlugin::widget(const NetworkManager::VpnSetting::Ptr \
&setting, QWidget * parent) +{
+ return new OpenconnectSettingWidget(setting, parent);
+}
+
+SettingWidget * OpenconnectUiPlugin::askUser(const NetworkManager::VpnSetting::Ptr \
&setting, QWidget * parent) +{
+ return new OpenconnectAuthWidget(setting, parent);
+}
+
+#if 0
+KDialog::ButtonCodes OpenconnectUiPlugin::suggestAuthDialogButtons()
+{
+ return KDialog::Cancel;
+}
+
+QString OpenconnectUiPlugin::suggestedFileName(Knm::Connection *connection) const
+{
+ Q_UNUSED(connection);
+
+ // TODO : implement suggested file name
+ return QString();
+}
+
+QString OpenconnectUiPlugin::supportedFileExtensions() const
+{
+ // TODO: return supported file extensions
+ return QString();
+}
+
+QVariantList OpenconnectUiPlugin::importConnectionSettings(const QString &fileName)
+{
+ Q_UNUSED(fileName);
+
+ // TODO : import the Openconnect connection from file and return settings
+ mError = VpnUiPlugin::NotImplemented;
+ return QVariantList();
+}
+
+bool OpenconnectUiPlugin::exportConnectionSettings(Knm::Connection * connection, \
const QString &fileName) +{
+ Q_UNUSED(connection);
+ Q_UNUSED(fileName);
+
+ // TODO : export Openconnect connection to file
+ mError = VpnUiPlugin::NotImplemented;
+ return false;
+}
+#endif
diff --git a/vpn/openconnect/openconnectui.h b/vpn/openconnect/openconnectui.h
new file mode 100644
index 0000000..39994f3
--- /dev/null
+++ b/vpn/openconnect/openconnectui.h
@@ -0,0 +1,47 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+Copyright 2013 Lukas Tinkl <ltinkl@redhat.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef OPENCONNECT_UI_H
+#define OPENCONNECT_UI_H
+
+#include "vpnuiplugin.h"
+
+#include <QVariant>
+#include <KDialog>
+
+class OpenconnectUiPlugin : public VpnUiPlugin
+{
+ Q_OBJECT
+public:
+ explicit OpenconnectUiPlugin(QObject * parent = 0, const QVariantList& = \
QVariantList()); + virtual ~OpenconnectUiPlugin();
+ virtual SettingWidget * widget(const NetworkManager::VpnSetting::Ptr &setting, \
QWidget * parent = 0); + virtual SettingWidget * askUser(const \
NetworkManager::VpnSetting::Ptr &setting, QWidget * parent = 0); +#if 0
+ QString suggestedFileName(Knm::Connection *connection) const;
+ QString supportedFileExtensions() const;
+ QVariantList importConnectionSettings(const QString &fileName);
+ bool exportConnectionSettings(Knm::Connection * connection, const QString \
&fileName); + KDialog::ButtonCodes suggestAuthDialogButtons();
+#endif
+};
+
+#endif // OPENCONNECT_UI_H
diff --git a/vpn/openconnect/openconnectwidget.cpp \
b/vpn/openconnect/openconnectwidget.cpp new file mode 100644
index 0000000..a3a20fe
--- /dev/null
+++ b/vpn/openconnect/openconnectwidget.cpp
@@ -0,0 +1,110 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.de>
+Copyright 2013 Lukas Tinkl <ltinkl@redhat.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include "openconnectwidget.h"
+#include <KDialog>
+
+#include "ui_openconnectprop.h"
+
+#include <QString>
+#include "nm-openconnect-service.h"
+
+class OpenconnectSettingWidgetPrivate
+{
+public:
+ Ui_OpenconnectProp ui;
+ NetworkManager::VpnSetting::Ptr setting;
+};
+
+OpenconnectSettingWidget::OpenconnectSettingWidget(const \
NetworkManager::VpnSetting::Ptr &setting, QWidget * parent) +: SettingWidget(setting, \
parent), d_ptr(new OpenconnectSettingWidgetPrivate) +{
+ Q_D(OpenconnectSettingWidget);
+ d->ui.setupUi(this);
+ d->setting = setting;
+
+ connect(d->ui.leGateway, SIGNAL(textChanged(QString)), \
SLOT(slotWidgetChanged())); +
+ if (d->setting)
+ loadConfig(d->setting);
+}
+
+OpenconnectSettingWidget::~OpenconnectSettingWidget()
+{
+ delete d_ptr;
+}
+
+void OpenconnectSettingWidget::loadConfig(const NetworkManager::Setting::Ptr \
&setting) +{
+ Q_D(OpenconnectSettingWidget);
+ Q_UNUSED(setting)
+
+ // General settings
+ const NMStringMap dataMap = d->setting->data();
+
+ d->ui.leGateway->setText(dataMap[NM_OPENCONNECT_KEY_GATEWAY]);
+ d->ui.leCaCertificate->setUrl(KUrl(dataMap[NM_OPENCONNECT_KEY_CACERT]));
+ d->ui.leProxy->setText(dataMap[NM_OPENCONNECT_KEY_PROXY]);
+ d->ui.chkAllowTrojan->setChecked(dataMap[NM_OPENCONNECT_KEY_CSD_ENABLE] == \
"yes"); + d->ui.leCsdWrapperScript->setUrl(KUrl(dataMap[NM_OPENCONNECT_KEY_CSD_WRAPPER]));
+ d->ui.leUserCert->setUrl(KUrl(dataMap[NM_OPENCONNECT_KEY_USERCERT]));
+ d->ui.leUserPrivateKey->setUrl(KUrl(dataMap[NM_OPENCONNECT_KEY_PRIVKEY]));
+ d->ui.chkUseFsid->setChecked(dataMap[NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID] == \
"yes"); +}
+
+QVariantMap OpenconnectSettingWidget::setting(bool agentOwned) const
+{
+ Q_D(const OpenconnectSettingWidget);
+ Q_UNUSED(agentOwned)
+
+ NetworkManager::VpnSetting setting;
+ setting.setServiceType(QLatin1String(NM_DBUS_SERVICE_OPENCONNECT));
+
+ NMStringMap data;
+
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_GATEWAY), d->ui.leGateway->text());
+ if (!d->ui.leCaCertificate->url().isEmpty())
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_CACERT), \
d->ui.leCaCertificate->url().path()); + if (!d->ui.leProxy->text().isEmpty())
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_PROXY), d->ui.leProxy->text());
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_CSD_ENABLE), \
d->ui.chkAllowTrojan->isChecked() ? "yes" : "no"); + if \
(!d->ui.leCsdWrapperScript->url().isEmpty()) + \
data.insert(QLatin1String(NM_OPENCONNECT_KEY_CSD_WRAPPER), \
d->ui.leCsdWrapperScript->url().path()); + if (!d->ui.leUserCert->url().isEmpty())
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_USERCERT), \
d->ui.leUserCert->url().path()); + if (!d->ui.leUserPrivateKey->url().isEmpty())
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_PRIVKEY), \
d->ui.leUserPrivateKey->url().path()); + \
data.insert(QLatin1String(NM_OPENCONNECT_KEY_PEM_PASSPHRASE_FSID), \
d->ui.chkUseFsid->isChecked() ? "yes" : "no"); +
+ /* These are different for every login session, and should not be stored */
+ data.insert(QLatin1String(NM_OPENCONNECT_KEY_COOKIE"-flags"), \
QString::number(NetworkManager::Setting::NotSaved)); + \
data.insert(QLatin1String(NM_OPENCONNECT_KEY_GWCERT"-flags"), \
QString::number(NetworkManager::Setting::NotSaved)); + \
data.insert(QLatin1String(NM_OPENCONNECT_KEY_GATEWAY"-flags"), \
QString::number(NetworkManager::Setting::NotSaved)); +
+ setting.setData(data);
+ return setting.toMap();
+}
+
+bool OpenconnectSettingWidget::isValid() const
+{
+ Q_D(const OpenconnectSettingWidget);
+ return !d->ui.leGateway->text().isEmpty();
+}
diff --git a/vpn/openconnect/openconnectwidget.h \
b/vpn/openconnect/openconnectwidget.h new file mode 100644
index 0000000..516b704
--- /dev/null
+++ b/vpn/openconnect/openconnectwidget.h
@@ -0,0 +1,46 @@
+/*
+Copyright 2011 Ilia Kats <ilia-kats@gmx.net>
+Copyright 2013 Lukas Tinkl <ltinkl@redhat.com>
+
+This library is free software; you can redistribute it and/or
+modify it under the terms of the GNU Lesser General Public
+License as published by the Free Software Foundation; either
+version 2.1 of the License, or (at your option) version 3, or any
+later version accepted by the membership of KDE e.V. (or its
+successor approved by the membership of KDE e.V.), which shall
+act as a proxy defined in Section 6 of version 3 of the license.
+
+This library 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
+Lesser General Public License for more details.
+
+You should have received a copy of the GNU Lesser General Public
+License along with this library. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#ifndef OPENCONNECTWIDGET_H
+#define OPENCONNECTWIDGET_H
+
+#include "settingwidget.h"
+
+#include <NetworkManagerQt/VpnSetting>
+
+class OpenconnectSettingWidgetPrivate;
+
+class OpenconnectSettingWidget : public SettingWidget
+{
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(OpenconnectSettingWidget)
+public:
+ explicit OpenconnectSettingWidget(const NetworkManager::VpnSetting::Ptr \
&setting, QWidget * parent = 0); + ~OpenconnectSettingWidget();
+ virtual void loadConfig(const NetworkManager::Setting::Ptr &setting);
+ virtual QVariantMap setting(bool agentOwned = false) const;
+ virtual bool isValid() const;
+
+private:
+ OpenconnectSettingWidgetPrivate * d_ptr;
+};
+
+#endif // OPENCONNECTWIDGET_H
diff --git a/vpn/openconnect/plasmanm_openconnectui.desktop \
b/vpn/openconnect/plasmanm_openconnectui.desktop new file mode 100644
index 0000000..f5d4e77
--- /dev/null
+++ b/vpn/openconnect/plasmanm_openconnectui.desktop
@@ -0,0 +1,97 @@
+[Desktop Entry]
+Type=Service
+Icon=
+ServiceTypes=PlasmaNM/VpnUiPlugin
+X-KDE-Library=plasmanm_openconnectui
+X-NetworkManager-Services=org.freedesktop.NetworkManager.openconnect
+X-KDE-PluginInfo-Author=Lukáš Tinkl
+X-KDE-PluginInfo-Email=ltinkl@redhat.com
+X-KDE-PluginInfo-Name=plasmanm_openconnectui
+X-KDE-PluginInfo-Version=0.1
+X-KDE-PluginInfo-Website=
+X-KDE-PluginInfo-Category=VPNService
+X-KDE-PluginInfo-Depends=
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-EnabledByDefault=false
+Name=OpenConnect
+Name[ar]=OpenConnect
+Name[bs]=OpenConnect
+Name[ca]=OpenConnect
+Name[ca@valencia]=OpenConnect
+Name[cs]=OpenConnect
+Name[da]=OpenConnect
+Name[de]=OpenConnect
+Name[el]=OpenConnect
+Name[es]=OpenConnect
+Name[et]=OpenConnect
+Name[fi]=OpenConnect
+Name[fr]=OpenConnect
+Name[gl]=OpenConnect
+Name[hu]=OpenConnect
+Name[ia]=OpenConnect
+Name[it]=OpenConnect
+Name[km]=OpenConnect
+Name[lt]=OpenConnect
+Name[mr]=ओपन कनेक्ट
+Name[nb]=OpenConnect
+Name[nds]=OpenConnect
+Name[nl]=OpenConnect
+Name[pa]=OpenConnect
+Name[pl]=OpenConnect
+Name[pt]=OpenConnect
+Name[pt_BR]=OpenConnect
+Name[ro]=OpenConnect
+Name[ru]=OpenConnect
+Name[sk]=OpenConnect
+Name[sl]=OpenConnect
+Name[sr]=Опенконект
+Name[sr@ijekavian]=Опенконект
+Name[sr@ijekavianlatin]=OpenConnect
+Name[sr@latin]=OpenConnect
+Name[sv]=OpenConnect
+Name[tr]=OpenConnect
+Name[uk]=OpenConnect
+Name[x-test]=xxOpenConnectxx
+Name[zh_CN]=OpenConnect
+Name[zh_TW]=OpenConnect
+Comment=OpenConnect Plugin
+Comment[ar]=ملحق OpenConnect
+Comment[bs]=OpenConnect Dodatak
+Comment[ca]=Connector d'OpenConnect
+Comment[ca@valencia]=Connector d'OpenConnect
+Comment[cs]=Modul OpenConnect
+Comment[da]=Plugin til OpenConnect
+Comment[de]=OpenConnect-Modul
+Comment[el]= ρόσθετο OpenConnect
+Comment[es]=Complemento de OpenConnect
+Comment[et]=OpenConnecti plugin
+Comment[fi]=OpenConnect-liitännäinen
+Comment[fr]=Module externe OpenConnect
+Comment[gl]=Complemento de OpenConnect.
+Comment[hu]=OpenConnect modul
+Comment[ia]=Plugin de OpenConnect
+Comment[it]=Estensione OpenConnect
+Comment[km]=កម្មវិធីជំនួយ OpenConnect
+Comment[lt]=OpenConnect papildinys
+Comment[mr]=ओपन कनेक्ट प्लगइन
+Comment[nb]=OpenConnect programtillegg
+Comment[nds]=OpenConnect-Moduul
+Comment[nl]=OpenConnect-plug-in
+Comment[pa]=OpenConnect ਪਲੱਗਇਨ
+Comment[pl]=Wtyczka OpenConnect
+Comment[pt]='Plugin' do OpenConnect
+Comment[pt_BR]=Plugin do OpenConnect
+Comment[ro]=Extensie OpenConnect
+Comment[ru]=Модуль OpenConnect
+Comment[sk]=Plugin OpenConnect
+Comment[sl]=Vstavek OpenConnect
+Comment[sr]=Прикључак Опенконекта
+Comment[sr@ijekavian]=Прикључак Опенконекта
+Comment[sr@ijekavianlatin]=Priključak OpenConnecta
+Comment[sr@latin]=Priključak OpenConnecta
+Comment[sv]=Insticksprogram för OpenConnect
+Comment[tr]=OpenConnect Eklentisi
+Comment[uk]=Додаток OpenConnect
+Comment[x-test]=xxOpenConnect Pluginxx
+Comment[zh_CN]=OpenConnect 插件
+Comment[zh_TW]=OpenConnect 外掛程式
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic