reimplemented dbus plugin for NetworkManager 0.7, renamed to nm

This commit is contained in:
Martin Willi 2008-07-31 11:16:14 +00:00
parent 2d87903db9
commit 6dbce9c803
14 changed files with 542 additions and 792 deletions

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 <dbus/dbus.h>
#include <NetworkManager/NetworkManager.h>
#include <NetworkManager/NetworkManagerVPN.h>
#include <stdlib.h>
#include "dbus.h"
#include <library.h>
#include <daemon.h>
#include <processing/jobs/callback_job.h>
#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**)&current))
{
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;
}

View File

@ -1,21 +0,0 @@
<!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.strongswan"/>
<allow send_destination="org.freedesktop.NetworkManager.strongswan"/>
<allow send_interface="org.freedesktop.NetworkManager.strongswan"/>
</policy>
<policy at_console="true">
<allow send_destination="org.freedesktop.NetworkManager.strongswan"/>
<allow send_interface="org.freedesktop.NetworkManager.strongswan"/>
</policy>
<policy context="default">
<deny own="org.strongswan.charon"/>
<deny send_destination="org.freedesktop.NetworkManager.strongswan"/>
<deny send_interface="org.freedesktop.NetworkManager.strongswan"/>
</policy>
</busconfig>

View File

@ -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

View File

@ -1,11 +0,0 @@
#include <stdio.h>
int main()
{
char buf[1];
printf("PASSWORDL\n");
printf ("\n\n");
//fread (buf, sizeof (char), sizeof (buf), stdin);
return 0;
}

View File

@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 <glade/glade.h>
#define NM_VPN_API_SUBJECT_TO_CHANGE
#include <nm-vpn-ui-interface.h>
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;
}

View File

@ -1,93 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE glade-interface SYSTEM "glade-2.0.dtd">
<!--Generated with glade3 3.4.0 on Sat Mar 15 17:12:28 2008 -->
<glade-interface>
<widget class="GtkWindow" id="window1">
<child>
<widget class="GtkTable" id="main">
<property name="visible">True</property>
<property name="n_rows">3</property>
<property name="n_columns">2</property>
<property name="column_spacing">5</property>
<property name="row_spacing">5</property>
<child>
<widget class="GtkEntry" id="user">
<property name="visible">True</property>
</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="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label8">
<property name="visible">True</property>
<property name="label" translatable="yes">_Username</property>
<property name="use_underline">True</property>
<property name="justify">GTK_JUSTIFY_CENTER</property>
</widget>
<packing>
<property name="top_attach">2</property>
<property name="bottom_attach">3</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="gateway">
<property name="visible">True</property>
</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="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="label" translatable="yes">_Gateway</property>
<property name="use_underline">True</property>
<property name="justify">GTK_JUSTIFY_RIGHT</property>
</widget>
<packing>
<property name="top_attach">1</property>
<property name="bottom_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkEntry" id="name">
<property name="visible">True</property>
</widget>
<packing>
<property name="left_attach">1</property>
<property name="right_attach">2</property>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
<child>
<widget class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="label" translatable="yes">Connection _name</property>
<property name="use_underline">True</property>
<property name="justify">GTK_JUSTIFY_FILL</property>
</widget>
<packing>
<property name="x_options">GTK_FILL</property>
<property name="y_options">GTK_FILL</property>
</packing>
</child>
</widget>
</child>
</widget>
</glade-interface>

View File

@ -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}

View File

@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 <daemon.h>
#include <processing/jobs/callback_job.h>
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;
}

View File

@ -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 <plugins/plugin.h>
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_ @}*/

View File

@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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-setting-vpn.h>
#include <nm-setting-vpn-properties.h>
#include "nm_service.h"
#include <daemon.h>
#include <utils/host.h>
#include <utils/identification.h>
#include <config/peer_cfg.h>
#include <stdio.h>
#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<<bit & from.ptr[byte]) != (1<<bit & to.ptr[byte]))
{
*mask = ((7 - bit) + (byte * 8));
found = TRUE;
break;
}
}
if (found)
{
break;
}
}
net = *(u_int32_t*)from.ptr;
chunk_free(&from);
chunk_free(&to);
return net;
}
/**
* signal IPv4 config to NM, set connection as established
*/
static void signal_ipv4_config(NMVPNPlugin *plugin, child_sa_t *child_sa)
{
linked_list_t *list;
traffic_selector_t *ts = NULL;
enumerator_t *enumerator;
list = child_sa->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);
}

View File

@ -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 <http://www.fsf.org/copyleft/gpl.txt>.
*
* 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 <glib/gtypes.h>
#include <glib-object.h>
#include <nm-vpn-plugin.h>
#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_ */