[PATCH] Add OpenConnect VPN support
- From: David Woodhouse <dwmw2 infradead org>
- To: dcbw redhat com
- Cc: networkmanager-list gnome org
- Subject: [PATCH] Add OpenConnect VPN support
- Date: Wed, 26 Nov 2008 11:13:49 +0000
This adds support for the 'OpenConnect' VPN client, used with
Cisco's AnyConnect VPN. Mostly copied from the existing vpnc support.
Signed-off-by: David Woodhouse <dwmw2 infradead org>
---
vpn-daemons/openconnect/.cvsignore | 32 +
vpn-daemons/openconnect/AUTHORS | 3 +
vpn-daemons/openconnect/ChangeLog | 3 +
vpn-daemons/openconnect/Makefile.am | 27 +
vpn-daemons/openconnect/autogen.sh | 22 +
vpn-daemons/openconnect/configure.in | 127 ++++
.../openconnect/nm-openconnect-service.conf | 21 +
.../openconnect/nm-openconnect-service.name.in | 8 +
vpn-daemons/openconnect/po/.cvsignore | 7 +
vpn-daemons/openconnect/po/ChangeLog | 3 +
vpn-daemons/openconnect/po/LINGUAS | 2 +
vpn-daemons/openconnect/po/POTFILES.in | 8 +
vpn-daemons/openconnect/properties/.cvsignore | 2 +
vpn-daemons/openconnect/properties/Makefile.am | 40 ++
vpn-daemons/openconnect/properties/auth-helpers.c | 397 ++++++++++++
vpn-daemons/openconnect/properties/auth-helpers.h | 65 ++
.../properties/nm-openconnect-dialog.glade | 683 ++++++++++++++++++++
.../openconnect/properties/nm-openconnect.c | 502 ++++++++++++++
.../openconnect/properties/nm-openconnect.h | 84 +++
vpn-daemons/openconnect/src/.cvsignore | 4 +
vpn-daemons/openconnect/src/Makefile.am | 40 ++
.../nm-openconnect-service-openconnect-helper.c | 380 +++++++++++
.../openconnect/src/nm-openconnect-service.c | 562 ++++++++++++++++
.../openconnect/src/nm-openconnect-service.h | 49 ++
24 files changed, 3071 insertions(+), 0 deletions(-)
create mode 100644 vpn-daemons/openconnect/.cvsignore
create mode 100644 vpn-daemons/openconnect/AUTHORS
create mode 100644 vpn-daemons/openconnect/ChangeLog
create mode 100644 vpn-daemons/openconnect/Makefile.am
create mode 100644 vpn-daemons/openconnect/NEWS
create mode 100644 vpn-daemons/openconnect/README
create mode 100755 vpn-daemons/openconnect/autogen.sh
create mode 100644 vpn-daemons/openconnect/configure.in
create mode 100644 vpn-daemons/openconnect/nm-openconnect-service.conf
create mode 100644 vpn-daemons/openconnect/nm-openconnect-service.name.in
create mode 100644 vpn-daemons/openconnect/po/.cvsignore
create mode 100644 vpn-daemons/openconnect/po/ChangeLog
create mode 100644 vpn-daemons/openconnect/po/LINGUAS
create mode 100644 vpn-daemons/openconnect/po/POTFILES.in
create mode 100644 vpn-daemons/openconnect/properties/.cvsignore
create mode 100644 vpn-daemons/openconnect/properties/Makefile.am
create mode 100644 vpn-daemons/openconnect/properties/auth-helpers.c
create mode 100644 vpn-daemons/openconnect/properties/auth-helpers.h
create mode 100644 vpn-daemons/openconnect/properties/nm-openconnect-dialog.glade
create mode 100644 vpn-daemons/openconnect/properties/nm-openconnect.c
create mode 100644 vpn-daemons/openconnect/properties/nm-openconnect.h
create mode 100644 vpn-daemons/openconnect/src/.cvsignore
create mode 100644 vpn-daemons/openconnect/src/Makefile.am
create mode 100644 vpn-daemons/openconnect/src/nm-openconnect-service-openconnect-helper.c
create mode 100644 vpn-daemons/openconnect/src/nm-openconnect-service.c
create mode 100644 vpn-daemons/openconnect/src/nm-openconnect-service.h
diff --git a/vpn-daemons/openconnect/.cvsignore b/vpn-daemons/openconnect/.cvsignore
new file mode 100644
index 0000000..7905ef5
--- /dev/null
+++ b/vpn-daemons/openconnect/.cvsignore
@@ -0,0 +1,32 @@
+Makefile
+Makefile.in
+NetworkManager-openconnect*.tar.gz
+aclocal.m4
+autom4te.cache
+compile
+configure
+config.guess
+config.h.in
+config.h
+config.log
+config.status
+config.sub
+depcomp
+install-sh
+intltool-extract.in
+intltool-extract
+intltool-merge.in
+intltool-merge
+intltool-update.in
+intltool-update
+libtool
+ltmain.sh
+missing
+mkinstalldirs
+nm-openconnect.desktop
+nm-openconnect-service
+nm-openconnect-service-vpnc-helper
+nm-openconnect-service.name
+stamp-h1
+COPYING
+INSTALL
diff --git a/vpn-daemons/openconnect/AUTHORS b/vpn-daemons/openconnect/AUTHORS
new file mode 100644
index 0000000..619c96f
--- /dev/null
+++ b/vpn-daemons/openconnect/AUTHORS
@@ -0,0 +1,3 @@
+Dan Williams <dcbw redhat com>
+David Zeuthen <davidz redhat com>
+David Woodhouse <dwmw2 infradead org>
diff --git a/vpn-daemons/openconnect/ChangeLog b/vpn-daemons/openconnect/ChangeLog
new file mode 100644
index 0000000..5647d2f
--- /dev/null
+++ b/vpn-daemons/openconnect/ChangeLog
@@ -0,0 +1,3 @@
+2008-11-26 David Woodhouse <dwmw2 infradead org>
+
+ * New files, copied from vpnc support.
diff --git a/vpn-daemons/openconnect/Makefile.am b/vpn-daemons/openconnect/Makefile.am
new file mode 100644
index 0000000..9b7737d
--- /dev/null
+++ b/vpn-daemons/openconnect/Makefile.am
@@ -0,0 +1,27 @@
+AUTOMAKE_OPTIONS = foreign
+
+if WITH_GNOME
+SUBDIRS = src properties po
+else
+SUBDIRS = src
+endif
+
+dbusservicedir = $(sysconfdir)/dbus-1/system.d
+dbusservice_DATA = nm-openconnect-service.conf
+
+nmvpnservicedir = $(sysconfdir)/NetworkManager/VPN
+nmvpnservice_DATA = nm-openconnect-service.name
+
+nm-openconnect-service.name: $(srcdir)/nm-openconnect-service.name.in
+ sed -e 's|[ ]LIBEXECDIR[@]|$(libexecdir)|g' $< >$@
+
+EXTRA_DIST = nm-openconnect-service.name.in \
+ $(dbusservice_DATA) \
+ $(desktop_in_files) \
+ $(icon_DATA) \
+ intltool-extract.in \
+ intltool-merge.in \
+ intltool-update.in
+
+CLEANFILES = $(nmvpnservice_DATA) $(desktop_DATA) *~
+DISTCLEANFILES = intltool-extract intltool-merge intltool-update
diff --git a/vpn-daemons/openconnect/NEWS b/vpn-daemons/openconnect/NEWS
new file mode 100644
index 0000000..e69de29
diff --git a/vpn-daemons/openconnect/README b/vpn-daemons/openconnect/README
new file mode 100644
index 0000000..e69de29
diff --git a/vpn-daemons/openconnect/autogen.sh b/vpn-daemons/openconnect/autogen.sh
new file mode 100755
index 0000000..6742f1b
--- /dev/null
+++ b/vpn-daemons/openconnect/autogen.sh
@@ -0,0 +1,22 @@
+#!/bin/sh
+# Run this to generate all the initial makefiles, etc.
+
+srcdir=`dirname $0`
+test -z "$srcdir" && srcdir=.
+REQUIRED_AUTOMAKE_VERSION=1.7
+PKG_NAME=NetworkManager-openconnect
+
+(test -f $srcdir/configure.in) || {
+ echo -n "**Error**: Directory "\`$srcdir\'" does not look like the"
+ echo " top-level $PKG_NAME directory"
+ exit 1
+}
+
+
+which gnome-autogen.sh || {
+ echo "You need to install gnome-common from the GNOME CVS"
+ exit 1
+}
+USE_GNOME2_MACROS=1 . gnome-autogen.sh
+
+
diff --git a/vpn-daemons/openconnect/configure.in b/vpn-daemons/openconnect/configure.in
new file mode 100644
index 0000000..66820c7
--- /dev/null
+++ b/vpn-daemons/openconnect/configure.in
@@ -0,0 +1,127 @@
+AC_PREREQ(2.52)
+
+AC_INIT(NetworkManager-openconnect, 0.7.0, dcbw redhat com, NetworkManager-openconnect)
+AC_CONFIG_AUX_DIR(.)
+AM_INIT_AUTOMAKE([subdir-objects])
+AM_MAINTAINER_MODE
+
+AM_CONFIG_HEADER(config.h)
+
+dnl
+dnl Require programs
+dnl
+AC_PROG_CC
+AM_PROG_CC_C_O
+AC_PROG_INSTALL
+AC_PROG_LIBTOOL
+
+dnl
+dnl Required headers
+dnl
+AC_HEADER_STDC
+AC_CHECK_HEADERS(fcntl.h paths.h sys/ioctl.h sys/time.h syslog.h unistd.h)
+
+dnl
+dnl Checks for typedefs, structures, and compiler characteristics.
+dnl
+AC_TYPE_MODE_T
+AC_TYPE_PID_T
+AC_HEADER_TIME
+
+dnl
+dnl Checks for library functions.
+dnl
+AC_PROG_GCC_TRADITIONAL
+AC_FUNC_MEMCMP
+AC_CHECK_FUNCS(select socket uname)
+
+dnl
+dnl GNOME support
+dnl
+AC_ARG_WITH(gnome, AC_HELP_STRING([--without-gnome], [Build NetworkManager-openconnect without GNOME support, e.g. vpn service only]))
+AM_CONDITIONAL(WITH_GNOME, test x"$with_gnome" != xno)
+
+GETTEXT_PACKAGE=NetworkManager-openconnect
+AC_SUBST(GETTEXT_PACKAGE)
+AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE", [Gettext package])
+
+IT_PROG_INTLTOOL([0.35])
+AM_GLIB_GNU_GETTEXT
+
+PKG_CHECK_MODULES(GTHREAD, gthread-2.0)
+AC_SUBST(GTHREAD_CFLAGS)
+AC_SUBST(GTHREAD_LIBS)
+
+PKG_CHECK_MODULES(DBUS, dbus-glib-1 >= 0.30)
+AC_SUBST(DBUS_CFLAGS)
+AC_SUBST(DBUS_LIBS)
+
+if test x"$with_gnome" != xno; then
+ PKG_CHECK_MODULES(GTK, gtk+-2.0 >= 2.6)
+ AC_SUBST(GTK_CFLAGS)
+ AC_SUBST(GTK_LIBS)
+
+ PKG_CHECK_MODULES(GDK_PIXBUF, gdk-pixbuf-2.0)
+ AC_SUBST(GDK_PIXBUF_CFLAGS)
+ AC_SUBST(GDK_PIXBUF_LIBS)
+
+ PKG_CHECK_MODULES(GLADE, libglade-2.0)
+ AC_SUBST(GLADE_CFLAGS)
+ AC_SUBST(GLADE_LIBS)
+
+ PKG_CHECK_MODULES(LIBGNOMEUI, libgnomeui-2.0)
+ AC_SUBST(LIBGNOMEUI_CFLAGS)
+ AC_SUBST(LIBGNOMEUI_LIBS)
+
+ PKG_CHECK_MODULES(GCONF, gconf-2.0)
+ AC_SUBST(GCONF_CFLAGS)
+ AC_SUBST(GCONF_LIBS)
+
+ PKG_CHECK_MODULES(GNOMEKEYRING, gnome-keyring-1)
+ AC_SUBST(GNOMEKEYRING_CFLAGS)
+ AC_SUBST(GNOMEKEYRING_LIBS)
+fi
+
+PKG_CHECK_MODULES(NM_UTILS, NetworkManager >= 0.7.0 libnm-util libnm_glib libnm_glib_vpn)
+AC_SUBST(NM_UTILS_CFLAGS)
+AC_SUBST(NM_UTILS_LIBS)
+
+AC_ARG_ENABLE(more-warnings,
+AC_HELP_STRING([--enable-more-warnings], [Maximum compiler warnings]),
+set_more_warnings="$enableval",[
+if test -d "$srcdir/{arch}" || test -d "$srcdir/CVS"; then
+ set_more_warnings=yes
+else
+ set_more_warnings=no
+fi
+])
+AC_MSG_CHECKING(for more warnings, including -Werror)
+if test "$GCC" = "yes" -a "$set_more_warnings" != "no"; then
+ AC_MSG_RESULT(yes)
+ CFLAGS="-Wall -Werror -std=gnu89 $CFLAGS"
+
+ for option in -Wno-unused -Wno-strict-aliasing -Wno-sign-compare -Wdeclaration-after-statement -Wno-pointer-sign ; do
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS $option"
+ AC_MSG_CHECKING([whether gcc understands $option])
+ AC_TRY_COMPILE([], [],
+ has_option=yes,
+ has_option=no,)
+ if test $has_option = no; then
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ AC_MSG_RESULT($has_option)
+ unset has_option
+ unset SAVE_CFLAGS
+ done
+ unset option
+else
+ AC_MSG_RESULT(no)
+fi
+
+AC_OUTPUT([
+Makefile
+src/Makefile
+properties/Makefile
+po/Makefile.in
+])
diff --git a/vpn-daemons/openconnect/nm-openconnect-service.conf b/vpn-daemons/openconnect/nm-openconnect-service.conf
new file mode 100644
index 0000000..2cc1c27
--- /dev/null
+++ b/vpn-daemons/openconnect/nm-openconnect-service.conf
@@ -0,0 +1,21 @@
+<!DOCTYPE busconfig PUBLIC
+ "-//freedesktop//DTD D-BUS Bus Configuration 1.0//EN"
+ "http://www.freedesktop.org/standards/dbus/1.0/busconfig.dtd">
+<busconfig>
+ <policy user="root">
+ <allow own="org.freedesktop.NetworkManager.openconnect"/>
+ <allow send_destination="org.freedesktop.NetworkManager.openconnect"/>
+ <allow send_interface="org.freedesktop.NetworkManager.openconnect"/>
+ </policy>
+ <policy user="nm-openconnect">
+ <allow own="org.freedesktop.NetworkManager.openconnect"/>
+ <allow send_destination="org.freedesktop.NetworkManager.openconnect"/>
+ <allow send_interface="org.freedesktop.NetworkManager.openconnect"/>
+ </policy>
+ <policy context="default">
+ <deny own="org.freedesktop.NetworkManager.openconnect"/>
+ <deny send_destination="org.freedesktop.NetworkManager.openconnect"/>
+ <deny send_interface="org.freedesktop.NetworkManager.openconnect"/>
+ </policy>
+</busconfig>
+
diff --git a/vpn-daemons/openconnect/nm-openconnect-service.name.in b/vpn-daemons/openconnect/nm-openconnect-service.name.in
new file mode 100644
index 0000000..0e13290
--- /dev/null
+++ b/vpn-daemons/openconnect/nm-openconnect-service.name.in
@@ -0,0 +1,8 @@
+[VPN Connection]
+name=openconnect
+service=org.freedesktop.NetworkManager.openconnect
+program= LIBEXECDIR@/nm-openconnect-service
+
+[GNOME]
+auth-dialog=nm-openconnect-auth-dialog
+properties=libnm-openconnect-properties
diff --git a/vpn-daemons/openconnect/po/.cvsignore b/vpn-daemons/openconnect/po/.cvsignore
new file mode 100644
index 0000000..06d8851
--- /dev/null
+++ b/vpn-daemons/openconnect/po/.cvsignore
@@ -0,0 +1,7 @@
+Makefile.in.in
+Makefile
+Makefile.in
+POTFILES
+*.pot
+stamp-it
+*.gmo
diff --git a/vpn-daemons/openconnect/po/ChangeLog b/vpn-daemons/openconnect/po/ChangeLog
new file mode 100644
index 0000000..8a668ac
--- /dev/null
+++ b/vpn-daemons/openconnect/po/ChangeLog
@@ -0,0 +1,3 @@
+2008-11-26 David Woodhouse <dwmw2 infradead org>
+
+ * LINGUAS: Empty file; no translations yet.
diff --git a/vpn-daemons/openconnect/po/LINGUAS b/vpn-daemons/openconnect/po/LINGUAS
new file mode 100644
index 0000000..bc8cbb0
--- /dev/null
+++ b/vpn-daemons/openconnect/po/LINGUAS
@@ -0,0 +1,2 @@
+# please keep this list sorted alphabetically
+#
diff --git a/vpn-daemons/openconnect/po/POTFILES.in b/vpn-daemons/openconnect/po/POTFILES.in
new file mode 100644
index 0000000..9751d36
--- /dev/null
+++ b/vpn-daemons/openconnect/po/POTFILES.in
@@ -0,0 +1,8 @@
+# List of source files containing translatable strings.
+# Please keep this file sorted alphabetically.
+properties/auth-helpers.c
+properties/nm-openconnect.c
+properties/nm-openconnect-dialog.glade
+src/nm-openconnect-service.c
+
+
diff --git a/vpn-daemons/openconnect/properties/.cvsignore b/vpn-daemons/openconnect/properties/.cvsignore
new file mode 100644
index 0000000..3dda729
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/.cvsignore
@@ -0,0 +1,2 @@
+Makefile.in
+Makefile
diff --git a/vpn-daemons/openconnect/properties/Makefile.am b/vpn-daemons/openconnect/properties/Makefile.am
new file mode 100644
index 0000000..0b5921e
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/Makefile.am
@@ -0,0 +1,40 @@
+plugindir = $(libdir)/NetworkManager
+plugin_LTLIBRARIES = libnm-openconnect-properties.la
+
+libnm_openconnect_properties_la_SOURCES = \
+ auth-helpers.c \
+ auth-helpers.h \
+ nm-openconnect.c \
+ nm-openconnect.h
+
+gladedir = $(datadir)/gnome-vpn-properties/openconnect
+glade_DATA = nm-openconnect-dialog.glade
+
+libnm_openconnect_properties_la_CFLAGS = \
+ $(GLADE_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(GCONF_CFLAGS) \
+ $(LIBGNOMEUI_CFLAGS) \
+ $(NM_UTILS_CFLAGS) \
+ -DICONDIR=\""$(datadir)/pixmaps"\" \
+ -DGLADEDIR=\""$(gladedir)"\" \
+ -DG_DISABLE_DEPRECATED \
+ -DGDK_DISABLE_DEPRECATED \
+ -DGNOME_DISABLE_DEPRECATED \
+ -DGNOMELOCALEDIR=\"$(datadir)/locale\" \
+ -DVERSION=\"$(VERSION)\"
+
+libnm_openconnect_properties_la_LIBADD = \
+ $(GLADE_LIBS) \
+ $(GTK_LIBS) \
+ $(GCONF_LIBS) \
+ $(LIBGNOMEUI_LIBS) \
+ $(NM_UTILS_LIBS)
+
+libnm_openconnect_properties_la_LDFLAGS = \
+ -avoid-version
+
+CLEANFILES = *.bak *.gladep *~
+
+EXTRA_DIST = \
+ $(glade_DATA)
diff --git a/vpn-daemons/openconnect/properties/auth-helpers.c b/vpn-daemons/openconnect/properties/auth-helpers.c
new file mode 100644
index 0000000..3cbd896
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/auth-helpers.c
@@ -0,0 +1,397 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ * Copyright (C) 2008 Tambet Ingo, <tambet gmail com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include <glib/gi18n-lib.h>
+
+#include "auth-helpers.h"
+#include "nm-openconnect.h"
+#include "../src/nm-openconnect-service.h"
+
+void
+tls_pw_init_auth_widget (GladeXML *xml,
+ GtkSizeGroup *group,
+ NMSettingVPN *s_vpn,
+ const char *contype,
+ const char *prefix,
+ ChangedCallback changed_cb,
+ gpointer user_data)
+{
+ GtkWidget *widget;
+ const char *value;
+ char *tmp;
+ GtkFileFilter *filter;
+
+ g_return_if_fail (xml != NULL);
+ g_return_if_fail (group != NULL);
+ g_return_if_fail (changed_cb != NULL);
+ g_return_if_fail (prefix != NULL);
+
+ tmp = g_strdup_printf ("%s_ca_cert_chooser", prefix);
+ widget = glade_xml_get_widget (xml, tmp);
+ g_free (tmp);
+
+ gtk_size_group_add_widget (group, widget);
+ filter = tls_file_chooser_filter_new ();
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
+ gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
+ _("Choose a Certificate Authority certificate..."));
+ g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (changed_cb), user_data);
+
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_CACERT);
+ if (value && strlen (value))
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
+ }
+
+ if (!strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT) ||
+ !strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT_TPM)) {
+ tmp = g_strdup_printf ("%s_user_cert_chooser", prefix);
+ widget = glade_xml_get_widget (xml, tmp);
+ g_free (tmp);
+
+ gtk_size_group_add_widget (group, widget);
+ filter = tls_file_chooser_filter_new ();
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
+ gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
+ _("Choose your personal certificate..."));
+ g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (changed_cb), user_data);
+
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_USERCERT);
+ if (value && strlen (value))
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
+ }
+
+ tmp = g_strdup_printf ("%s_private_key_chooser", prefix);
+ widget = glade_xml_get_widget (xml, tmp);
+ g_free (tmp);
+
+ gtk_size_group_add_widget (group, widget);
+ filter = tls_file_chooser_filter_new ();
+ gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (widget), filter);
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (widget), TRUE);
+ gtk_file_chooser_button_set_title (GTK_FILE_CHOOSER_BUTTON (widget),
+ _("Choose your private key..."));
+ g_signal_connect (G_OBJECT (widget), "selection-changed", G_CALLBACK (changed_cb), user_data);
+
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_PRIVKEY);
+ if (value && strlen (value))
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), value);
+ }
+ }
+
+ if (!strcmp (contype, NM_OPENCONNECT_AUTHTYPE_PASSWORD)) {
+ tmp = g_strdup_printf ("%s_username_entry", prefix);
+ widget = glade_xml_get_widget (xml, tmp);
+ g_free (tmp);
+
+ gtk_size_group_add_widget (group, widget);
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_USERNAME);
+ if (value && strlen (value))
+ gtk_entry_set_text (GTK_ENTRY (widget), value);
+ }
+ g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (changed_cb), user_data);
+ }
+}
+
+static gboolean
+validate_file_chooser (GladeXML *xml, const char *name)
+{
+ GtkWidget *widget;
+ char *str;
+
+ widget = glade_xml_get_widget (xml, name);
+ str = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+ if (!str || !strlen (str))
+ return FALSE;
+ return TRUE;
+}
+
+static gboolean
+validate_tls (GladeXML *xml, const char *prefix, GError **error)
+{
+ char *tmp;
+ gboolean valid;
+
+#if 0 // optional
+ tmp = g_strdup_printf ("%s_ca_cert_chooser", prefix);
+ valid = validate_file_chooser (xml, tmp);
+ g_free (tmp);
+ if (!valid) {
+ g_set_error (error,
+ OPENCONNECT_PLUGIN_UI_ERROR,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_OPENCONNECT_KEY_CACERT);
+ return FALSE;
+ }
+#endif
+ tmp = g_strdup_printf ("%s_user_cert_chooser", prefix);
+ valid = validate_file_chooser (xml, tmp);
+ g_free (tmp);
+ if (!valid) {
+ g_set_error (error,
+ OPENCONNECT_PLUGIN_UI_ERROR,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_OPENCONNECT_KEY_USERCERT);
+ return FALSE;
+ }
+#if 0 // also optional -- can be in the cert
+ tmp = g_strdup_printf ("%s_private_key_chooser", prefix);
+ valid = validate_file_chooser (xml, tmp);
+ g_free (tmp);
+ if (!valid) {
+ g_set_error (error,
+ OPENCONNECT_PLUGIN_UI_ERROR,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_OPENCONNECT_KEY_PRIVKEY);
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+gboolean
+auth_widget_check_validity (GladeXML *xml, const char *contype, GError **error)
+{
+ GtkWidget *widget;
+ const char *str;
+
+ if (!strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT) ||
+ !strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT_TPM)) {
+ if (!validate_tls (xml, "cert", error))
+ return FALSE;
+ } else if (!strcmp (contype, NM_OPENCONNECT_AUTHTYPE_PASSWORD)) {
+#if 0 // optional
+ if (!validate_file_chooser (xml, "pw_ca_cert_chooser")) {
+ g_set_error (error,
+ OPENCONNECT_PLUGIN_UI_ERROR,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_OPENCONNECT_KEY_CACERT);
+ return FALSE;
+ }
+// as is this... the auth-dialog can ask for it.
+ widget = glade_xml_get_widget (xml, "pw_username_entry");
+ str = gtk_entry_get_text (GTK_ENTRY (widget));
+ if (!str || !strlen (str)) {
+ g_set_error (error,
+ OPENCONNECT_PLUGIN_UI_ERROR,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_OPENCONNECT_KEY_USERNAME);
+ return FALSE;
+ }
+#endif
+ } else
+ g_assert_not_reached ();
+
+ return TRUE;
+}
+
+static void
+update_from_filechooser (GladeXML *xml,
+ const char *key,
+ const char *prefix,
+ const char *widget_name,
+ NMSettingVPN *s_vpn)
+{
+ GtkWidget *widget;
+ char *tmp, *filename;
+
+ g_return_if_fail (xml != NULL);
+ g_return_if_fail (key != NULL);
+ g_return_if_fail (prefix != NULL);
+ g_return_if_fail (widget_name != NULL);
+ g_return_if_fail (s_vpn != NULL);
+
+ tmp = g_strdup_printf ("%s_%s", prefix, widget_name);
+ widget = glade_xml_get_widget (xml, tmp);
+ g_free (tmp);
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+ if (!filename)
+ return;
+
+ if (strlen (filename))
+ nm_setting_vpn_add_data_item (s_vpn, key, filename);
+
+ g_free (filename);
+}
+
+static void
+update_tls (GladeXML *xml, const char *prefix, NMSettingVPN *s_vpn)
+{
+ update_from_filechooser (xml, NM_OPENCONNECT_KEY_CACERT, prefix, "ca_cert_chooser", s_vpn);
+ update_from_filechooser (xml, NM_OPENCONNECT_KEY_USERCERT, prefix, "user_cert_chooser", s_vpn);
+ update_from_filechooser (xml, NM_OPENCONNECT_KEY_PRIVKEY, prefix, "private_key_chooser", s_vpn);
+}
+
+static void
+update_username (GladeXML *xml, const char *prefix, NMSettingVPN *s_vpn)
+{
+ GtkWidget *widget;
+ char *tmp;
+ const char *str;
+
+ g_return_if_fail (xml != NULL);
+ g_return_if_fail (prefix != NULL);
+ g_return_if_fail (s_vpn != NULL);
+
+ tmp = g_strdup_printf ("%s_username_entry", prefix);
+ widget = glade_xml_get_widget (xml, tmp);
+ g_free (tmp);
+
+ str = gtk_entry_get_text (GTK_ENTRY (widget));
+ if (str && strlen (str))
+ nm_setting_vpn_add_data_item (s_vpn, NM_OPENCONNECT_KEY_USERNAME, str);
+}
+
+gboolean
+auth_widget_update_connection (GladeXML *xml,
+ const char *contype,
+ NMSettingVPN *s_vpn)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ GtkWidget *widget;
+
+ if (!strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT) ||
+ !strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT_TPM)) {
+ update_tls (xml, "cert", s_vpn);
+ } else if (!strcmp (contype, NM_OPENCONNECT_AUTHTYPE_PASSWORD)) {
+ update_from_filechooser (xml, NM_OPENCONNECT_KEY_CACERT, "pw",
+ "ca_cert_chooser", s_vpn);
+ update_username (xml, "pw", s_vpn);
+ } else
+ g_assert_not_reached ();
+
+ return TRUE;
+}
+
+static const char *
+find_tag (const char *tag, const char *buf, gsize len)
+{
+ gsize i, taglen;
+
+ taglen = strlen (tag);
+ if (len < taglen)
+ return NULL;
+
+ for (i = 0; i < len - taglen; i++) {
+ if (memcmp (buf + i, tag, taglen) == 0)
+ return buf + i;
+ }
+ return NULL;
+}
+
+static const char *pem_rsa_key_begin = "-----BEGIN RSA PRIVATE KEY-----";
+static const char *pem_dsa_key_begin = "-----BEGIN DSA PRIVATE KEY-----";
+static const char *pem_tss_keyblob_begin = "-----BEGIN TSS KEY BLOB-----";
+static const char *pem_cert_begin = "-----BEGIN CERTIFICATE-----";
+
+static gboolean
+tls_default_filter (const GtkFileFilterInfo *filter_info, gpointer data)
+{
+ char *contents = NULL, *p, *ext;
+ gsize bytes_read = 0;
+ gboolean show = FALSE;
+ struct stat statbuf;
+
+ if (!filter_info->filename)
+ return FALSE;
+
+ p = strrchr (filter_info->filename, '.');
+ if (!p)
+ return FALSE;
+
+ ext = g_ascii_strdown (p, -1);
+ if (!ext)
+ return FALSE;
+ if (strcmp (ext, ".pem") && strcmp (ext, ".crt") && strcmp (ext, ".key")) {
+ g_free (ext);
+ return FALSE;
+ }
+ g_free (ext);
+
+ /* Ignore files that are really large */
+ if (!stat (filter_info->filename, &statbuf)) {
+ if (statbuf.st_size > 500000)
+ return FALSE;
+ }
+
+ if (!g_file_get_contents (filter_info->filename, &contents, &bytes_read, NULL))
+ return FALSE;
+
+ if (bytes_read < 400) /* needs to be lower? */
+ goto out;
+
+ /* Check for PEM signatures */
+ if (find_tag (pem_rsa_key_begin, (const char *) contents, bytes_read)) {
+ show = TRUE;
+ goto out;
+ }
+
+ if (find_tag (pem_dsa_key_begin, (const char *) contents, bytes_read)) {
+ show = TRUE;
+ goto out;
+ }
+
+ if (find_tag (pem_tss_keyblob_begin, (const char *) contents, bytes_read)) {
+ show = TRUE;
+ goto out;
+ }
+
+ if (find_tag (pem_cert_begin, (const char *) contents, bytes_read)) {
+ show = TRUE;
+ goto out;
+ }
+
+out:
+ g_free (contents);
+ return show;
+}
+
+GtkFileFilter *
+tls_file_chooser_filter_new (void)
+{
+ GtkFileFilter *filter;
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_add_custom (filter, GTK_FILE_FILTER_FILENAME, tls_default_filter, NULL, NULL);
+ gtk_file_filter_set_name (filter, _("PEM certificates (*.pem, *.crt, *.key)"));
+ return filter;
+}
+
diff --git a/vpn-daemons/openconnect/properties/auth-helpers.h b/vpn-daemons/openconnect/properties/auth-helpers.h
new file mode 100644
index 0000000..7168221
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/auth-helpers.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef _AUTH_HELPERS_H_
+#define _AUTH_HELPERS_H_
+
+#include <glib.h>
+#include <gtk/gtk.h>
+#include <gtk/gtkfilefilter.h>
+#include <glade/glade.h>
+
+#include <nm-connection.h>
+#include <nm-setting-vpn.h>
+
+typedef void (*ChangedCallback) (GtkWidget *widget, gpointer user_data);
+
+void tls_pw_init_auth_widget (GladeXML *xml,
+ GtkSizeGroup *group,
+ NMSettingVPN *s_vpn,
+ const char *contype,
+ const char *prefix,
+ ChangedCallback changed_cb,
+ gpointer user_data);
+
+void sk_init_auth_widget (GladeXML *xml,
+ GtkSizeGroup *group,
+ NMSettingVPN *s_vpn,
+ ChangedCallback changed_cb,
+ gpointer user_data);
+
+gboolean auth_widget_check_validity (GladeXML *xml, const char *contype, GError **error);
+
+gboolean auth_widget_update_connection (GladeXML *xml,
+ const char *contype,
+ NMSettingVPN *s_vpn);
+
+GtkFileFilter *tls_file_chooser_filter_new (void);
+
+GtkFileFilter *sk_file_chooser_filter_new (void);
+
+GtkWidget *advanced_dialog_new (GHashTable *hash, const char *contype);
+
+GHashTable *advanced_dialog_new_hash_from_connection (NMConnection *connection, GError **error);
+
+GHashTable *advanced_dialog_new_hash_from_dialog (GtkWidget *dialog, GError **error);
+
+#endif
diff --git a/vpn-daemons/openconnect/properties/nm-openconnect-dialog.glade b/vpn-daemons/openconnect/properties/nm-openconnect-dialog.glade
new file mode 100644
index 0000000..eea845d
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/nm-openconnect-dialog.glade
@@ -0,0 +1,683 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.gnome.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkWindow" id="openconnect-widget">
+ <property name="title" translatable="yes">window1</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_NORMAL</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="openconnect-vbox">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">16</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox8">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label22">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>General</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment8">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table2">
+ <property name="visible">True</property>
+ <property name="n_rows">1</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment2">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="gateway_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label23">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Gateway:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">gateway_entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox11">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label25">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes"><b>Authentication</b></property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment9">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table3">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment3">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkComboBox" id="auth_combo">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes"> </property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label26">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Type:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkNotebook" id="auth_notebook">
+ <property name="visible">True</property>
+ <property name="show_tabs">False</property>
+ <property name="show_border">False</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkTable" id="table1">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment6">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0.019999999553</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkFileChooserButton" id="cert_private_key_chooser">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Select A File</property>
+ <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+ <property name="local_only">True</property>
+ <property name="show_hidden">False</property>
+ <property name="do_overwrite_confirmation">False</property>
+ <property name="width_chars">-1</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment5">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkFileChooserButton" id="cert_user_cert_chooser">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Select A File</property>
+ <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+ <property name="local_only">True</property>
+ <property name="show_hidden">False</property>
+ <property name="do_overwrite_confirmation">False</property>
+ <property name="width_chars">-1</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment4">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkFileChooserButton" id="cert_ca_cert_chooser">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Select A File</property>
+ <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+ <property name="local_only">True</property>
+ <property name="show_hidden">False</property>
+ <property name="do_overwrite_confirmation">False</property>
+ <property name="width_chars">-1</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label2">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">CA Certificate:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label3">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">User Certificate:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label4">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Private Key:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label14">
+ <property name="visible">True</property>
+ <property name="label">page 1</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table4">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkFileChooserButton" id="pw_ca_cert_chooser">
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Select A File</property>
+ <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+ <property name="local_only">True</property>
+ <property name="show_hidden">False</property>
+ <property name="do_overwrite_confirmation">False</property>
+ <property name="width_chars">-1</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment7">
+ <property name="visible">True</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkEntry" id="pw_username_entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="invisible_char">•</property>
+ <property name="activates_default">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label5">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">User name:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label7">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">CA Certificate:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label15">
+ <property name="visible">True</property>
+ <property name="label">page 2</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/vpn-daemons/openconnect/properties/nm-openconnect.c b/vpn-daemons/openconnect/properties/nm-openconnect.c
new file mode 100644
index 0000000..30cd4c2
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/nm-openconnect.c
@@ -0,0 +1,502 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ * CVSID: $Id$
+ *
+ * nm-openconnect.c : GNOME UI dialogs for configuring openconnect VPN connections
+ *
+ * Copyright (C) 2005 David Zeuthen, <davidz redhat com>
+ * Copyright (C) 2005 - 2008 Dan Williams, <dcbw redhat com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <glib/gi18n-lib.h>
+#include <string.h>
+#include <gtk/gtk.h>
+#include <glade/glade.h>
+
+#define NM_VPN_API_SUBJECT_TO_CHANGE
+
+#include <nm-vpn-plugin-ui-interface.h>
+#include <nm-setting-vpn.h>
+#include <nm-setting-connection.h>
+#include <nm-setting-ip4-config.h>
+
+#include "../src/nm-openconnect-service.h"
+#include "nm-openconnect.h"
+#include "auth-helpers.h"
+
+#define OPENCONNECT_PLUGIN_NAME _("Cisco AnyConnect Compatible VPN (openconnect)")
+#define OPENCONNECT_PLUGIN_DESC _("Compatible with Cisco AnyConnect SSL VPN.")
+#define OPENCONNECT_PLUGIN_SERVICE NM_DBUS_SERVICE_OPENCONNECT
+
+
+/************** plugin class **************/
+
+static void openconnect_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class);
+
+G_DEFINE_TYPE_EXTENDED (OpenconnectPluginUi, openconnect_plugin_ui, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_INTERFACE,
+ openconnect_plugin_ui_interface_init))
+
+/************** UI widget class **************/
+
+static void openconnect_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class);
+
+G_DEFINE_TYPE_EXTENDED (OpenconnectPluginUiWidget, openconnect_plugin_ui_widget, G_TYPE_OBJECT, 0,
+ G_IMPLEMENT_INTERFACE (NM_TYPE_VPN_PLUGIN_UI_WIDGET_INTERFACE,
+ openconnect_plugin_ui_widget_interface_init))
+
+#define OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), OPENCONNECT_TYPE_PLUGIN_UI_WIDGET, OpenconnectPluginUiWidgetPrivate))
+
+typedef struct {
+ GladeXML *xml;
+ GtkWidget *widget;
+ GtkSizeGroup *group;
+ GtkWindowGroup *window_group;
+ gboolean window_added;
+} OpenconnectPluginUiWidgetPrivate;
+
+#define COL_AUTH_NAME 0
+#define COL_AUTH_PAGE 1
+#define COL_AUTH_TYPE 2
+
+GQuark
+openconnect_plugin_ui_error_quark (void)
+{
+ static GQuark error_quark = 0;
+
+ if (G_UNLIKELY (error_quark == 0))
+ error_quark = g_quark_from_static_string ("openconnect-plugin-ui-error-quark");
+
+ return error_quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+openconnect_plugin_ui_error_get_type (void)
+{
+ static GType etype = 0;
+
+ if (etype == 0) {
+ static const GEnumValue values[] = {
+ /* Unknown error. */
+ ENUM_ENTRY (OPENCONNECT_PLUGIN_UI_ERROR_UNKNOWN, "UnknownError"),
+ /* The specified property was invalid. */
+ ENUM_ENTRY (OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY, "InvalidProperty"),
+ /* The specified property was missing and is required. */
+ ENUM_ENTRY (OPENCONNECT_PLUGIN_UI_ERROR_MISSING_PROPERTY, "MissingProperty"),
+ { 0, 0, 0 }
+ };
+ etype = g_enum_register_static ("OpenconnectPluginUiError", values);
+ }
+ return etype;
+}
+
+static gboolean
+check_validity (OpenconnectPluginUiWidget *self, GError **error)
+{
+ OpenconnectPluginUiWidgetPrivate *priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ GtkWidget *widget;
+ const char *str;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ const char *contype = NULL;
+
+ widget = glade_xml_get_widget (priv->xml, "gateway_entry");
+ str = gtk_entry_get_text (GTK_ENTRY (widget));
+ if (!str || !strlen (str)) {
+ g_set_error (error,
+ OPENCONNECT_PLUGIN_UI_ERROR,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ NM_OPENCONNECT_KEY_GATEWAY);
+ return FALSE;
+ }
+
+ widget = glade_xml_get_widget (priv->xml, "auth_combo");
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+ g_assert (model);
+ g_assert (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter));
+
+ gtk_tree_model_get (model, &iter, COL_AUTH_TYPE, &contype, -1);
+ if (!auth_widget_check_validity (priv->xml, contype, error))
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+stuff_changed_cb (GtkWidget *widget, gpointer user_data)
+{
+ g_signal_emit_by_name (OPENCONNECT_PLUGIN_UI_WIDGET (user_data), "changed");
+}
+
+static void
+auth_combo_changed_cb (GtkWidget *combo, gpointer user_data)
+{
+ OpenconnectPluginUiWidget *self = OPENCONNECT_PLUGIN_UI_WIDGET (user_data);
+ OpenconnectPluginUiWidgetPrivate *priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ GtkWidget *auth_notebook;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gint new_page = 0;
+
+ auth_notebook = glade_xml_get_widget (priv->xml, "auth_notebook");
+ g_assert (auth_notebook);
+
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (combo));
+ g_assert (model);
+ g_assert (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (combo), &iter));
+
+ gtk_tree_model_get (model, &iter, COL_AUTH_PAGE, &new_page, -1);
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (auth_notebook), new_page);
+
+ stuff_changed_cb (combo, self);
+}
+
+static gboolean
+init_plugin_ui (OpenconnectPluginUiWidget *self, NMConnection *connection, GError **error)
+{
+ OpenconnectPluginUiWidgetPrivate *priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ NMSettingVPN *s_vpn;
+ GtkWidget *widget;
+ GtkListStore *store;
+ GtkTreeIter iter;
+ int active = -1;
+ const char *value;
+ const char *contype = NM_OPENCONNECT_AUTHTYPE_PASSWORD;
+
+ s_vpn = (NMSettingVPN *) nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN);
+
+ priv->group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
+
+ widget = glade_xml_get_widget (priv->xml, "gateway_entry");
+ if (!widget)
+ return FALSE;
+ gtk_size_group_add_widget (priv->group, widget);
+ if (s_vpn) {
+ value = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_GATEWAY);
+ if (value)
+ gtk_entry_set_text (GTK_ENTRY (widget), value);
+ }
+ g_signal_connect (G_OBJECT (widget), "changed", G_CALLBACK (stuff_changed_cb), self);
+
+ widget = glade_xml_get_widget (priv->xml, "auth_combo");
+ if (!widget)
+ return FALSE;
+ gtk_size_group_add_widget (priv->group, widget);
+
+ store = gtk_list_store_new (3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
+
+ if (s_vpn) {
+ contype = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_AUTHTYPE);
+ if (contype) {
+ if ( strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT)
+ && strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT_TPM)
+ && strcmp (contype, NM_OPENCONNECT_AUTHTYPE_PASSWORD))
+ contype = NM_OPENCONNECT_AUTHTYPE_PASSWORD;
+ } else
+ contype = NM_OPENCONNECT_AUTHTYPE_PASSWORD;
+ }
+
+ /* SecurID/password auth widget */
+ tls_pw_init_auth_widget (priv->xml, priv->group, s_vpn,
+ NM_OPENCONNECT_AUTHTYPE_PASSWORD, "pw",
+ stuff_changed_cb, self);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_AUTH_NAME, _("Password / SecurID"),
+ COL_AUTH_PAGE, 1,
+ COL_AUTH_TYPE, NM_OPENCONNECT_AUTHTYPE_PASSWORD,
+ -1);
+
+ /* Certificate auth widget */
+ tls_pw_init_auth_widget (priv->xml, priv->group, s_vpn,
+ NM_OPENCONNECT_AUTHTYPE_CERT, "cert",
+ stuff_changed_cb, self);
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_AUTH_NAME, _("Certificate (TLS)"),
+ COL_AUTH_PAGE, 0,
+ COL_AUTH_TYPE, NM_OPENCONNECT_AUTHTYPE_CERT,
+ -1);
+ if ((active < 0) && !strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT))
+ active = 1;
+
+ gtk_list_store_append (store, &iter);
+ gtk_list_store_set (store, &iter,
+ COL_AUTH_NAME, _("Certificate (TLS) with TPM"),
+ COL_AUTH_PAGE, 0,
+ COL_AUTH_TYPE, NM_OPENCONNECT_AUTHTYPE_CERT_TPM,
+ -1);
+ if ((active < 0) && !strcmp (contype, NM_OPENCONNECT_AUTHTYPE_CERT_TPM))
+ active = 2;
+
+ gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
+ g_object_unref (store);
+ g_signal_connect (widget, "changed", G_CALLBACK (auth_combo_changed_cb), self);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget), active < 0 ? 0 : active);
+
+ return TRUE;
+}
+
+static GObject *
+get_widget (NMVpnPluginUiWidgetInterface *iface)
+{
+ OpenconnectPluginUiWidget *self = OPENCONNECT_PLUGIN_UI_WIDGET (iface);
+ OpenconnectPluginUiWidgetPrivate *priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+
+ return G_OBJECT (priv->widget);
+}
+
+static gboolean
+update_connection (NMVpnPluginUiWidgetInterface *iface,
+ NMConnection *connection,
+ GError **error)
+{
+ OpenconnectPluginUiWidget *self = OPENCONNECT_PLUGIN_UI_WIDGET (iface);
+ OpenconnectPluginUiWidgetPrivate *priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (self);
+ NMSettingVPN *s_vpn;
+ GtkWidget *widget;
+ char *str;
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean valid = FALSE;
+ const char *auth_type = NULL;
+
+ if (!check_validity (self, error))
+ return FALSE;
+
+ s_vpn = NM_SETTING_VPN (nm_setting_vpn_new ());
+ g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, NM_DBUS_SERVICE_OPENCONNECT, NULL);
+
+ /* Gateway */
+ widget = glade_xml_get_widget (priv->xml, "gateway_entry");
+ str = (char *) gtk_entry_get_text (GTK_ENTRY (widget));
+ if (str && strlen (str))
+ nm_setting_vpn_add_data_item (s_vpn, NM_OPENCONNECT_KEY_GATEWAY, str);
+
+ widget = glade_xml_get_widget (priv->xml, "auth_combo");
+ model = gtk_combo_box_get_model (GTK_COMBO_BOX (widget));
+ if (gtk_combo_box_get_active_iter (GTK_COMBO_BOX (widget), &iter)) {
+ gtk_tree_model_get (model, &iter, COL_AUTH_TYPE, &auth_type, -1);
+ nm_setting_vpn_add_data_item (s_vpn, NM_OPENCONNECT_KEY_AUTHTYPE, auth_type);
+ auth_widget_update_connection (priv->xml, auth_type, s_vpn);
+ }
+
+ nm_connection_add_setting (connection, NM_SETTING (s_vpn));
+ valid = TRUE;
+
+done:
+ return valid;
+}
+
+static gboolean
+save_secrets (NMVpnPluginUiWidgetInterface *iface,
+ NMConnection *connection,
+ GError **error)
+{
+ return TRUE;
+}
+
+
+static NMVpnPluginUiWidgetInterface *
+nm_vpn_plugin_ui_widget_interface_new (NMConnection *connection, GError **error)
+{
+ NMVpnPluginUiWidgetInterface *object;
+ OpenconnectPluginUiWidgetPrivate *priv;
+ char *glade_file;
+
+ if (error)
+ g_return_val_if_fail (*error == NULL, NULL);
+
+ object = NM_VPN_PLUGIN_UI_WIDGET_INTERFACE (g_object_new (OPENCONNECT_TYPE_PLUGIN_UI_WIDGET, NULL));
+ if (!object) {
+ g_set_error (error, OPENCONNECT_PLUGIN_UI_ERROR, 0, "could not create openconnect object");
+ return NULL;
+ }
+
+ priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (object);
+
+ glade_file = g_strdup_printf ("%s/%s", GLADEDIR, "nm-openconnect-dialog.glade");
+ priv->xml = glade_xml_new (glade_file, "openconnect-vbox", GETTEXT_PACKAGE);
+ if (priv->xml == NULL) {
+ g_set_error (error, OPENCONNECT_PLUGIN_UI_ERROR, 0,
+ "could not load required resources at %s", glade_file);
+ g_free (glade_file);
+ g_object_unref (object);
+ return NULL;
+ }
+ g_free (glade_file);
+
+ priv->widget = glade_xml_get_widget (priv->xml, "openconnect-vbox");
+ if (!priv->widget) {
+ g_set_error (error, OPENCONNECT_PLUGIN_UI_ERROR, 0, "could not load UI widget");
+ g_object_unref (object);
+ return NULL;
+ }
+ g_object_ref_sink (priv->widget);
+
+ priv->window_group = gtk_window_group_new ();
+
+ if (!init_plugin_ui (OPENCONNECT_PLUGIN_UI_WIDGET (object), connection, error)) {
+ g_object_unref (object);
+ return NULL;
+ }
+
+ return object;
+}
+
+static void
+dispose (GObject *object)
+{
+ OpenconnectPluginUiWidget *plugin = OPENCONNECT_PLUGIN_UI_WIDGET (object);
+ OpenconnectPluginUiWidgetPrivate *priv = OPENCONNECT_PLUGIN_UI_WIDGET_GET_PRIVATE (plugin);
+
+ if (priv->group)
+ g_object_unref (priv->group);
+
+ if (priv->window_group)
+ g_object_unref (priv->window_group);
+
+ if (priv->widget)
+ g_object_unref (priv->widget);
+
+ if (priv->xml)
+ g_object_unref (priv->xml);
+
+ G_OBJECT_CLASS (openconnect_plugin_ui_widget_parent_class)->dispose (object);
+}
+
+static void
+openconnect_plugin_ui_widget_class_init (OpenconnectPluginUiWidgetClass *req_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+ g_type_class_add_private (req_class, sizeof (OpenconnectPluginUiWidgetPrivate));
+
+ object_class->dispose = dispose;
+}
+
+static void
+openconnect_plugin_ui_widget_init (OpenconnectPluginUiWidget *plugin)
+{
+}
+
+static void
+openconnect_plugin_ui_widget_interface_init (NMVpnPluginUiWidgetInterface *iface_class)
+{
+ /* interface implementation */
+ iface_class->get_widget = get_widget;
+ iface_class->update_connection = update_connection;
+ iface_class->save_secrets = save_secrets;
+}
+
+static gboolean
+delete_connection (NMVpnPluginUiInterface *iface,
+ NMConnection *connection,
+ GError **error)
+{
+ return TRUE;
+}
+
+static guint32
+get_capabilities (NMVpnPluginUiInterface *iface)
+{
+ return 0;
+}
+
+static NMVpnPluginUiWidgetInterface *
+ui_factory (NMVpnPluginUiInterface *iface, NMConnection *connection, GError **error)
+{
+ return nm_vpn_plugin_ui_widget_interface_new (connection, error);
+}
+
+static void
+get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ switch (prop_id) {
+ case NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME:
+ g_value_set_string (value, OPENCONNECT_PLUGIN_NAME);
+ break;
+ case NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC:
+ g_value_set_string (value, OPENCONNECT_PLUGIN_DESC);
+ break;
+ case NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE:
+ g_value_set_string (value, OPENCONNECT_PLUGIN_SERVICE);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+openconnect_plugin_ui_class_init (OpenconnectPluginUiClass *req_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+
+ object_class->get_property = get_property;
+
+ g_object_class_override_property (object_class,
+ NM_VPN_PLUGIN_UI_INTERFACE_PROP_NAME,
+ NM_VPN_PLUGIN_UI_INTERFACE_NAME);
+
+ g_object_class_override_property (object_class,
+ NM_VPN_PLUGIN_UI_INTERFACE_PROP_DESC,
+ NM_VPN_PLUGIN_UI_INTERFACE_DESC);
+
+ g_object_class_override_property (object_class,
+ NM_VPN_PLUGIN_UI_INTERFACE_PROP_SERVICE,
+ NM_VPN_PLUGIN_UI_INTERFACE_SERVICE);
+}
+
+static void
+openconnect_plugin_ui_init (OpenconnectPluginUi *plugin)
+{
+}
+
+static void
+openconnect_plugin_ui_interface_init (NMVpnPluginUiInterface *iface_class)
+{
+ /* interface implementation */
+ iface_class->ui_factory = ui_factory;
+ iface_class->get_capabilities = get_capabilities;
+ iface_class->delete_connection = delete_connection;
+}
+
+G_MODULE_EXPORT NMVpnPluginUiInterface *
+nm_vpn_plugin_ui_factory (GError **error)
+{
+ if (error)
+ g_return_val_if_fail (*error == NULL, NULL);
+
+ return NM_VPN_PLUGIN_UI_INTERFACE (g_object_new (OPENCONNECT_TYPE_PLUGIN_UI, NULL));
+}
+
diff --git a/vpn-daemons/openconnect/properties/nm-openconnect.h b/vpn-daemons/openconnect/properties/nm-openconnect.h
new file mode 100644
index 0000000..59c79a7
--- /dev/null
+++ b/vpn-daemons/openconnect/properties/nm-openconnect.h
@@ -0,0 +1,84 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/***************************************************************************
+ * nm-openconnect.h : GNOME UI dialogs for configuring openconnect VPN connections
+ *
+ * Copyright (C) 2008 Dan Williams, <dcbw redhat com>
+ *
+ * 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.
+ *
+ **************************************************************************/
+
+#ifndef _NM_OPENCONNECT_H_
+#define _NM_OPENCONNECT_H_
+
+#include <glib-object.h>
+
+typedef enum
+{
+ OPENCONNECT_PLUGIN_UI_ERROR_UNKNOWN = 0,
+ OPENCONNECT_PLUGIN_UI_ERROR_INVALID_PROPERTY,
+ OPENCONNECT_PLUGIN_UI_ERROR_MISSING_PROPERTY
+} OpenconnectPluginUiError;
+
+
+GQuark openconnect_plugin_ui_error_quark (void);
+#define OPENCONNECT_PLUGIN_UI_ERROR openconnect_plugin_ui_error_quark ()
+
+#define OPENCONNECT_TYPE_PLUGIN_UI_ERROR (openconnect_plugin_ui_error_get_type ())
+GType openconnect_plugin_ui_error_get_type (void);
+
+#define OPENCONNECT_TYPE_PLUGIN_UI (openconnect_plugin_ui_get_type ())
+#define OPENCONNECT_PLUGIN_UI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OPENCONNECT_TYPE_PLUGIN_UI, OpenconnectPluginUi))
+#define OPENCONNECT_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OPENCONNECT_TYPE_PLUGIN_UI, OpenconnectPluginUiClass))
+#define OPENCONNECT_IS_PLUGIN_UI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OPENCONNECT_TYPE_PLUGIN_UI))
+#define OPENCONNECT_IS_PLUGIN_UI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), OPENCONNECT_TYPE_PLUGIN_UI))
+#define OPENCONNECT_PLUGIN_UI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OPENCONNECT_TYPE_PLUGIN_UI, OpenconnectPluginUiClass))
+
+typedef struct _OpenconnectPluginUi OpenconnectPluginUi;
+typedef struct _OpenconnectPluginUiClass OpenconnectPluginUiClass;
+
+struct _OpenconnectPluginUi {
+ GObject parent;
+};
+
+struct _OpenconnectPluginUiClass {
+ GObjectClass parent;
+};
+
+GType openconnect_plugin_ui_get_type (void);
+
+
+#define OPENCONNECT_TYPE_PLUGIN_UI_WIDGET (openconnect_plugin_ui_widget_get_type ())
+#define OPENCONNECT_PLUGIN_UI_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), OPENCONNECT_TYPE_PLUGIN_UI_WIDGET, OpenconnectPluginUiWidget))
+#define OPENCONNECT_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), OPENCONNECT_TYPE_PLUGIN_UI_WIDGET, OpenconnectPluginUiWidgetClass))
+#define OPENCONNECT_IS_PLUGIN_UI_WIDGET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), OPENCONNECT_TYPE_PLUGIN_UI_WIDGET))
+#define OPENCONNECT_IS_PLUGIN_UI_WIDGET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), OPENCONNECT_TYPE_PLUGIN_UI_WIDGET))
+#define OPENCONNECT_PLUGIN_UI_WIDGET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), OPENCONNECT_TYPE_PLUGIN_UI_WIDGET, OpenconnectPluginUiWidgetClass))
+
+typedef struct _OpenconnectPluginUiWidget OpenconnectPluginUiWidget;
+typedef struct _OpenconnectPluginUiWidgetClass OpenconnectPluginUiWidgetClass;
+
+struct _OpenconnectPluginUiWidget {
+ GObject parent;
+};
+
+struct _OpenconnectPluginUiWidgetClass {
+ GObjectClass parent;
+};
+
+GType openconnect_plugin_ui_widget_get_type (void);
+
+#endif /* _NM_OPENCONNECT_H_ */
+
diff --git a/vpn-daemons/openconnect/src/.cvsignore b/vpn-daemons/openconnect/src/.cvsignore
new file mode 100644
index 0000000..dc66b2e
--- /dev/null
+++ b/vpn-daemons/openconnect/src/.cvsignore
@@ -0,0 +1,4 @@
+Makefile.in
+Makefile
+nm-openconnect-service
+nm-openconnect-service-openconnect-helper
diff --git a/vpn-daemons/openconnect/src/Makefile.am b/vpn-daemons/openconnect/src/Makefile.am
new file mode 100644
index 0000000..2351efc
--- /dev/null
+++ b/vpn-daemons/openconnect/src/Makefile.am
@@ -0,0 +1,40 @@
+INCLUDES = -I${top_srcdir}
+
+AM_CPPFLAGS = \
+ $(DBUS_CFLAGS) \
+ $(GTHREAD_CFLAGS) \
+ $(NM_UTILS_CFLAGS) \
+ -DDBUS_API_SUBJECT_TO_CHANGE \
+ -DG_DISABLE_DEPRECATED \
+ -DBINDIR=\"$(bindir)\" \
+ -DPREFIX=\""$(prefix)"\" \
+ -DSYSCONFDIR=\""$(sysconfdir)"\" \
+ -DVERSION="\"$(VERSION)\"" \
+ -DLIBDIR=\""$(libdir)"\" \
+ -DLIBEXECDIR=\""$(libexecdir)"\" \
+ -DLOCALSTATEDIR=\""$(localstatedir)"\" \
+ -DDATADIR=\"$(datadir)\"
+
+libexec_PROGRAMS = nm-openconnect-service nm-openconnect-service-openconnect-helper
+
+nm_openconnect_service_SOURCES = \
+ nm-openconnect-service.c \
+ nm-openconnect-service.h
+
+
+nm_openconnect_service_LDADD = \
+ $(DBUS_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(NM_UTILS_LIBS) \
+ -lnm_glib_vpn
+
+
+nm_openconnect_service_openconnect_helper_SOURCES = \
+ nm-openconnect-service-openconnect-helper.c
+
+nm_openconnect_service_openconnect_helper_LDADD = \
+ $(DBUS_LIBS) \
+ $(GTHREAD_LIBS) \
+ $(NM_UTILS_LIBS)
+
+CLEANFILES = *~
diff --git a/vpn-daemons/openconnect/src/nm-openconnect-service-openconnect-helper.c b/vpn-daemons/openconnect/src/nm-openconnect-service-openconnect-helper.c
new file mode 100644
index 0000000..b2e9a1d
--- /dev/null
+++ b/vpn-daemons/openconnect/src/nm-openconnect-service-openconnect-helper.c
@@ -0,0 +1,380 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+/* nm-openconnect-service - openconnect integration with NetworkManager
+ *
+ * Dan Williams <dcbw redhat com>
+ *
+ * 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.
+ *
+ * (C) Copyright 2005 Red Hat, Inc.
+ */
+
+#include <glib.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib-lowlevel.h>
+#include <dbus/dbus-glib.h>
+#include <NetworkManager.h>
+
+#include "nm-openconnect-service.h"
+#include "nm-utils.h"
+
+/* These are here because nm-dbus-glib-types.h isn't exported */
+#define DBUS_TYPE_G_ARRAY_OF_UINT (dbus_g_type_get_collection ("GArray", G_TYPE_UINT))
+#define DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT (dbus_g_type_get_collection ("GPtrArray", DBUS_TYPE_G_ARRAY_OF_UINT))
+
+static void
+helper_failed (DBusGConnection *connection, const char *reason)
+{
+ DBusGProxy *proxy;
+ GError *err = NULL;
+
+ nm_warning ("nm-nopenconnect-service-openconnect-helper did not receive a valid %s from openconnect", reason);
+
+ proxy = dbus_g_proxy_new_for_name (connection,
+ NM_DBUS_SERVICE_OPENCONNECT,
+ NM_VPN_DBUS_PLUGIN_PATH,
+ NM_VPN_DBUS_PLUGIN_INTERFACE);
+
+ dbus_g_proxy_call (proxy, "SetFailure", &err,
+ G_TYPE_STRING, reason,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (err) {
+ nm_warning ("Could not send failure information: %s", err->message);
+ g_error_free (err);
+ }
+
+ g_object_unref (proxy);
+
+ exit (1);
+}
+
+static void
+send_ip4_config (DBusGConnection *connection, GHashTable *config)
+{
+ DBusGProxy *proxy;
+ GError *err = NULL;
+
+ proxy = dbus_g_proxy_new_for_name (connection,
+ NM_DBUS_SERVICE_OPENCONNECT,
+ NM_VPN_DBUS_PLUGIN_PATH,
+ NM_VPN_DBUS_PLUGIN_INTERFACE);
+
+ dbus_g_proxy_call (proxy, "SetIp4Config", &err,
+ dbus_g_type_get_map ("GHashTable", G_TYPE_STRING, G_TYPE_VALUE),
+ config,
+ G_TYPE_INVALID,
+ G_TYPE_INVALID);
+
+ if (err) {
+ nm_warning ("Could not send failure information: %s", err->message);
+ g_error_free (err);
+ }
+
+ g_object_unref (proxy);
+}
+
+static GValue *
+str_to_gvalue (const char *str, gboolean try_convert)
+{
+ GValue *val;
+
+ /* Empty */
+ if (!str || strlen (str) < 1)
+ return NULL;
+
+ if (!g_utf8_validate (str, -1, NULL)) {
+ if (try_convert && !(str = g_convert (str, -1, "ISO-8859-1", "UTF-8", NULL, NULL, NULL)))
+ str = g_convert (str, -1, "C", "UTF-8", NULL, NULL, NULL);
+
+ if (!str)
+ /* Invalid */
+ return NULL;
+ }
+
+ val = g_slice_new0 (GValue);
+ g_value_init (val, G_TYPE_STRING);
+ g_value_set_string (val, str);
+
+ return val;
+}
+
+static GValue *
+uint_to_gvalue (guint32 num)
+{
+ GValue *val;
+
+ if (num == 0)
+ return NULL;
+
+ val = g_slice_new0 (GValue);
+ g_value_init (val, G_TYPE_UINT);
+ g_value_set_uint (val, num);
+
+ return val;
+}
+
+static GValue *
+addr_to_gvalue (const char *str)
+{
+ struct in_addr temp_addr;
+
+ /* Empty */
+ if (!str || strlen (str) < 1)
+ return NULL;
+
+ if (inet_pton (AF_INET, str, &temp_addr) <= 0)
+ return NULL;
+
+ return uint_to_gvalue (temp_addr.s_addr);
+}
+
+static GValue *
+addr_list_to_gvalue (const char *str)
+{
+ GValue *val;
+ char **split;
+ int i;
+ GArray *array;
+
+ /* Empty */
+ if (!str || strlen (str) < 1)
+ return NULL;
+
+ split = g_strsplit (str, " ", -1);
+ if (g_strv_length (split) == 0)
+ return NULL;
+
+ array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), g_strv_length (split));
+ for (i = 0; split[i]; i++) {
+ struct in_addr addr;
+
+ if (inet_pton (AF_INET, split[i], &addr) > 0) {
+ g_array_append_val (array, addr.s_addr);
+ } else {
+ g_strfreev (split);
+ g_array_free (array, TRUE);
+ return NULL;
+ }
+ }
+
+ g_strfreev (split);
+
+ val = g_slice_new0 (GValue);
+ g_value_init (val, DBUS_TYPE_G_UINT_ARRAY);
+ g_value_set_boxed (val, array);
+
+ return val;
+}
+
+static GValue *
+get_routes (void)
+{
+ GValue *value = NULL;
+ GPtrArray *routes;
+ char *tmp;
+ int num;
+ int i;
+
+#define BUFLEN 256
+
+ tmp = getenv ("CISCO_SPLIT_INC");
+ if (!tmp || strlen (tmp) < 1)
+ return NULL;
+
+ num = atoi (tmp);
+ if (!num)
+ return NULL;
+
+ routes = g_ptr_array_new ();
+
+ for (i = 0; i < num; i++) {
+ GArray *array;
+ char buf[BUFLEN];
+ struct in_addr network;
+ guint32 next_hop = 0; /* no next hop */
+ guint32 prefix, metric = 0;
+
+ snprintf (buf, BUFLEN, "CISCO_SPLIT_INC_%d_ADDR", i);
+ tmp = getenv (buf);
+ if (!tmp || inet_pton (AF_INET, tmp, &network) <= 0) {
+ nm_warning ("Ignoring invalid static route address '%s'", tmp ? tmp : "NULL");
+ continue;
+ }
+
+ snprintf (buf, BUFLEN, "CISCO_SPLIT_INC_%d_MASKLEN", i);
+ tmp = getenv (buf);
+ if (tmp) {
+ long int tmp_prefix;
+
+ errno = 0;
+ tmp_prefix = strtol (tmp, NULL, 10);
+ if (errno || tmp_prefix <= 0 || tmp_prefix > 32) {
+ nm_warning ("Ignoring invalid static route prefix '%s'", tmp ? tmp : "NULL");
+ continue;
+ }
+ prefix = (guint32) tmp_prefix;
+ } else {
+ struct in_addr netmask;
+
+ snprintf (buf, BUFLEN, "CISCO_SPLIT_INC_%d_MASK", i);
+ tmp = getenv (buf);
+ if (!tmp || inet_pton (AF_INET, tmp, &netmask) <= 0) {
+ nm_warning ("Ignoring invalid static route netmask '%s'", tmp ? tmp : "NULL");
+ continue;
+ }
+ prefix = nm_utils_ip4_netmask_to_prefix (netmask.s_addr);
+ }
+
+ array = g_array_sized_new (FALSE, TRUE, sizeof (guint32), 4);
+ g_array_append_val (array, network.s_addr);
+ g_array_append_val (array, prefix);
+ g_array_append_val (array, next_hop);
+ g_array_append_val (array, metric);
+ g_ptr_array_add (routes, array);
+ }
+
+ if (routes->len > 0) {
+ value = g_new0 (GValue, 1);
+ g_value_init (value, DBUS_TYPE_G_ARRAY_OF_ARRAY_OF_UINT);
+ g_value_take_boxed (value, routes);
+ } else
+ g_ptr_array_free (routes, TRUE);
+
+ return value;
+}
+
+/*
+ * Environment variables passed back from 'openconnect':
+ *
+ * VPNGATEWAY -- vpn gateway address (always present)
+ * TUNDEV -- tunnel device (always present)
+ * INTERNAL_IP4_ADDRESS -- address (always present)
+ * INTERNAL_IP4_NETMASK -- netmask (often unset)
+ * INTERNAL_IP4_DNS -- list of dns serverss
+ * INTERNAL_IP4_NBNS -- list of wins servers
+ * CISCO_DEF_DOMAIN -- default domain name
+ * CISCO_BANNER -- banner from server
+ *
+ */
+int
+main (int argc, char *argv[])
+{
+ DBusGConnection *connection;
+ char *tmp;
+ GHashTable *config;
+ GValue *val;
+ GError *err = NULL;
+ struct in_addr temp_addr;
+
+ g_type_init ();
+
+ /* openconnect gives us a "reason" code. If we are given one,
+ * don't proceed unless its "connect".
+ */
+ tmp = getenv ("reason");
+ if (tmp && strcmp (tmp, "connect") != 0)
+ exit (0);
+
+ connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
+ if (!connection) {
+ nm_warning ("Could not get the system bus: %s", err->message);
+ exit (1);
+ }
+
+ config = g_hash_table_new (g_str_hash, g_str_equal);
+
+ /* Gateway */
+ val = addr_to_gvalue (getenv ("VPNGATEWAY"));
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_GATEWAY, val);
+ else
+ helper_failed (connection, "VPN Gateway");
+
+ /* Tunnel device */
+ val = str_to_gvalue (getenv ("TUNDEV"), FALSE);
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, val);
+ else
+ helper_failed (connection, "Tunnel Device");
+
+ /* IP address */
+ val = addr_to_gvalue (getenv ("INTERNAL_IP4_ADDRESS"));
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val);
+ else
+ helper_failed (connection, "IP4 Address");
+
+ /* PTP address; for openconnect PTP address == internal IP4 address */
+ val = addr_to_gvalue (getenv ("INTERNAL_IP4_ADDRESS"));
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_PTP, val);
+ else
+ helper_failed (connection, "IP4 PTP Address");
+
+ /* Netmask */
+ tmp = getenv ("INTERNAL_IP4_NETMASK");
+ if (tmp && inet_pton (AF_INET, tmp, &temp_addr) > 0) {
+ GValue *val;
+
+ val = g_slice_new0 (GValue);
+ g_value_init (val, G_TYPE_UINT);
+ g_value_set_uint (val, nm_utils_ip4_netmask_to_prefix (temp_addr.s_addr));
+
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val);
+ }
+
+ /* DNS */
+ val = addr_list_to_gvalue (getenv ("INTERNAL_IP4_DNS"));
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_DNS, val);
+
+ /* WINS servers */
+ val = addr_list_to_gvalue (getenv ("INTERNAL_IP4_NBNS"));
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_NBNS, val);
+
+ /* Default domain */
+ val = str_to_gvalue (getenv ("CISCO_DEF_DOMAIN"), TRUE);
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_DOMAIN, val);
+
+ /* Routes */
+ val = get_routes ();
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, val);
+
+ /* Banner */
+ val = str_to_gvalue (getenv ("CISCO_BANNER"), TRUE);
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_BANNER, val);
+
+ /* MTU */
+ val = str_to_gvalue (getenv ("INTERNAL_IP4_MTU"), TRUE);
+ if (val)
+ g_hash_table_insert (config, NM_VPN_PLUGIN_IP4_CONFIG_MTU, val);
+
+ /* Send the config info to nm-openconnect-service */
+ send_ip4_config (connection, config);
+
+ exit (0);
+}
diff --git a/vpn-daemons/openconnect/src/nm-openconnect-service.c b/vpn-daemons/openconnect/src/nm-openconnect-service.c
new file mode 100644
index 0000000..8c7fd3a
--- /dev/null
+++ b/vpn-daemons/openconnect/src/nm-openconnect-service.c
@@ -0,0 +1,562 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+#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 <errno.h>
+#include <sys/ioctl.h>
+#include <linux/if_tun.h>
+#include <net/if.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <nm-setting-vpn.h>
+#include "nm-openconnect-service.h"
+#include "nm-utils.h"
+
+G_DEFINE_TYPE (NMOPENCONNECTPlugin, nm_openconnect_plugin, NM_TYPE_VPN_PLUGIN)
+
+typedef struct {
+ GPid pid;
+} NMOPENCONNECTPluginPrivate;
+
+#define NM_OPENCONNECT_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_OPENCONNECT_PLUGIN, NMOPENCONNECTPluginPrivate))
+
+static const char *openconnect_binary_paths[] =
+{
+ "/usr/bin/openconnect",
+ "/usr/local/bin/openconnect",
+ "/opt/bin/openconnect",
+ NULL
+};
+
+#define NM_OPENCONNECT_HELPER_PATH LIBEXECDIR"/nm-openconnect-service-openconnect-helper"
+#define NM_OPENCONNECT_UDP_ENCAPSULATION_PORT 0 /* random port */
+
+typedef struct {
+ const char *name;
+ GType type;
+ gint int_min;
+ gint int_max;
+} ValidProperty;
+
+static ValidProperty valid_properties[] = {
+ { NM_OPENCONNECT_KEY_GATEWAY, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_CACERT, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_AUTHTYPE, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_USERCERT, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_USERNAME, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_XMLCONFIG, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_PRIVKEY, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_CERTSIGS, G_TYPE_STRING, 0, 0 },
+ { NULL, G_TYPE_NONE, 0, 0 }
+};
+
+static ValidProperty valid_secrets[] = {
+ { NM_OPENCONNECT_KEY_COOKIE, G_TYPE_STRING, 0, 0 },
+ { NM_OPENCONNECT_KEY_GATEWAY, G_TYPE_STRING, 0, 0 },
+ { NULL, G_TYPE_NONE, 0, 0 }
+};
+
+static uid_t tun_owner;
+static gid_t tun_group;
+static char *tun_name = NULL;
+
+typedef struct ValidateInfo {
+ ValidProperty *table;
+ GError **error;
+ gboolean have_items;
+} ValidateInfo;
+
+static void
+validate_one_property (const char *key, const char *value, gpointer user_data)
+{
+ ValidateInfo *info = (ValidateInfo *) user_data;
+ int i;
+
+ if (*(info->error))
+ return;
+
+ info->have_items = TRUE;
+
+ /* 'name' is the setting name; always allowed but unused */
+ if (!strcmp (key, NM_SETTING_NAME))
+ return;
+
+ for (i = 0; info->table[i].name; i++) {
+ ValidProperty prop = info->table[i];
+ long int tmp;
+
+ if (strcmp (prop.name, key))
+ continue;
+
+ switch (prop.type) {
+ case G_TYPE_STRING:
+ return; /* valid */
+ case G_TYPE_INT:
+ errno = 0;
+ tmp = strtol (value, NULL, 10);
+ if (errno == 0 && tmp >= prop.int_min && tmp <= prop.int_max)
+ return; /* valid */
+
+ g_set_error (info->error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "invalid integer property '%s' or out of range [%d -> %d]",
+ key, prop.int_min, prop.int_max);
+ break;
+ case G_TYPE_BOOLEAN:
+ if (!strcmp (value, "yes") || !strcmp (value, "no"))
+ return; /* valid */
+
+ g_set_error (info->error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "invalid boolean property '%s' (not yes or no)",
+ key);
+ break;
+ default:
+ g_set_error (info->error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "unhandled property '%s' type %s",
+ key, g_type_name (prop.type));
+ break;
+ }
+ }
+
+ /* Did not find the property from valid_properties or the type did not match */
+ if (!info->table[i].name) {
+ g_set_error (info->error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "property '%s' invalid or not supported",
+ key);
+ }
+}
+
+static gboolean
+nm_openconnect_properties_validate (NMSettingVPN *s_vpn, GError **error)
+{
+ ValidateInfo info = { &valid_properties[0], error, FALSE };
+
+ nm_setting_vpn_foreach_data_item (s_vpn, validate_one_property, &info);
+ if (!info.have_items) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "%s",
+ "No VPN configuration options.");
+ return FALSE;
+ }
+
+ return *error ? FALSE : TRUE;
+}
+
+static gboolean
+nm_openconnect_secrets_validate (NMSettingVPN *s_vpn, GError **error)
+{
+ ValidateInfo info = { &valid_secrets[0], error, FALSE };
+
+ nm_setting_vpn_foreach_secret (s_vpn, validate_one_property, &info);
+ if (!info.have_items) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
+ "%s",
+ "No VPN secrets!");
+ return FALSE;
+ }
+
+ return *error ? FALSE : TRUE;
+}
+
+static void openconnect_drop_child_privs(gpointer user_data)
+{
+ if (tun_name) {
+ initgroups(NM_OPENCONNECT_USER, tun_group);
+ setuid((uid_t)tun_owner);
+ }
+}
+
+static void
+openconnect_watch_cb (GPid pid, gint status, gpointer user_data)
+{
+ NMOPENCONNECTPlugin *plugin = NM_OPENCONNECT_PLUGIN (user_data);
+ NMOPENCONNECTPluginPrivate *priv = NM_OPENCONNECT_PLUGIN_GET_PRIVATE (plugin);
+ guint error = 0;
+
+ if (WIFEXITED (status)) {
+ error = WEXITSTATUS (status);
+ if (error != 0)
+ nm_warning ("openconnect exited with error code %d", error);
+ }
+ else if (WIFSTOPPED (status))
+ nm_warning ("openconnect stopped unexpectedly with signal %d", WSTOPSIG (status));
+ else if (WIFSIGNALED (status))
+ nm_warning ("openconnect died with signal %d", WTERMSIG (status));
+ else
+ nm_warning ("openconnect died from an unknown cause");
+
+ /* Reap child if needed. */
+ waitpid (priv->pid, NULL, WNOHANG);
+ priv->pid = 0;
+
+ /* Must be after data->state is set since signals use data->state */
+ switch (error) {
+ case 2:
+ /* Couldn't log in due to bad user/pass */
+ nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_LOGIN_FAILED);
+ break;
+ case 1:
+ /* Other error (couldn't bind to address, etc) */
+ nm_vpn_plugin_failure (NM_VPN_PLUGIN (plugin), NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED);
+ break;
+ default:
+ break;
+ }
+
+ nm_vpn_plugin_set_state (NM_VPN_PLUGIN (plugin), NM_VPN_SERVICE_STATE_STOPPED);
+}
+
+static gint
+nm_openconnect_start_openconnect_binary (NMOPENCONNECTPlugin *plugin,
+ NMSettingVPN *s_vpn,
+ GError **error)
+{
+ GPid pid;
+ const char **openconnect_binary = NULL;
+ GPtrArray *openconnect_argv;
+ GSource *openconnect_watch;
+ gint stdin_fd;
+ const char *props_vpn_gw, *props_cookie, *props_cacert;
+
+ /* Find openconnect */
+ openconnect_binary = openconnect_binary_paths;
+ while (*openconnect_binary != NULL) {
+ if (g_file_test (*openconnect_binary, G_FILE_TEST_EXISTS))
+ break;
+ openconnect_binary++;
+ }
+
+ if (!*openconnect_binary) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+ "%s",
+ "Could not find openconnect binary.");
+ return -1;
+ }
+
+ /* The actual gateway to use (after redirection) comes from the auth
+ dialog, so it's in the secrets hash not the properties */
+ props_vpn_gw = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_GATEWAY);
+ if (!props_vpn_gw || !strlen (props_vpn_gw) ) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+ "%s",
+ "No VPN gateway specified.");
+ return -1;
+ }
+
+ props_cookie = nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_COOKIE);
+ if (!props_cookie || !strlen (props_cookie)) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED,
+ "%s",
+ "No WebVPN cookie provided.");
+ return -1;
+ }
+
+ props_cacert = nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_CACERT);
+
+ openconnect_argv = g_ptr_array_new ();
+ g_ptr_array_add (openconnect_argv, (gpointer) (*openconnect_binary));
+
+ if (props_cacert && strlen(props_cacert)) {
+ g_ptr_array_add (openconnect_argv, (gpointer) "--cafile");
+ g_ptr_array_add (openconnect_argv, (gpointer) props_cacert);
+ }
+
+ g_ptr_array_add (openconnect_argv, (gpointer) "--syslog");
+ g_ptr_array_add (openconnect_argv, (gpointer) "--cookie-on-stdin");
+
+ g_ptr_array_add (openconnect_argv, (gpointer) "--script");
+ g_ptr_array_add (openconnect_argv, (gpointer) NM_OPENCONNECT_HELPER_PATH);
+
+ if (tun_name) {
+ g_ptr_array_add (openconnect_argv, (gpointer) "--interface");
+ g_ptr_array_add (openconnect_argv, (gpointer) tun_name);
+ }
+
+ g_ptr_array_add (openconnect_argv, (gpointer) props_vpn_gw);
+
+ g_ptr_array_add (openconnect_argv, NULL);
+
+ if (!g_spawn_async_with_pipes (NULL, (char **) openconnect_argv->pdata, NULL,
+ G_SPAWN_DO_NOT_REAP_CHILD,
+ openconnect_drop_child_privs, NULL,
+ &pid, &stdin_fd, NULL, NULL, error)) {
+ g_ptr_array_free (openconnect_argv, TRUE);
+ nm_warning ("openconnect failed to start. error: '%s'", (*error)->message);
+ return -1;
+ }
+ g_ptr_array_free (openconnect_argv, TRUE);
+
+ nm_info ("openconnect started with pid %d", pid);
+
+ if (write(stdin_fd, props_cookie, strlen(props_cookie)) != strlen(props_cookie) ||
+ write(stdin_fd, "\n", 1) != 1) {
+ nm_warning ("openconnect didn't eat the cookie we fed it");
+ return -1;
+ }
+
+ close(stdin_fd);
+
+ NM_OPENCONNECT_PLUGIN_GET_PRIVATE (plugin)->pid = pid;
+ openconnect_watch = g_child_watch_source_new (pid);
+ g_source_set_callback (openconnect_watch, (GSourceFunc) openconnect_watch_cb, plugin, NULL);
+ g_source_attach (openconnect_watch, NULL);
+ g_source_unref (openconnect_watch);
+
+ return 0;
+}
+static gboolean
+real_connect (NMVPNPlugin *plugin,
+ NMConnection *connection,
+ GError **error)
+{
+ NMSettingVPN *s_vpn;
+ gint openconnect_fd = -1;
+ gboolean success = FALSE;
+ GHashTable *secrets;
+
+ s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+ g_assert (s_vpn);
+ if (!nm_openconnect_properties_validate (s_vpn, error))
+ goto out;
+ if (!nm_openconnect_secrets_validate (s_vpn, error))
+ goto out;
+
+ openconnect_fd = nm_openconnect_start_openconnect_binary (NM_OPENCONNECT_PLUGIN (plugin), s_vpn, error);
+ if (!openconnect_fd)
+ return TRUE;
+
+ out:
+ return FALSE;
+}
+
+static gboolean
+real_need_secrets (NMVPNPlugin *plugin,
+ NMConnection *connection,
+ char **setting_name,
+ GError **error)
+{
+ NMSettingVPN *s_vpn;
+
+ g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
+
+ s_vpn = NM_SETTING_VPN (nm_connection_get_setting (connection, NM_TYPE_SETTING_VPN));
+ if (!s_vpn) {
+ g_set_error (error,
+ NM_VPN_PLUGIN_ERROR,
+ NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
+ "%s",
+ "Could not process the request because the VPN connection settings were invalid.");
+ return FALSE;
+ }
+
+ /* We just need the WebVPN cookie, and the final IP address of the gateway
+ (after HTTP redirects, which do happen). All the certificate/SecurID
+ nonsense can be handled for us, in the user's context, by auth-dialog */
+ if (!nm_setting_vpn_get_data_item (s_vpn, NM_OPENCONNECT_KEY_GATEWAY)) {
+ *setting_name = NM_SETTING_VPN_SETTING_NAME;
+ return TRUE;
+ }
+ if (!nm_setting_vpn_get_secret (s_vpn, NM_OPENCONNECT_KEY_COOKIE)) {
+ *setting_name = NM_SETTING_VPN_SETTING_NAME;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static gboolean
+ensure_killed (gpointer data)
+{
+ int pid = GPOINTER_TO_INT (data);
+
+ if (kill (pid, 0) == 0)
+ kill (pid, SIGKILL);
+
+ return FALSE;
+}
+
+static gboolean
+real_disconnect (NMVPNPlugin *plugin,
+ GError **err)
+{
+ NMOPENCONNECTPluginPrivate *priv = NM_OPENCONNECT_PLUGIN_GET_PRIVATE (plugin);
+
+ if (priv->pid) {
+ if (kill (priv->pid, SIGTERM) == 0)
+ g_timeout_add (2000, ensure_killed, GINT_TO_POINTER (priv->pid));
+ else
+ kill (priv->pid, SIGKILL);
+
+ nm_info ("Terminated openconnect daemon with PID %d.", priv->pid);
+ priv->pid = 0;
+ }
+
+ return TRUE;
+}
+
+static void
+nm_openconnect_plugin_init (NMOPENCONNECTPlugin *plugin)
+{
+}
+
+static void
+nm_openconnect_plugin_class_init (NMOPENCONNECTPluginClass *openconnect_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (openconnect_class);
+ NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS (openconnect_class);
+
+ g_type_class_add_private (object_class, sizeof (NMOPENCONNECTPluginPrivate));
+
+ /* virtual methods */
+ parent_class->connect = real_connect;
+ parent_class->need_secrets = real_need_secrets;
+ parent_class->disconnect = real_disconnect;
+}
+
+NMOPENCONNECTPlugin *
+nm_openconnect_plugin_new (void)
+{
+ return (NMOPENCONNECTPlugin *) g_object_new (NM_TYPE_OPENCONNECT_PLUGIN,
+ NM_VPN_PLUGIN_DBUS_SERVICE_NAME, NM_DBUS_SERVICE_OPENCONNECT,
+ NULL);
+}
+
+static void
+quit_mainloop (NMOPENCONNECTPlugin *plugin, gpointer user_data)
+{
+ g_main_loop_quit ((GMainLoop *) user_data);
+}
+
+void create_persistent_tundev(void)
+{
+ struct passwd *pw;
+ struct ifreq ifr;
+ int fd;
+ int i;
+
+ pw = getpwnam(NM_OPENCONNECT_USER);
+ if (!pw)
+ return;
+
+ tun_owner = pw->pw_uid;
+ tun_group = pw->pw_gid;
+
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd < 0) {
+ perror("open /dev/net/tun");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(&ifr, 0, sizeof(ifr));
+ ifr.ifr_flags = IFF_TUN | IFF_NO_PI;
+
+ for (i = 0; i < 256; i++) {
+ if (tun_name)
+ g_free(tun_name);
+
+ sprintf(ifr.ifr_name, "vpn%d", i);
+
+ if (!ioctl(fd, TUNSETIFF, (void *)&ifr))
+ break;
+ }
+ if (i == 256)
+ exit(EXIT_FAILURE);
+
+ if (ioctl(fd, TUNSETOWNER, tun_owner) < 0) {
+ perror("TUNSETOWNER");
+ exit(EXIT_FAILURE);
+ }
+
+ if (ioctl(fd, TUNSETPERSIST, 1)) {
+ perror("TUNSETPERSIST");
+ exit(EXIT_FAILURE);
+ }
+ tun_name = g_strdup(ifr.ifr_name);
+ close(fd);
+}
+
+void destroy_persistent_tundev(void)
+{
+ struct ifreq ifr;
+ int fd;
+
+ if (!tun_name)
+ return;
+
+ fd = open("/dev/net/tun", O_RDWR);
+ if (fd < 0) {
+ perror("open /dev/net/tun");
+ exit(EXIT_FAILURE);
+ }
+
+ 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) {
+ perror("TUNSETIFF");
+ exit(EXIT_FAILURE);
+ }
+
+ if (ioctl(fd, TUNSETPERSIST, 0)) {
+ perror("TUNSETPERSIST");
+ exit(EXIT_FAILURE);
+ }
+ close(fd);
+}
+
+int main (int argc, char *argv[])
+{
+ NMOPENCONNECTPlugin *plugin;
+ GMainLoop *main_loop;
+
+ g_type_init ();
+
+ if (system ("/sbin/modprobe tun") == -1)
+ exit (EXIT_FAILURE);
+
+ create_persistent_tundev();
+
+ plugin = nm_openconnect_plugin_new ();
+ if (!plugin)
+ exit (EXIT_FAILURE);
+
+ main_loop = g_main_loop_new (NULL, FALSE);
+
+ g_signal_connect (plugin, "quit",
+ G_CALLBACK (quit_mainloop),
+ main_loop);
+
+ g_main_loop_run (main_loop);
+
+ g_main_loop_unref (main_loop);
+ g_object_unref (plugin);
+
+ destroy_persistent_tundev();
+
+ exit (EXIT_SUCCESS);
+}
diff --git a/vpn-daemons/openconnect/src/nm-openconnect-service.h b/vpn-daemons/openconnect/src/nm-openconnect-service.h
new file mode 100644
index 0000000..92db840
--- /dev/null
+++ b/vpn-daemons/openconnect/src/nm-openconnect-service.h
@@ -0,0 +1,49 @@
+/* -*- Mode: C; tab-width: 5; indent-tabs-mode: t; c-basic-offset: 5 -*- */
+
+#ifndef NM_OPENCONNECT_PLUGIN_H
+#define NM_OPENCONNECT_PLUGIN_H
+
+#include <glib/gtypes.h>
+#include <glib-object.h>
+#include <nm-vpn-plugin.h>
+
+#define NM_TYPE_OPENCONNECT_PLUGIN (nm_openconnect_plugin_get_type ())
+#define NM_OPENCONNECT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_OPENCONNECT_PLUGIN, NMOPENCONNECTPlugin))
+#define NM_OPENCONNECT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_OPENCONNECT_PLUGIN, NMOPENCONNECTPluginClass))
+#define NM_IS_OPENCONNECT_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_OPENCONNECT_PLUGIN))
+#define NM_IS_OPENCONNECT_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_OPENCONNECT_PLUGIN))
+#define NM_OPENCONNECT_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_OPENCONNECT_PLUGIN, NMOPENCONNECTPluginClass))
+
+#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_AUTHTYPE "authtype"
+#define NM_OPENCONNECT_KEY_USERCERT "usercert"
+#define NM_OPENCONNECT_KEY_CACERT "cacert"
+#define NM_OPENCONNECT_KEY_PRIVKEY "userkey"
+#define NM_OPENCONNECT_KEY_USERNAME "username"
+#define NM_OPENCONNECT_KEY_XMLCONFIG "xmlconfig"
+#define NM_OPENCONNECT_KEY_CERTSIGS "certsigs"
+
+#define NM_OPENCONNECT_AUTHTYPE_CERT "cert"
+#define NM_OPENCONNECT_AUTHTYPE_CERT_TPM "cert-tpm"
+#define NM_OPENCONNECT_AUTHTYPE_PASSWORD "password"
+
+typedef struct {
+ NMVPNPlugin parent;
+} NMOPENCONNECTPlugin;
+
+typedef struct {
+ NMVPNPluginClass parent;
+} NMOPENCONNECTPluginClass;
+
+GType nm_openconnect_plugin_get_type (void);
+
+NMOPENCONNECTPlugin *nm_openconnect_plugin_new (void);
+
+#define NM_OPENCONNECT_USER "nm-openconnect"
+
+#endif /* NM_OPENCONNECT_PLUGIN_H */
--
1.6.0.3
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]