From 6dbce9c803c06af4ff0f41468d1ffdf0776d4070 Mon Sep 17 00:00:00 2001 From: Martin Willi Date: Thu, 31 Jul 2008 11:16:14 +0000 Subject: [PATCH] reimplemented dbus plugin for NetworkManager 0.7, renamed to nm --- configure.in | 16 + src/charon/Makefile.am | 5 + src/charon/plugins/dbus/Makefile.am | 11 - src/charon/plugins/dbus/dbus.c | 422 ------------------ src/charon/plugins/dbus/nm-strongswan.conf | 21 - src/charon/plugins/dbus/nm-strongswan.name | 8 - src/charon/plugins/dbus/nm_applet_auth.c | 11 - src/charon/plugins/dbus/nm_applet_gui.c | 212 --------- src/charon/plugins/dbus/nm_applet_gui.xml | 93 ---- src/charon/plugins/nm/Makefile.am | 11 + src/charon/plugins/nm/nm_plugin.c | 91 ++++ .../plugins/{dbus/dbus.h => nm/nm_plugin.h} | 27 +- src/charon/plugins/nm/nm_service.c | 351 +++++++++++++++ src/charon/plugins/nm/nm_service.h | 55 +++ 14 files changed, 542 insertions(+), 792 deletions(-) delete mode 100644 src/charon/plugins/dbus/Makefile.am delete mode 100644 src/charon/plugins/dbus/dbus.c delete mode 100644 src/charon/plugins/dbus/nm-strongswan.conf delete mode 100644 src/charon/plugins/dbus/nm-strongswan.name delete mode 100644 src/charon/plugins/dbus/nm_applet_auth.c delete mode 100644 src/charon/plugins/dbus/nm_applet_gui.c delete mode 100644 src/charon/plugins/dbus/nm_applet_gui.xml create mode 100644 src/charon/plugins/nm/Makefile.am create mode 100644 src/charon/plugins/nm/nm_plugin.c rename src/charon/plugins/{dbus/dbus.h => nm/nm_plugin.h} (64%) create mode 100644 src/charon/plugins/nm/nm_service.c create mode 100644 src/charon/plugins/nm/nm_service.h diff --git a/configure.in b/configure.in index 9531bb361..8c790eb1b 100644 --- a/configure.in +++ b/configure.in @@ -563,6 +563,14 @@ AC_ARG_ENABLE( fi] ) +AC_ARG_ENABLE( + [nm], + AS_HELP_STRING([--enable-nm],[enable NetworkManager plugin (default is NO).]), + [if test x$enableval = xyes; then + nm=true + fi] +) + dnl ========================= dnl check required programs dnl ========================= @@ -705,6 +713,12 @@ if test x$uci = xtrue; then AC_CHECK_HEADER([uci.h],,[AC_MSG_ERROR([UCI header uci.h not found!])]) fi +if test x$nm = xtrue; then + PKG_CHECK_MODULES(nm, [NetworkManager libnm_glib_vpn gthread-2.0]) + AC_SUBST(nm_CFLAGS) + AC_SUBST(nm_LIBS) +fi + dnl ====================================== dnl collect all plugins for libstrongswan dnl ====================================== @@ -798,6 +812,7 @@ dnl ============== AM_CONDITIONAL(USE_STROKE, test x$stroke = xtrue) AM_CONDITIONAL(USE_MEDSRV, test x$medsrv = xtrue) AM_CONDITIONAL(USE_MEDCLI, test x$medcli = xtrue) +AM_CONDITIONAL(USE_NM, test x$nm = xtrue) AM_CONDITIONAL(USE_UCI, test x$uci = xtrue) AM_CONDITIONAL(USE_SMP, test x$smp = xtrue) AM_CONDITIONAL(USE_SQL, test x$sql = xtrue) @@ -876,6 +891,7 @@ AC_OUTPUT( src/charon/plugins/sql/Makefile src/charon/plugins/medsrv/Makefile src/charon/plugins/medcli/Makefile + src/charon/plugins/nm/Makefile src/charon/plugins/uci/Makefile src/charon/plugins/stroke/Makefile src/charon/plugins/unit_tester/Makefile diff --git a/src/charon/Makefile.am b/src/charon/Makefile.am index 782b2a9ba..3ea21a020 100644 --- a/src/charon/Makefile.am +++ b/src/charon/Makefile.am @@ -180,6 +180,11 @@ if USE_MEDCLI PLUGINS += medcli endif +if USE_NM + SUBDIRS += plugins/nm + PLUGINS += nm +endif + if USE_UCI SUBDIRS += plugins/uci PLUGINS += uci diff --git a/src/charon/plugins/dbus/Makefile.am b/src/charon/plugins/dbus/Makefile.am deleted file mode 100644 index 05f325358..000000000 --- a/src/charon/plugins/dbus/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ - -INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${dbus_CFLAGS} - -AM_CFLAGS = -rdynamic - -plugin_LTLIBRARIES = libstrongswan-dbus.la - -libstrongswan_dbus_la_SOURCES = dbus.h dbus.c -libstrongswan_dbus_la_LDFLAGS = -module -libstrongswan_dbus_la_LIBADD = ${dbus_LIBS} - diff --git a/src/charon/plugins/dbus/dbus.c b/src/charon/plugins/dbus/dbus.c deleted file mode 100644 index 97bd3b32f..000000000 --- a/src/charon/plugins/dbus/dbus.c +++ /dev/null @@ -1,422 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * 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. See . - * - * 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. - * - * $Id$ - */ - -#define DBUS_API_SUBJECT_TO_CHANGE -#include -#include -#include -#include - -#include "dbus.h" - -#include -#include -#include - - -#define NM_DBUS_SERVICE_STRONG "org.freedesktop.NetworkManager.strongswan" -#define NM_dbus_STRONG "org.freedesktop.NetworkManager.strongswan" -#define NM_DBUS_PATH_STRONG "/org/freedesktop/NetworkManager/strongswan" - -typedef struct private_dbus_t private_dbus_t; - -/** - * Private data of an dbus_t object. - */ -struct private_dbus_t { - - /** - * Public part of dbus_t object. - */ - dbus_t public; - - /** - * DBUS connection - */ - DBusConnection* conn; - - /** - * error value used here and there - */ - DBusError err; - - /** - * state of the daemon - */ - NMVPNState state; - - /** - * job accepting stroke messages - */ - callback_job_t *job; - - /** - * name of the currently active connection - */ - char *name; -}; - -/** - * set daemon state and send StateChange signal to the bus - */ -static void set_state(private_dbus_t *this, NMVPNState state) -{ - DBusMessage* msg; - - msg = dbus_message_new_signal(NM_DBUS_PATH_STRONG, NM_dbus_STRONG, NM_DBUS_VPN_SIGNAL_STATE_CHANGE); - - if (!dbus_message_append_args(msg, DBUS_TYPE_UINT32, &this->state, - DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID) || - !dbus_connection_send(this->conn, msg, NULL)) - { - DBG1(DBG_CFG, "unable to send DBUS StateChange signal"); - } - dbus_connection_flush(this->conn); - dbus_message_unref(msg); - this->state = state; -} - - -/** - * get the child_cfg with the same name as the peer cfg - */ -static child_cfg_t* get_child_from_peer(peer_cfg_t *peer_cfg, char *name) -{ - child_cfg_t *current, *found = NULL; - iterator_t *iterator; - - iterator = peer_cfg->create_child_cfg_iterator(peer_cfg); - while (iterator->iterate(iterator, (void**)¤t)) - { - if (streq(current->get_name(current), name)) - { - found = current; - found->get_ref(found); - break; - } - } - iterator->destroy(iterator); - return found; -} - - -/** - * process NetworkManagers startConnection method call - */ -static bool start_connection(private_dbus_t *this, DBusMessage* msg) -{ - DBusMessage *reply, *signal; - char *name, *user, **data, **passwords, **routes; - int data_count, passwords_count, routes_count; - u_int32_t me, other, p2p, netmask, mss; - char *dev, *domain, *banner; - const dbus_int32_t array[] = {}; - const dbus_int32_t *varray = array; - peer_cfg_t *peer_cfg; - child_cfg_t *child_cfg; - status_t status = FAILED; - - dbus_error_free(&this->err); - - if (!dbus_message_get_args(msg, &this->err, - DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &user, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &passwords, &passwords_count, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &data, &data_count, - DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &routes, &routes_count, - DBUS_TYPE_INVALID)) - { - return FALSE; - } - set_state(this, NM_VPN_STATE_STARTING); - - peer_cfg = charon->backends->get_peer_cfg_by_name(charon->backends, name); - if (peer_cfg) - { - free(this->name); - this->name = strdup(peer_cfg->get_name(peer_cfg)); - child_cfg = get_child_from_peer(peer_cfg, name); - if (child_cfg) - { - status = charon->controller->initiate(charon->controller, - peer_cfg, child_cfg, controller_cb_empty, NULL); - } - else - { - peer_cfg->destroy(peer_cfg); - } - } - reply = dbus_message_new_method_return(msg); - dbus_connection_send(this->conn, reply, NULL); - dbus_message_unref(reply); - - if (status == SUCCESS) - { - - set_state(this, NM_VPN_STATE_STARTED); - signal = dbus_message_new_signal(NM_DBUS_PATH_STRONG, - NM_dbus_STRONG, - NM_DBUS_VPN_SIGNAL_IP4_CONFIG); - me = other = p2p = mss = netmask = 0; - dev = domain = banner = ""; - if (dbus_message_append_args(signal, - DBUS_TYPE_UINT32, &other, - DBUS_TYPE_STRING, &dev, - DBUS_TYPE_UINT32, &me, - DBUS_TYPE_UINT32, &p2p, - DBUS_TYPE_UINT32, &netmask, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, - DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &varray, 0, - DBUS_TYPE_UINT32, &mss, - DBUS_TYPE_STRING, &domain, - DBUS_TYPE_STRING, &banner, DBUS_TYPE_INVALID)) - { - dbus_connection_send(this->conn, signal, NULL); - } - dbus_message_unref(signal); - } - else - { - set_state(this, NM_VPN_STATE_STOPPED); - } - - dbus_connection_flush(this->conn); - return TRUE; -} - -/** - * process NetworkManagers stopConnection method call - */ -static bool stop_connection(private_dbus_t *this, DBusMessage* msg) -{ - u_int32_t id; - enumerator_t *enumerator; - ike_sa_t *ike_sa; - - if (this->name == NULL) - { - return FALSE; - } - - dbus_error_free(&this->err); - - set_state(this, NM_VPN_STATE_STOPPING); - - enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); - while (enumerator->enumerate(enumerator, (void**)&ike_sa)) - { - child_sa_t *child_sa; - iterator_t *children; - - if (this->name && streq(this->name, ike_sa->get_name(ike_sa))) - { - id = ike_sa->get_unique_id(ike_sa); - enumerator->destroy(enumerator); - charon->controller->terminate_ike(charon->controller, id, NULL, NULL); - set_state(this, NM_VPN_STATE_STOPPED); - return TRUE;; - } - children = ike_sa->create_child_sa_iterator(ike_sa); - while (children->iterate(children, (void**)&child_sa)) - { - if (this->name && streq(this->name, child_sa->get_name(child_sa))) - { - id = child_sa->get_reqid(child_sa); - children->destroy(children); - enumerator->destroy(enumerator); - charon->controller->terminate_child(charon->controller, id, NULL, NULL); - set_state(this, NM_VPN_STATE_STOPPED); - return TRUE; - } - } - children->destroy(children); - } - enumerator->destroy(enumerator); - set_state(this, NM_VPN_STATE_STOPPED); - return TRUE; -} - -/** - * process NetworkManagers getState method call - */ -static bool get_state(private_dbus_t *this, DBusMessage* msg) -{ - DBusMessage* reply; - reply = dbus_message_new_method_return(msg); - if (!reply || !dbus_message_append_args(reply, - DBUS_TYPE_UINT32, &this->state, - DBUS_TYPE_INVALID)) - { - return FALSE; - } - dbus_connection_send(this->conn, reply, NULL); - return TRUE; -} - -/** - * Handle incoming messages - */ -static DBusHandlerResult message_handler(DBusConnection *con, DBusMessage *msg, - private_dbus_t *this) -{ - bool handled; - - if (dbus_message_is_method_call(msg, NM_dbus_STRONG, - "startConnection")) - { - handled = start_connection(this, msg); - } - else if (dbus_message_is_method_call(msg, NM_dbus_STRONG, - "stopConnection")) - { - handled = stop_connection(this, msg); - } - else if (dbus_message_is_method_call(msg, NM_dbus_STRONG, - "getState")) - { - handled = get_state(this, msg); - } - else - { - DBG1(DBG_CFG, "ignoring DBUS message %s.%s", - dbus_message_get_interface(msg), dbus_message_get_member(msg)); - handled = FALSE; - } - - if (handled) - { - return DBUS_HANDLER_RESULT_HANDLED; - } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} - -/** - * Handle received signals - -static DBusHandlerResult signal_handler(DBusConnection *con, DBusMessage *msg, - private_dbus_t *this) -{ - bool handled; - - if (dbus_message_is_signal(msg, NM_dbus, "VPNConnectionStateChange")) - { - NMVPNState state; - char *name; - - if (dbus_message_get_args(msg, &this->err, DBUS_TYPE_STRING, &name, - DBUS_TYPE_UINT32, &state, DBUS_TYPE_INVALID)) - { - DBG1(DBG_CFG, "got state %d for %s", state, name); - } - handled = TRUE; - } - else - { - DBG1(DBG_CFG, "ignoring DBUS signal %s.%s", - dbus_message_get_interface(msg), dbus_message_get_member(msg)); - handled = FALSE; - } - if (handled) - { - return DBUS_HANDLER_RESULT_HANDLED; - } - return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; -} */ - -/** - * dispatcher function processed by a seperate thread - */ -static job_requeue_t dispatch(private_dbus_t *this) -{ - if (dbus_connection_read_write_dispatch(this->conn, -1)) - { - return JOB_REQUEUE_DIRECT; - } - return JOB_REQUEUE_NONE; -} - -/** - * Implementation of interface_t.destroy. - */ -static void destroy(private_dbus_t *this) -{ - this->job->cancel(this->job); - dbus_connection_close(this->conn); - dbus_error_free(&this->err); - dbus_shutdown(); - free(this->name); - free(this); -} - -/* - * Described in header file - */ -plugin_t *plugin_create() -{ - int ret; - DBusObjectPathVTable v = {NULL, (void*)&message_handler, NULL, NULL, NULL, NULL}; - private_dbus_t *this = malloc_thing(private_dbus_t); - - this->public.plugin.destroy = (void (*)(plugin_t*))destroy; - - dbus_error_init(&this->err); - this->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &this->err); - if (dbus_error_is_set(&this->err)) - { - DBG1(DBG_CFG, "unable to open DBUS connection: %s", this->err.message); - charon->kill(charon, "DBUS initialization failed"); - } - dbus_connection_set_exit_on_disconnect(this->conn, FALSE); - - ret = dbus_bus_request_name(this->conn, NM_DBUS_SERVICE_STRONG, - DBUS_NAME_FLAG_REPLACE_EXISTING , &this->err); - if (dbus_error_is_set(&this->err)) - { - DBG1(DBG_CFG, "unable to set DBUS name: %s", this->err.message); - charon->kill(charon, "unable to set DBUS name"); - } - if (ret != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) - { - charon->kill(charon, "DBUS name already owned"); - } - if (!dbus_connection_register_object_path(this->conn, NM_DBUS_PATH_STRONG, &v, this)) - { - charon->kill(charon, "unable to register DBUS message handler"); - } - /* - if (!dbus_connection_add_filter(this->conn, (void*)signal_handler, this, NULL)) - { - charon->kill(charon, "unable to register DBUS signal handler"); - } - - dbus_bus_add_match(this->conn, "type='signal', " - "interface='" NM_dbus_VPN "'," - "path='" NM_DBUS_PATH_VPN "'", &this->err); - if (dbus_error_is_set (&this->err)) - { - charon->kill(charon, "unable to add DBUS signal match"); - }*/ - - this->name = NULL; - this->state = NM_VPN_STATE_INIT; - set_state(this, NM_VPN_STATE_STOPPED); - - this->job = callback_job_create((callback_job_cb_t)dispatch, this, NULL, NULL); - charon->processor->queue_job(charon->processor, (job_t*)this->job); - - return &this->public.plugin; -} - diff --git a/src/charon/plugins/dbus/nm-strongswan.conf b/src/charon/plugins/dbus/nm-strongswan.conf deleted file mode 100644 index 020617566..000000000 --- a/src/charon/plugins/dbus/nm-strongswan.conf +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - - - - - - - - - - - - diff --git a/src/charon/plugins/dbus/nm-strongswan.name b/src/charon/plugins/dbus/nm-strongswan.name deleted file mode 100644 index 2f6ed062c..000000000 --- a/src/charon/plugins/dbus/nm-strongswan.name +++ /dev/null @@ -1,8 +0,0 @@ -[VPN Connection] -name=strongSwan -service=org.freedesktop.NetworkManager.strongswan -program=/usr/local/libexec/ipsec/charon - -[GNOME] -auth-dialog=/home/martin/strongswan/trunk/src/networkmanager/nm_applet_auth -properties=/home/martin/strongswan/trunk/src/networkmanager/strongswan.so diff --git a/src/charon/plugins/dbus/nm_applet_auth.c b/src/charon/plugins/dbus/nm_applet_auth.c deleted file mode 100644 index f48ee1ba3..000000000 --- a/src/charon/plugins/dbus/nm_applet_auth.c +++ /dev/null @@ -1,11 +0,0 @@ -#include - - -int main() -{ - char buf[1]; - printf("PASSWORDL\n"); - printf ("\n\n"); - //fread (buf, sizeof (char), sizeof (buf), stdin); - return 0; -} diff --git a/src/charon/plugins/dbus/nm_applet_gui.c b/src/charon/plugins/dbus/nm_applet_gui.c deleted file mode 100644 index 70abfaddb..000000000 --- a/src/charon/plugins/dbus/nm_applet_gui.c +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Copyright (C) 2007 Martin Willi - * Hochschule fuer Technik Rapperswil - * - * 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. See . - * - * 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. - * - * $Id$ - */ - -#include - -#define NM_VPN_API_SUBJECT_TO_CHANGE -#include - - -typedef struct private_nm_applet_gui_t private_nm_applet_gui_t; - -/** - * Private data of an nm_applet_gui_t object. - */ -struct private_nm_applet_gui_t { - - /** - * Implements NetworkManagerVpnUI interface. - */ - NetworkManagerVpnUI public; - - /** - * callback registered by NM to update validity - */ - NetworkManagerVpnUIDialogValidityCallback callback; - - /** - * loaded Glade XML interface description - */ - GladeXML *xml; - - /** - * root widget to return to druid - */ - GtkWidget *widget; - - /** - * name of the connection - */ - GtkEntry *name; - - /** - * gateway address - */ - GtkEntry *gateway; - - /** - * username - */ - GtkEntry *user; -}; - -static const char *get_display_name(private_nm_applet_gui_t *this) -{ - return "strongSwan (IPsec/IKEv2)"; -} - -static const char *get_service_name(private_nm_applet_gui_t *this) -{ - return "org.freedesktop.NetworkManager.strongswan"; -} - -static GtkWidget *get_widget(private_nm_applet_gui_t *this, GSList *properties, - GSList *routes, const char *connection_name) -{ - GSList *i; - - gtk_entry_set_text(this->name, ""); - gtk_entry_set_text(this->gateway, ""); - gtk_entry_set_text(this->user, ""); - - if (connection_name) - { - gtk_entry_set_text(this->name, connection_name); - } - - while (properties) - { - const char *key; - const char *value; - - key = properties->data; - properties = g_slist_next(properties); - if (properties) - { - value = properties->data; - if (strcmp(key, "gateway") == 0) - { - gtk_entry_set_text(this->gateway, value); - } - if (strcmp(key, "user") == 0) - { - gtk_entry_set_text(this->user, value); - } - properties = g_slist_next(properties); - } - } - return this->widget; -} - -static GSList *get_properties(private_nm_applet_gui_t *this) -{ - GSList *props = NULL; - - props = g_slist_append(props, g_strdup("gateway")); - props = g_slist_append(props, g_strdup(gtk_entry_get_text(this->gateway))); - props = g_slist_append(props, g_strdup("user")); - props = g_slist_append(props, g_strdup(gtk_entry_get_text(this->user))); - - return props; -} - -static GSList *get_routes(private_nm_applet_gui_t *this) -{ - return NULL; -} - -static char *get_connection_name(private_nm_applet_gui_t *this) -{ - const char *name; - - name = gtk_entry_get_text(this->name); - if (name != NULL) - { - return g_strdup(name); - } - return NULL; -} - -static gboolean is_valid(private_nm_applet_gui_t *this) -{ - return TRUE; -} - -static void set_validity_changed_callback(private_nm_applet_gui_t *this, - NetworkManagerVpnUIDialogValidityCallback callback, - gpointer user_data) -{ - this->callback = callback; -} - -static void get_confirmation_details(private_nm_applet_gui_t *this, gchar **retval) -{ - *retval = g_strdup_printf("connection %s\n", gtk_entry_get_text(this->name)); -} - -static gboolean can_export(private_nm_applet_gui_t *this) -{ - return FALSE; -} - -static gboolean import_file (private_nm_applet_gui_t *this, const char *path) -{ - return FALSE; -} - -static gboolean export(private_nm_applet_gui_t *this, GSList *properties, - GSList *routes, const char *connection_name) -{ - return FALSE; -} - -NetworkManagerVpnUI* nm_vpn_properties_factory(void) -{ - private_nm_applet_gui_t *this = g_new0(private_nm_applet_gui_t, 1); - - this->public.get_display_name = (const char *(*)(NetworkManagerVpnUI *))get_display_name; - this->public.get_service_name = (const char *(*) (NetworkManagerVpnUI *))get_service_name; - this->public.get_widget = (GtkWidget *(*) (NetworkManagerVpnUI *self, GSList *, GSList *, const char *))get_widget; - this->public.get_connection_name = (char *(*) (NetworkManagerVpnUI *))get_connection_name; - this->public.get_properties = (GSList *(*) (NetworkManagerVpnUI *))get_properties; - this->public.get_routes = (GSList *(*) (NetworkManagerVpnUI *))get_routes; - this->public.set_validity_changed_callback = (void (*) (NetworkManagerVpnUI *, NetworkManagerVpnUIDialogValidityCallback, gpointer))set_validity_changed_callback; - this->public.is_valid = (gboolean (*) (NetworkManagerVpnUI *))is_valid; - this->public.get_confirmation_details = (void (*)(NetworkManagerVpnUI *, gchar **))get_confirmation_details; - this->public.can_export = (gboolean (*) (NetworkManagerVpnUI *))can_export; - this->public.import_file = (gboolean (*) (NetworkManagerVpnUI *, const char *))import_file; - this->public.export = (gboolean (*) (NetworkManagerVpnUI *, GSList *, GSList *, const char *))export; - this->public.data = NULL; - - this->callback = NULL; - this->xml = glade_xml_new("/home/martin/strongswan/trunk/src/charon/plugins/dbus/nm_applet_gui.xml", NULL, NULL); - - if (this->xml != NULL) - { - this->widget = glade_xml_get_widget(this->xml, "main"); - this->name = GTK_ENTRY(glade_xml_get_widget(this->xml, "name")); - this->gateway = GTK_ENTRY(glade_xml_get_widget(this->xml, "gateway")); - this->user = GTK_ENTRY(glade_xml_get_widget(this->xml, "user")); - - if (this->widget && this->name && this->gateway && this->user) - { - return &this->public; - } - } - g_free(this); - return NULL; -} diff --git a/src/charon/plugins/dbus/nm_applet_gui.xml b/src/charon/plugins/dbus/nm_applet_gui.xml deleted file mode 100644 index f59d3e9c7..000000000 --- a/src/charon/plugins/dbus/nm_applet_gui.xml +++ /dev/null @@ -1,93 +0,0 @@ - - - - - - - - True - 3 - 2 - 5 - 5 - - - True - - - 1 - 2 - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - _Username - True - GTK_JUSTIFY_CENTER - - - 2 - 3 - GTK_FILL - GTK_FILL - - - - - True - - - 1 - 2 - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - _Gateway - True - GTK_JUSTIFY_RIGHT - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - - - 1 - 2 - GTK_FILL - GTK_FILL - - - - - True - Connection _name - True - GTK_JUSTIFY_FILL - - - GTK_FILL - GTK_FILL - - - - - - diff --git a/src/charon/plugins/nm/Makefile.am b/src/charon/plugins/nm/Makefile.am new file mode 100644 index 000000000..0d6677d6f --- /dev/null +++ b/src/charon/plugins/nm/Makefile.am @@ -0,0 +1,11 @@ + +INCLUDES = -I$(top_srcdir)/src/libstrongswan -I$(top_srcdir)/src/charon ${nm_CFLAGS} + +AM_CFLAGS = -rdynamic + +plugin_LTLIBRARIES = libstrongswan-nm.la +libstrongswan_nm_la_SOURCES = \ + nm_plugin.h nm_plugin.c nm_service.h nm_service.c +libstrongswan_nm_la_LDFLAGS = -module +libstrongswan_nm_la_LIBADD = ${nm_LIBS} + diff --git a/src/charon/plugins/nm/nm_plugin.c b/src/charon/plugins/nm/nm_plugin.c new file mode 100644 index 000000000..aa9552878 --- /dev/null +++ b/src/charon/plugins/nm/nm_plugin.c @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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. + * + * $Id$ + */ + +#include "nm_plugin.h" +#include "nm_service.h" + +#include +#include + +typedef struct private_nm_plugin_t private_nm_plugin_t; + +/** + * private data of nm plugin + */ +struct private_nm_plugin_t { + + /** + * implements plugin interface + */ + nm_plugin_t public; + + GMainLoop *loop; +}; + +/** + * NM plugin processing routine, creates and handles NMVPNPlugin + */ +static job_requeue_t run(private_nm_plugin_t *this) +{ + NMStrongswanPlugin *plugin; + GMainLoop *loop; + + plugin = nm_strongswan_plugin_new(); + + this->loop = loop = g_main_loop_new(NULL, FALSE); + g_main_loop_run(loop); + + g_main_loop_unref(loop); + g_object_unref(plugin); + + return JOB_REQUEUE_NONE; +} + +/** + * Implementation of plugin_t.destroy + */ +static void destroy(private_nm_plugin_t *this) +{ + if (this->loop) + { + g_main_loop_quit(this->loop); + } + free(this); +} + +/* + * see header file + */ +plugin_t *plugin_create() +{ + private_nm_plugin_t *this = malloc_thing(private_nm_plugin_t); + + this->public.plugin.destroy = (void(*)(plugin_t*))destroy; + + this->loop = NULL; + g_type_init (); + if (!g_thread_supported()) + { + g_thread_init(NULL); + } + + charon->processor->queue_job(charon->processor, + (job_t*)callback_job_create((callback_job_cb_t)run, this, NULL, NULL)); + + return &this->public.plugin; +} + diff --git a/src/charon/plugins/dbus/dbus.h b/src/charon/plugins/nm/nm_plugin.h similarity index 64% rename from src/charon/plugins/dbus/dbus.h rename to src/charon/plugins/nm/nm_plugin.h index e5bc2d20c..2604b80dd 100644 --- a/src/charon/plugins/dbus/dbus.h +++ b/src/charon/plugins/nm/nm_plugin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2007-2008 Martin Willi + * Copyright (C) 2008 Martin Willi * Hochschule fuer Technik Rapperswil * * This program is free software; you can redistribute it and/or modify it @@ -11,30 +11,29 @@ * 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. + * + * $Id$ */ /** - * @defgroup dbus dbus + * @defgroup nm nm * @ingroup cplugins * - * @defgroup dbus_i dbus - * @{ @ingroup dbus + * @defgroup nm_plugin nm_plugin + * @{ @ingroup nm */ -#ifndef DBUS_H_ -#define DBUS_H_ +#ifndef NM_PLUGIN_H_ +#define NM_PLUGIN_H_ #include -typedef struct dbus_t dbus_t; +typedef struct nm_plugin_t nm_plugin_t; /** - * NetworkManager DBUS control plugin. - * - * This plugin uses a DBUS connection. It is designed to work in conjuction - * with NetworkManager to configure and control the daemon. + * NetworkManager integration plugin. */ -struct dbus_t { +struct nm_plugin_t { /** * implements plugin interface @@ -43,8 +42,8 @@ struct dbus_t { }; /** - * Create a dbus plugin instance. + * Create a nm_plugin instance. */ plugin_t *plugin_create(); -#endif /* DBUS_H_ @}*/ +#endif /* NM_PLUGIN_H_ @}*/ diff --git a/src/charon/plugins/nm/nm_service.c b/src/charon/plugins/nm/nm_service.c new file mode 100644 index 000000000..ed30d7f2c --- /dev/null +++ b/src/charon/plugins/nm/nm_service.c @@ -0,0 +1,351 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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. + * + * $Id$ + */ + +#include +#include +#include "nm_service.h" + +#include +#include +#include +#include + +#include + +#define CONFIG_NAME "NetworkManager" + +G_DEFINE_TYPE(NMStrongswanPlugin, nm_strongswan_plugin, NM_TYPE_VPN_PLUGIN) + +/** + * Private data of NMStrongswanPlugin + */ +typedef struct { + bus_listener_t listener; + ike_sa_t *ike_sa; + NMVPNPlugin *plugin; +} NMStrongswanPluginPrivate; + +#define NM_STRONGSWAN_PLUGIN_GET_PRIVATE(o) \ + (G_TYPE_INSTANCE_GET_PRIVATE ((o), \ + NM_TYPE_STRONGSWAN_PLUGIN, NMStrongswanPluginPrivate)) + +/** + * convert a traffic selector address range to subnet and its mask. + */ +static u_int ts2subnet(traffic_selector_t* ts, u_int8_t *mask) +{ + /* there is no way to do this cleanly, as the address range may + * be anything else but a subnet. We use from_addr as subnet + * and try to calculate a usable subnet mask. + */ + int byte, bit, net; + bool found = FALSE; + chunk_t from, to; + size_t size = (ts->get_type(ts) == TS_IPV4_ADDR_RANGE) ? 4 : 16; + + from = ts->get_from_address(ts); + to = ts->get_to_address(ts); + + *mask = (size * 8); + /* go trough all bits of the addresses, beginning in the front. + * as long as they are equal, the subnet gets larger + */ + for (byte = 0; byte < size; byte++) + { + for (bit = 7; bit >= 0; bit--) + { + if ((1<get_traffic_selectors(child_sa, FALSE); + enumerator = list->create_enumerator(list); + while (enumerator->enumerate(enumerator, &ts)) + { + GValue *val; + GHashTable *config; + u_int8_t mask; + + config = g_hash_table_new(g_str_hash, g_str_equal); + + val = g_slice_new0(GValue); + g_value_init(val, G_TYPE_UINT); + g_value_set_uint(val, ts2subnet(ts, &mask)); + g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_ADDRESS, val); + + val = g_slice_new0(GValue); + g_value_init(val, G_TYPE_UINT); + g_value_set_uint(val, mask); + g_hash_table_insert(config, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, val); + + nm_vpn_plugin_set_ip4_config(plugin, config); + } + enumerator->destroy(enumerator); +} + +/** + * Bus listen function to wait for SA establishing + */ +bool listen_bus(bus_listener_t *listener, signal_t signal, level_t level, + int thread, ike_sa_t *ike_sa, void *data, + char* format, va_list args) +{ + NMStrongswanPluginPrivate *private = (NMStrongswanPluginPrivate*)listener; + + if (private->ike_sa == ike_sa) + { + switch (signal) + { + case CHD_UP_SUCCESS: + if (data) + { + signal_ipv4_config(private->plugin, (child_sa_t*)data); + return FALSE; + } + /* FALL */ + case IKE_UP_FAILED: + case CHD_UP_FAILED: + nm_vpn_plugin_failure(private->plugin, + NM_VPN_PLUGIN_FAILURE_CONNECT_FAILED); + /* TODO: NM does not react on this failure!? So additionaly + * reset state */ + nm_vpn_plugin_set_state(private->plugin, + NM_VPN_SERVICE_STATE_STOPPED); + return FALSE; + default: + break; + } + } + return TRUE; +} + +/** + * Read a string from a hash table using a given key + */ +static char* get_str(GHashTable *hash, char *key) +{ + GValue *value; + + value = g_hash_table_lookup(hash, key); + if (G_VALUE_TYPE (value) == G_TYPE_STRING) + { + return (char*)g_value_get_string(value); + } + return NULL; +} + +/** + * Connect function called from NM via DBUS + */ +static gboolean connect_(NMVPNPlugin *plugin, NMConnection *connection, + GError **err) +{ + NMSettingVPNProperties *properties; + identification_t *user = NULL; + char *address, *str; + ike_cfg_t *ike_cfg; + peer_cfg_t *peer_cfg; + child_cfg_t *child_cfg; + traffic_selector_t *ts; + ike_sa_t *ike_sa; + + /** + * Read parameters + */ + properties = NM_SETTING_VPN_PROPERTIES( + nm_connection_get_setting(connection, NM_TYPE_SETTING_VPN_PROPERTIES)); + + if (!properties) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "%s", "Invalid arguments."); + return FALSE; + } + + DBG2(DBG_CFG, "received NetworkManager connection: %s", + nm_setting_to_string(NM_SETTING(properties))); + + str = get_str(properties->data, "user"); + if (str) + { + user = identification_create_from_string(str); + } + if (!user) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Username '%s' invalid.", str); + return FALSE; + } + address = get_str(properties->data, "address"); + if (!address || !*address) + { + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Gateway address missing."); + return FALSE; + } + + /** + * Set up configurations + */ + ike_cfg = ike_cfg_create(TRUE, TRUE, "0.0.0.0", address); + ike_cfg->add_proposal(ike_cfg, proposal_create_default(PROTO_IKE)); + peer_cfg = peer_cfg_create(CONFIG_NAME, 2, ike_cfg, user, + identification_create_from_encoding(ID_ANY, chunk_empty), + CERT_SEND_IF_ASKED, UNIQUE_REPLACE, CONF_AUTH_PUBKEY, + 0, 0, 1, /* EAP method, vendor, keyingtries */ + 18000, 0, /* rekey 5h, reauth none */ + 600, 600, /* jitter, over 10min */ + TRUE, 0, /* mobike, DPD */ + host_create_from_string("0.0.0.0", 0), /* virtual ip */ + NULL, FALSE, NULL, NULL); /* pool, mediation */ + child_cfg = child_cfg_create(CONFIG_NAME, + 3600, 3000, /* lifetime 1h, rekey 50min */ + 300, /* jitter 5min */ + NULL, TRUE, MODE_TUNNEL, /* updown, hostaccess */ + ACTION_NONE, ACTION_NONE, FALSE); /* ipcomp */ + child_cfg->add_proposal(child_cfg, proposal_create_default(PROTO_ESP)); + ts = traffic_selector_create_dynamic(0, 0, 65535); + child_cfg->add_traffic_selector(child_cfg, TRUE, ts); + ts = traffic_selector_create_from_string(0, TS_IPV4_ADDR_RANGE, + "0.0.0.0", 0, + "255.255.255.255", 65535); + child_cfg->add_traffic_selector(child_cfg, FALSE, ts); + peer_cfg->add_child_cfg(peer_cfg, child_cfg); + + /** + * Start to initiate + */ + ike_sa = charon->ike_sa_manager->checkout_by_config(charon->ike_sa_manager, + peer_cfg); + if (!ike_sa->get_peer_cfg(ike_sa)) + { + ike_sa->set_peer_cfg(ike_sa, peer_cfg); + } + else + { + peer_cfg->destroy(peer_cfg); + } + if (ike_sa->initiate(ike_sa, child_cfg) != SUCCESS) + { + charon->ike_sa_manager->checkin_and_destroy(charon->ike_sa_manager, ike_sa); + + g_set_error(err, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_LAUNCH_FAILED, + "Initiating failed."); + return FALSE; + } + + /** + * Register listener + */ + NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->ike_sa = ike_sa; + charon->bus->add_listener(charon->bus, + &NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->listener); + charon->ike_sa_manager->checkin(charon->ike_sa_manager, ike_sa); + return TRUE; +} + +/** + * NeedSecrets called from NM via DBUS + */ +static gboolean need_secrets(NMVPNPlugin *plugin, NMConnection *connection, + char **setting_name, GError **error) +{ + return FALSE; +} + +/** + * Disconnect called from NM via DBUS + */ +static gboolean disconnect(NMVPNPlugin *plugin, GError **err) +{ + enumerator_t *enumerator; + ike_sa_t *ike_sa; + u_int id; + + enumerator = charon->controller->create_ike_sa_enumerator(charon->controller); + while (enumerator->enumerate(enumerator, &ike_sa)) + { + if (streq(CONFIG_NAME, ike_sa->get_name(ike_sa))) + { + id = ike_sa->get_unique_id(ike_sa); + enumerator->destroy(enumerator); + charon->controller->terminate_ike(charon->controller, id, + controller_cb_empty, NULL); + return TRUE; + } + } + enumerator->destroy(enumerator); + return FALSE; +} + +/** + * Initializer + */ +static void nm_strongswan_plugin_init(NMStrongswanPlugin *plugin) +{ + NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->plugin = NM_VPN_PLUGIN(plugin); + NM_STRONGSWAN_PLUGIN_GET_PRIVATE(plugin)->listener.signal = listen_bus; +} + +/** + * Class constructor + */ +static void nm_strongswan_plugin_class_init( + NMStrongswanPluginClass *strongswan_class) +{ + NMVPNPluginClass *parent_class = NM_VPN_PLUGIN_CLASS(strongswan_class); + + g_type_class_add_private(G_OBJECT_CLASS(strongswan_class), + sizeof(NMStrongswanPluginPrivate)); + parent_class->connect = connect_; + parent_class->need_secrets = need_secrets; + parent_class->disconnect = disconnect; +} + +/** + * Object constructor + */ +NMStrongswanPlugin *nm_strongswan_plugin_new(void) +{ + return (NMStrongswanPlugin *)g_object_new ( + NM_TYPE_STRONGSWAN_PLUGIN, NM_VPN_PLUGIN_DBUS_SERVICE_NAME, + NM_DBUS_SERVICE_STRONGSWAN, NULL); +} + diff --git a/src/charon/plugins/nm/nm_service.h b/src/charon/plugins/nm/nm_service.h new file mode 100644 index 000000000..71334723f --- /dev/null +++ b/src/charon/plugins/nm/nm_service.h @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2008 Martin Willi + * Hochschule fuer Technik Rapperswil + * + * 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. See . + * + * 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. + * + * $Id$ + */ + +/** + * @defgroup nm_service nm_service + * @{ @ingroup nm + */ + +#ifndef NM_SERVICE_H_ +#define NM_SERVICE_H_ + +#include +#include +#include +#undef TRUE +#undef FALSE + +#define NM_TYPE_STRONGSWAN_PLUGIN (nm_strongswan_plugin_get_type ()) +#define NM_STRONGSWAN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPlugin)) +#define NM_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPluginClass)) +#define NM_IS_STRONGSWAN_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN)) +#define NM_IS_STRONGSWAN_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), NM_TYPE_STRONGSWAN_PLUGIN)) +#define NM_STRONGSWAN_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_STRONGSWAN_PLUGIN, NMSTRONGSWANPluginClass)) + +#define NM_DBUS_SERVICE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" +#define NM_DBUS_INTERFACE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan" +#define NM_DBUS_PATH_STRONGSWAN "/org/freedesktop/NetworkManager/strongswan" + +typedef struct { + NMVPNPlugin parent; +} NMStrongswanPlugin; + +typedef struct { + NMVPNPluginClass parent; +} NMStrongswanPluginClass; + +GType nm_strongswan_plugin_get_type(void); + +NMStrongswanPlugin *nm_strongswan_plugin_new(void); + +#endif /* NM_SERVICE_H_ */