[PATCH] Add OpenConnect VPN support



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">&lt;b&gt;General&lt;/b&gt;</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">&lt;b&gt;Authentication&lt;/b&gt;</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]