2008-11-14 17:41:16 +00:00
|
|
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
|
|
/*
|
|
|
|
* libnm_glib -- Access network status & information from glib applications
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the
|
|
|
|
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301 USA.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2007 - 2008 Novell, Inc.
|
|
|
|
* Copyright (C) 2007 - 2008 Red Hat, Inc.
|
|
|
|
*/
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
#include <signal.h>
|
2008-12-31 23:57:36 +00:00
|
|
|
#include "nm-glib-compat.h"
|
2007-09-12 16:23:53 +00:00
|
|
|
#include "nm-vpn-plugin.h"
|
2012-02-08 17:56:52 +00:00
|
|
|
#include "nm-vpn-enum-types.h"
|
2007-09-12 16:23:53 +00:00
|
|
|
#include "nm-utils.h"
|
2007-09-27 02:20:53 +00:00
|
|
|
#include "nm-connection.h"
|
2008-03-24 15:17:30 +00:00
|
|
|
#include "nm-dbus-glib-types.h"
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
static gboolean impl_vpn_plugin_connect (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GHashTable *connection,
|
|
|
|
GError **err);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
2007-09-27 02:20:53 +00:00
|
|
|
static gboolean impl_vpn_plugin_need_secrets (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GHashTable *connection,
|
|
|
|
char **service_name,
|
|
|
|
GError **err);
|
2007-09-27 02:20:53 +00:00
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean impl_vpn_plugin_disconnect (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GError **err);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
static gboolean impl_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *config,
|
|
|
|
GError **err);
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean impl_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GHashTable *config,
|
|
|
|
GError **err);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
static gboolean impl_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *config,
|
|
|
|
GError **err);
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean impl_vpn_plugin_set_failure (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
char *reason,
|
|
|
|
GError **err);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
#include "nm-vpn-plugin-glue.h"
|
|
|
|
|
2008-12-31 23:57:36 +00:00
|
|
|
#define NM_VPN_PLUGIN_CONNECT_TIMER 60
|
|
|
|
#define NM_VPN_PLUGIN_QUIT_TIMER 20
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (NMVPNPlugin, nm_vpn_plugin, G_TYPE_OBJECT)
|
|
|
|
|
|
|
|
typedef struct {
|
|
|
|
NMVPNServiceState state;
|
|
|
|
|
|
|
|
/* DBUS-y stuff */
|
|
|
|
DBusGConnection *connection;
|
|
|
|
char *dbus_service_name;
|
|
|
|
|
|
|
|
/* Temporary stuff */
|
|
|
|
guint connect_timer;
|
|
|
|
guint quit_timer;
|
2008-08-11 01:47:09 +00:00
|
|
|
guint fail_stop_id;
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
|
2012-06-11 15:14:38 +00:00
|
|
|
gboolean got_config;
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
gboolean has_ip4, got_ip4;
|
|
|
|
gboolean has_ip6, got_ip6;
|
|
|
|
|
|
|
|
/* Config stuff copied from config to ip4config */
|
|
|
|
GValue banner, tundev, gateway, mtu;
|
2007-09-12 16:23:53 +00:00
|
|
|
} NMVPNPluginPrivate;
|
|
|
|
|
|
|
|
#define NM_VPN_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_PLUGIN, NMVPNPluginPrivate))
|
|
|
|
|
|
|
|
enum {
|
|
|
|
STATE_CHANGED,
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
CONFIG,
|
2007-09-12 16:23:53 +00:00
|
|
|
IP4_CONFIG,
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
IP6_CONFIG,
|
2007-09-12 16:23:53 +00:00
|
|
|
LOGIN_BANNER,
|
|
|
|
FAILURE,
|
|
|
|
QUIT,
|
|
|
|
|
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
|
|
|
static guint signals[LAST_SIGNAL] = { 0 };
|
|
|
|
|
|
|
|
enum {
|
|
|
|
PROP_0,
|
|
|
|
PROP_DBUS_SERVICE_NAME,
|
|
|
|
PROP_STATE,
|
|
|
|
|
|
|
|
LAST_PROP
|
|
|
|
};
|
|
|
|
|
|
|
|
static GSList *active_plugins = NULL;
|
|
|
|
|
|
|
|
|
|
|
|
GQuark
|
|
|
|
nm_vpn_plugin_error_quark (void)
|
|
|
|
{
|
|
|
|
static GQuark quark = 0;
|
|
|
|
|
|
|
|
if (!quark)
|
|
|
|
quark = g_quark_from_static_string ("nm_vpn_plugin_error");
|
|
|
|
|
|
|
|
return quark;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
nm_vpn_plugin_set_connection (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
DBusGConnection *connection)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
|
|
|
|
if (priv->connection)
|
|
|
|
dbus_g_connection_unref (priv->connection);
|
|
|
|
|
|
|
|
priv->connection = connection;
|
|
|
|
}
|
|
|
|
|
|
|
|
DBusGConnection *
|
|
|
|
nm_vpn_plugin_get_connection (NMVPNPlugin *plugin)
|
|
|
|
{
|
|
|
|
DBusGConnection *connection;
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), NULL);
|
|
|
|
|
|
|
|
connection = NM_VPN_PLUGIN_GET_PRIVATE (plugin)->connection;
|
|
|
|
|
|
|
|
if (connection)
|
|
|
|
dbus_g_connection_ref (connection);
|
|
|
|
|
|
|
|
return connection;
|
|
|
|
}
|
|
|
|
|
|
|
|
NMVPNServiceState
|
|
|
|
nm_vpn_plugin_get_state (NMVPNPlugin *plugin)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), NM_VPN_SERVICE_STATE_UNKNOWN);
|
|
|
|
|
|
|
|
return NM_VPN_PLUGIN_GET_PRIVATE (plugin)->state;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nm_vpn_plugin_set_state (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
NMVPNServiceState state)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
|
|
|
|
|
|
|
priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
if (priv->state != state) {
|
|
|
|
priv->state = state;
|
|
|
|
g_signal_emit (plugin, signals[STATE_CHANGED], 0, state);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nm_vpn_plugin_set_login_banner (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
const char *banner)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
|
|
|
g_return_if_fail (banner != NULL);
|
|
|
|
|
|
|
|
g_signal_emit (plugin, signals[LOGIN_BANNER], 0, banner);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
nm_vpn_plugin_failure (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
NMVPNPluginFailure reason)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
|
|
|
|
|
|
|
g_signal_emit (plugin, signals[FAILURE], 0, reason);
|
|
|
|
}
|
|
|
|
|
|
|
|
gboolean
|
|
|
|
nm_vpn_plugin_disconnect (NMVPNPlugin *plugin, GError **err)
|
|
|
|
{
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
NMVPNServiceState state;
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
|
|
|
|
|
|
|
|
state = nm_vpn_plugin_get_state (plugin);
|
|
|
|
switch (state) {
|
|
|
|
case NM_VPN_SERVICE_STATE_STOPPING:
|
|
|
|
g_set_error (err,
|
2012-05-04 13:53:19 +00:00
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
NM_VPN_PLUGIN_ERROR_STOPPING_IN_PROGRESS,
|
|
|
|
"%s",
|
|
|
|
"Could not process the request because the VPN connection is already being stopped.");
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
case NM_VPN_SERVICE_STATE_STOPPED:
|
|
|
|
g_set_error (err,
|
2012-05-04 13:53:19 +00:00
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
NM_VPN_PLUGIN_ERROR_ALREADY_STOPPED,
|
|
|
|
"%s",
|
|
|
|
"Could not process the request because no VPN connection was active.");
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
case NM_VPN_SERVICE_STATE_STARTING:
|
|
|
|
case NM_VPN_SERVICE_STATE_STARTED:
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPING);
|
|
|
|
ret = NM_VPN_PLUGIN_GET_CLASS (plugin)->disconnect (plugin, err);
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPED);
|
|
|
|
break;
|
2007-09-27 02:20:53 +00:00
|
|
|
case NM_VPN_SERVICE_STATE_INIT:
|
|
|
|
ret = TRUE;
|
|
|
|
break;
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
default:
|
2007-09-27 02:20:53 +00:00
|
|
|
g_warning ("Unhandled VPN service state %d", state);
|
2007-09-12 16:23:53 +00:00
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nm_vpn_plugin_emit_quit (NMVPNPlugin *plugin)
|
|
|
|
{
|
|
|
|
g_signal_emit (plugin, signals[QUIT], 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
connect_timer_expired (gpointer data)
|
|
|
|
{
|
|
|
|
NMVPNPlugin *plugin = NM_VPN_PLUGIN (data);
|
|
|
|
GError *err = NULL;
|
|
|
|
|
2011-02-23 17:42:04 +00:00
|
|
|
g_message ("Connect timer expired, disconnecting.");
|
2007-09-12 16:23:53 +00:00
|
|
|
nm_vpn_plugin_disconnect (plugin, &err);
|
|
|
|
if (err) {
|
2011-02-23 17:42:04 +00:00
|
|
|
g_warning ("Disconnect failed: %s", err->message);
|
2007-09-12 16:23:53 +00:00
|
|
|
g_error_free (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
quit_timer_expired (gpointer data)
|
|
|
|
{
|
|
|
|
NMVPNPlugin *plugin = NM_VPN_PLUGIN (data);
|
|
|
|
|
|
|
|
nm_vpn_plugin_emit_quit (plugin);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-08-11 01:47:09 +00:00
|
|
|
static gboolean
|
|
|
|
fail_stop (gpointer data)
|
|
|
|
{
|
|
|
|
NMVPNPlugin *plugin = NM_VPN_PLUGIN (data);
|
|
|
|
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPED);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean
|
|
|
|
nm_vpn_plugin_connect (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
NMConnection *connection,
|
|
|
|
GError **err)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
2008-08-11 01:47:09 +00:00
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
2007-09-12 16:23:53 +00:00
|
|
|
gboolean ret = FALSE;
|
|
|
|
NMVPNServiceState state;
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
|
|
|
|
|
|
|
|
state = nm_vpn_plugin_get_state (plugin);
|
|
|
|
switch (state) {
|
|
|
|
case NM_VPN_SERVICE_STATE_STARTING:
|
|
|
|
g_set_error (err,
|
2012-05-04 13:53:19 +00:00
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
NM_VPN_PLUGIN_ERROR_STARTING_IN_PROGRESS,
|
|
|
|
"%s",
|
|
|
|
"Could not process the request because the VPN connection is already being started.");
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
case NM_VPN_SERVICE_STATE_STARTED:
|
|
|
|
g_set_error (err,
|
2012-05-04 13:53:19 +00:00
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
NM_VPN_PLUGIN_ERROR_ALREADY_STARTED,
|
|
|
|
"%s",
|
|
|
|
"Could not process the request because a VPN connection was already active.");
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
case NM_VPN_SERVICE_STATE_STOPPING:
|
|
|
|
g_set_error (err,
|
2012-05-04 13:53:19 +00:00
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
NM_VPN_PLUGIN_ERROR_STOPPING_IN_PROGRESS,
|
|
|
|
"%s",
|
|
|
|
"Could not process the request because the VPN connection is being stopped.");
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
case NM_VPN_SERVICE_STATE_STOPPED:
|
|
|
|
case NM_VPN_SERVICE_STATE_INIT:
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING);
|
2007-09-26 15:42:09 +00:00
|
|
|
ret = NM_VPN_PLUGIN_GET_CLASS (plugin)->connect (plugin, connection, err);
|
2008-08-11 01:47:09 +00:00
|
|
|
if (!ret) {
|
|
|
|
/* Stop the plugin from and idle handler so that the Connect
|
|
|
|
* method return gets sent before the STOP StateChanged signal.
|
|
|
|
*/
|
|
|
|
if (priv->fail_stop_id)
|
|
|
|
g_source_remove (priv->fail_stop_id);
|
|
|
|
priv->fail_stop_id = g_idle_add (fail_stop, plugin);
|
|
|
|
}
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
void
|
|
|
|
nm_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *config)
|
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
GValue *val;
|
|
|
|
|
|
|
|
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
|
|
|
g_return_if_fail (config != NULL);
|
|
|
|
|
2012-06-11 15:14:38 +00:00
|
|
|
priv->got_config = TRUE;
|
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_HAS_IP4);
|
|
|
|
if (val && g_value_get_boolean (val))
|
|
|
|
priv->has_ip4 = TRUE;
|
|
|
|
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_HAS_IP6);
|
|
|
|
if (val && g_value_get_boolean (val))
|
|
|
|
priv->has_ip6 = TRUE;
|
|
|
|
|
|
|
|
g_warn_if_fail (priv->has_ip4 || priv->has_ip6);
|
|
|
|
|
|
|
|
/* Record the items that need to also be inserted into the
|
|
|
|
* ip4config, for compatibility with older daemons.
|
|
|
|
*/
|
|
|
|
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_BANNER);
|
|
|
|
if (val) {
|
|
|
|
g_value_init (&priv->banner, G_VALUE_TYPE (val));
|
|
|
|
g_value_copy (val, &priv->banner);
|
|
|
|
}
|
|
|
|
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_TUNDEV);
|
|
|
|
if (val) {
|
|
|
|
g_value_init (&priv->tundev, G_VALUE_TYPE (val));
|
|
|
|
g_value_copy (val, &priv->tundev);
|
|
|
|
}
|
|
|
|
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY);
|
|
|
|
if (val) {
|
|
|
|
g_value_init (&priv->gateway, G_VALUE_TYPE (val));
|
|
|
|
g_value_copy (val, &priv->gateway);
|
|
|
|
}
|
|
|
|
val = g_hash_table_lookup (config, NM_VPN_PLUGIN_CONFIG_MTU);
|
|
|
|
if (val) {
|
|
|
|
g_value_init (&priv->mtu, G_VALUE_TYPE (val));
|
|
|
|
g_value_copy (val, &priv->mtu);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_emit (plugin, signals[CONFIG], 0, config);
|
|
|
|
}
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
void
|
|
|
|
nm_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GHashTable *ip4_config)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
GHashTable *combined_config;
|
|
|
|
GHashTableIter iter;
|
|
|
|
gpointer key, value;
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
|
|
|
g_return_if_fail (ip4_config != NULL);
|
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
priv->got_ip4 = TRUE;
|
|
|
|
|
2012-06-11 15:14:38 +00:00
|
|
|
/* Old plugins won't send the "config" signal and thus can't send
|
|
|
|
* NM_VPN_PLUGIN_CONFIG_HAS_IP4 either. But since they don't support IPv6,
|
|
|
|
* we can safely assume that, if we don't receive a "config" signal but do
|
|
|
|
* receive an "ip4-config" signal, the old plugin supports IPv4.
|
|
|
|
*/
|
|
|
|
if (!priv->got_config)
|
|
|
|
priv->has_ip4 = TRUE;
|
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
/* Older NetworkManager daemons expect all config info to be in
|
|
|
|
* the ip4 config, so they won't even notice the "config" signal
|
|
|
|
* being emitted. So just copy all of that data into the ip4
|
|
|
|
* config too.
|
|
|
|
*/
|
|
|
|
combined_config = g_hash_table_new (g_str_hash, g_str_equal);
|
|
|
|
g_hash_table_iter_init (&iter, ip4_config);
|
|
|
|
while (g_hash_table_iter_next (&iter, &key, &value))
|
|
|
|
g_hash_table_insert (combined_config, key, value);
|
|
|
|
|
|
|
|
if (G_VALUE_TYPE (&priv->banner) != G_TYPE_INVALID)
|
|
|
|
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_BANNER, &priv->banner);
|
|
|
|
if (G_VALUE_TYPE (&priv->tundev) != G_TYPE_INVALID)
|
|
|
|
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, &priv->tundev);
|
|
|
|
if (G_VALUE_TYPE (&priv->gateway) != G_TYPE_INVALID)
|
|
|
|
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY, &priv->gateway);
|
|
|
|
if (G_VALUE_TYPE (&priv->mtu) != G_TYPE_INVALID)
|
|
|
|
g_hash_table_insert (combined_config, NM_VPN_PLUGIN_IP4_CONFIG_MTU, &priv->mtu);
|
|
|
|
|
|
|
|
g_signal_emit (plugin, signals[IP4_CONFIG], 0, combined_config);
|
|
|
|
g_hash_table_destroy (combined_config);
|
|
|
|
|
|
|
|
if ( priv->has_ip4 == priv->got_ip4
|
|
|
|
&& priv->has_ip6 == priv->got_ip6)
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED);
|
|
|
|
}
|
2007-09-12 16:23:53 +00:00
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
void
|
|
|
|
nm_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *ip6_config)
|
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
|
|
|
|
g_return_if_fail (NM_IS_VPN_PLUGIN (plugin));
|
|
|
|
g_return_if_fail (ip6_config != NULL);
|
|
|
|
|
|
|
|
priv->got_ip6 = TRUE;
|
|
|
|
g_signal_emit (plugin, signals[IP6_CONFIG], 0, ip6_config);
|
|
|
|
|
|
|
|
if ( priv->has_ip4 == priv->got_ip4
|
|
|
|
&& priv->has_ip6 == priv->got_ip6)
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED);
|
2007-09-12 16:23:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_connect (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GHashTable *properties,
|
|
|
|
GError **error)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
2007-09-26 15:42:09 +00:00
|
|
|
NMConnection *connection;
|
2008-06-12 23:58:08 +00:00
|
|
|
gboolean success = FALSE;
|
2007-09-26 15:42:09 +00:00
|
|
|
|
2008-06-12 23:58:08 +00:00
|
|
|
connection = nm_connection_new_from_hash (properties, error);
|
|
|
|
if (!connection) {
|
2011-02-23 17:42:04 +00:00
|
|
|
g_warning ("%s: Invalid connection: '%s' / '%s' invalid: %d",
|
|
|
|
__func__,
|
|
|
|
g_type_name (nm_connection_lookup_setting_type_by_quark ((*error)->domain)),
|
|
|
|
(*error)->message,
|
|
|
|
(*error)->code);
|
2008-06-12 23:58:08 +00:00
|
|
|
} else {
|
|
|
|
success = nm_vpn_plugin_connect (plugin, connection, error);
|
|
|
|
g_object_unref (connection);
|
|
|
|
}
|
2007-09-26 15:42:09 +00:00
|
|
|
|
|
|
|
return success;
|
2007-09-12 16:23:53 +00:00
|
|
|
}
|
|
|
|
|
2007-09-27 02:20:53 +00:00
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_need_secrets (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *properties,
|
|
|
|
char **setting_name,
|
|
|
|
GError **err)
|
|
|
|
{
|
|
|
|
gboolean ret = FALSE;
|
|
|
|
NMConnection *connection;
|
|
|
|
char *sn = NULL;
|
|
|
|
GError *ns_err = NULL;
|
2007-09-27 03:03:09 +00:00
|
|
|
gboolean needed = FALSE;
|
2008-06-12 23:58:08 +00:00
|
|
|
GError *cnfh_err = NULL;
|
2007-09-27 02:20:53 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
|
|
|
|
g_return_val_if_fail (properties != NULL, FALSE);
|
|
|
|
|
2008-06-12 23:58:08 +00:00
|
|
|
connection = nm_connection_new_from_hash (properties, &cnfh_err);
|
2007-09-27 02:20:53 +00:00
|
|
|
if (!connection) {
|
|
|
|
g_set_error (err,
|
|
|
|
NM_VPN_PLUGIN_ERROR,
|
|
|
|
NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
|
2008-06-12 23:58:08 +00:00
|
|
|
"The connection was invalid: '%s' / '%s' invalid: %d.",
|
|
|
|
g_type_name (nm_connection_lookup_setting_type_by_quark (cnfh_err->domain)),
|
|
|
|
cnfh_err->message, cnfh_err->code);
|
|
|
|
g_error_free (cnfh_err);
|
2007-09-27 02:20:53 +00:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!NM_VPN_PLUGIN_GET_CLASS (plugin)->need_secrets) {
|
|
|
|
*setting_name = "";
|
|
|
|
ret = TRUE;
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
2007-09-27 03:03:09 +00:00
|
|
|
needed = NM_VPN_PLUGIN_GET_CLASS (plugin)->need_secrets (plugin, connection, &sn, &ns_err);
|
|
|
|
if (ns_err) {
|
|
|
|
*err = g_error_copy (ns_err);
|
|
|
|
g_error_free (ns_err);
|
|
|
|
goto out;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = TRUE;
|
|
|
|
if (needed) {
|
2007-09-27 02:20:53 +00:00
|
|
|
g_assert (sn);
|
|
|
|
*setting_name = g_strdup (sn);
|
|
|
|
} else {
|
2007-09-27 03:03:09 +00:00
|
|
|
/* No secrets required */
|
|
|
|
*setting_name = g_strdup ("");
|
2007-09-27 02:20:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
out:
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_disconnect (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GError **err)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
return nm_vpn_plugin_disconnect (plugin, err);
|
|
|
|
}
|
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_set_config (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *config,
|
|
|
|
GError **err)
|
|
|
|
{
|
|
|
|
nm_vpn_plugin_set_config (plugin, config);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_set_ip4_config (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
GHashTable *config,
|
|
|
|
GError **err)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
nm_vpn_plugin_set_ip4_config (plugin, config);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_set_ip6_config (NMVPNPlugin *plugin,
|
|
|
|
GHashTable *config,
|
|
|
|
GError **err)
|
|
|
|
{
|
|
|
|
nm_vpn_plugin_set_ip6_config (plugin, config);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
static gboolean
|
|
|
|
impl_vpn_plugin_set_failure (NMVPNPlugin *plugin,
|
2012-05-04 13:53:19 +00:00
|
|
|
char *reason,
|
|
|
|
GError **err)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
nm_vpn_plugin_failure (plugin, NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
sigterm_handler (int signum)
|
|
|
|
{
|
|
|
|
g_slist_foreach (active_plugins, (GFunc) nm_vpn_plugin_emit_quit, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
setup_unix_signal_handler (void)
|
|
|
|
{
|
|
|
|
struct sigaction action;
|
|
|
|
sigset_t block_mask;
|
|
|
|
|
|
|
|
action.sa_handler = sigterm_handler;
|
|
|
|
sigemptyset (&block_mask);
|
|
|
|
action.sa_mask = block_mask;
|
|
|
|
action.sa_flags = 0;
|
|
|
|
sigaction (SIGINT, &action, NULL);
|
|
|
|
sigaction (SIGTERM, &action, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*********************************************************************/
|
|
|
|
|
|
|
|
static void
|
|
|
|
one_plugin_destroyed (gpointer data,
|
2012-05-04 13:53:19 +00:00
|
|
|
GObject *object)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
active_plugins = g_slist_remove (active_plugins, object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nm_vpn_plugin_init (NMVPNPlugin *plugin)
|
|
|
|
{
|
|
|
|
active_plugins = g_slist_append (active_plugins, plugin);
|
|
|
|
g_object_weak_ref (G_OBJECT (plugin),
|
|
|
|
one_plugin_destroyed,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
static GObject *
|
|
|
|
constructor (GType type,
|
2012-05-04 13:53:19 +00:00
|
|
|
guint n_construct_params,
|
|
|
|
GObjectConstructParam *construct_params)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
GObject *object;
|
|
|
|
NMVPNPlugin *plugin;
|
|
|
|
NMVPNPluginPrivate *priv;
|
|
|
|
DBusGConnection *connection;
|
|
|
|
DBusGProxy *proxy;
|
|
|
|
guint request_name_result;
|
|
|
|
GError *err = NULL;
|
|
|
|
|
|
|
|
object = G_OBJECT_CLASS (nm_vpn_plugin_parent_class)->constructor (type,
|
|
|
|
n_construct_params,
|
|
|
|
construct_params);
|
|
|
|
if (!object)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
priv = NM_VPN_PLUGIN_GET_PRIVATE (object);
|
|
|
|
if (!priv->dbus_service_name)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
connection = dbus_g_bus_get (DBUS_BUS_SYSTEM, &err);
|
|
|
|
if (!connection)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
proxy = dbus_g_proxy_new_for_name (connection,
|
2012-05-04 13:53:19 +00:00
|
|
|
"org.freedesktop.DBus",
|
|
|
|
"/org/freedesktop/DBus",
|
|
|
|
"org.freedesktop.DBus");
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
if (!dbus_g_proxy_call (proxy, "RequestName", &err,
|
2012-05-04 13:53:19 +00:00
|
|
|
G_TYPE_STRING, priv->dbus_service_name,
|
|
|
|
G_TYPE_UINT, 0,
|
|
|
|
G_TYPE_INVALID,
|
|
|
|
G_TYPE_UINT, &request_name_result,
|
|
|
|
G_TYPE_INVALID)) {
|
2007-09-12 16:23:53 +00:00
|
|
|
g_object_unref (proxy);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
g_object_unref (proxy);
|
|
|
|
|
|
|
|
dbus_g_connection_register_g_object (connection,
|
2012-05-04 13:53:19 +00:00
|
|
|
NM_VPN_DBUS_PLUGIN_PATH,
|
|
|
|
object);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
plugin = NM_VPN_PLUGIN (object);
|
|
|
|
|
|
|
|
nm_vpn_plugin_set_connection (plugin, connection);
|
|
|
|
nm_vpn_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_INIT);
|
|
|
|
|
|
|
|
return object;
|
|
|
|
|
|
|
|
err:
|
|
|
|
if (err) {
|
2011-02-23 17:42:04 +00:00
|
|
|
g_warning ("Failed to initialize VPN plugin: %s", err->message);
|
2007-09-12 16:23:53 +00:00
|
|
|
g_error_free (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (object)
|
|
|
|
g_object_unref (object);
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
set_property (GObject *object, guint prop_id,
|
2012-05-04 13:53:19 +00:00
|
|
|
const GValue *value, GParamSpec *pspec)
|
2007-09-12 16:23:53 +00:00
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (object);
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
case PROP_DBUS_SERVICE_NAME:
|
|
|
|
/* Construct-only */
|
|
|
|
priv->dbus_service_name = g_strdup (g_value_get_string (value));
|
|
|
|
break;
|
|
|
|
case PROP_STATE:
|
|
|
|
nm_vpn_plugin_set_state (NM_VPN_PLUGIN (object),
|
2012-05-04 13:53:19 +00:00
|
|
|
(NMVPNServiceState) g_value_get_uint (value));
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
get_property (GObject *object, guint prop_id,
|
|
|
|
GValue *value, GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (object);
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
case PROP_DBUS_SERVICE_NAME:
|
|
|
|
g_value_set_string (value, priv->dbus_service_name);
|
|
|
|
break;
|
|
|
|
case PROP_STATE:
|
|
|
|
g_value_set_uint (value, nm_vpn_plugin_get_state (NM_VPN_PLUGIN (object)));
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
dispose (GObject *object)
|
|
|
|
{
|
|
|
|
NMVPNPlugin *plugin = NM_VPN_PLUGIN (object);
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
NMVPNServiceState state;
|
|
|
|
GError *err = NULL;
|
|
|
|
|
2012-04-23 15:02:48 +00:00
|
|
|
if (priv->fail_stop_id) {
|
2008-08-11 01:47:09 +00:00
|
|
|
g_source_remove (priv->fail_stop_id);
|
2012-04-23 15:02:48 +00:00
|
|
|
priv->fail_stop_id = 0;
|
|
|
|
}
|
2008-08-11 01:47:09 +00:00
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
state = nm_vpn_plugin_get_state (plugin);
|
|
|
|
|
|
|
|
if (state == NM_VPN_SERVICE_STATE_STARTED ||
|
|
|
|
state == NM_VPN_SERVICE_STATE_STARTING)
|
|
|
|
nm_vpn_plugin_disconnect (plugin, &err);
|
|
|
|
|
|
|
|
if (err) {
|
2011-02-23 17:42:04 +00:00
|
|
|
g_warning ("Error disconnecting VPN connection: %s", err->message);
|
2007-09-12 16:23:53 +00:00
|
|
|
g_error_free (err);
|
|
|
|
}
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (nm_vpn_plugin_parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
finalize (GObject *object)
|
|
|
|
{
|
|
|
|
NMVPNPlugin *plugin = NM_VPN_PLUGIN (object);
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
|
|
|
|
nm_vpn_plugin_set_connection (plugin, NULL);
|
|
|
|
g_free (priv->dbus_service_name);
|
|
|
|
|
2012-06-14 23:05:16 +00:00
|
|
|
if (G_IS_VALUE (&priv->banner))
|
|
|
|
g_value_unset (&priv->banner);
|
|
|
|
if (G_IS_VALUE (&priv->tundev))
|
|
|
|
g_value_unset (&priv->tundev);
|
|
|
|
if (G_IS_VALUE (&priv->gateway))
|
|
|
|
g_value_unset (&priv->gateway);
|
|
|
|
if (G_IS_VALUE (&priv->mtu))
|
|
|
|
g_value_unset (&priv->mtu);
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
G_OBJECT_CLASS (nm_vpn_plugin_parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
connect_timer_removed (gpointer data)
|
|
|
|
{
|
|
|
|
NM_VPN_PLUGIN_GET_PRIVATE (data)->connect_timer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
quit_timer_removed (gpointer data)
|
|
|
|
{
|
|
|
|
NM_VPN_PLUGIN_GET_PRIVATE (data)->quit_timer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
state_changed (NMVPNPlugin *plugin, NMVPNServiceState state)
|
|
|
|
{
|
|
|
|
NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
|
|
|
|
|
|
|
|
switch (state) {
|
|
|
|
case NM_VPN_SERVICE_STATE_STARTING:
|
|
|
|
/* Remove the quit timer. */
|
|
|
|
if (priv->quit_timer)
|
|
|
|
g_source_remove (priv->quit_timer);
|
|
|
|
|
2008-08-11 01:47:09 +00:00
|
|
|
if (priv->fail_stop_id) {
|
|
|
|
g_source_remove (priv->fail_stop_id);
|
|
|
|
priv->fail_stop_id = 0;
|
|
|
|
}
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
/* Add a timer to make sure we do not wait indefinitely for the successful connect. */
|
2008-12-31 23:57:36 +00:00
|
|
|
priv->connect_timer = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
|
|
|
|
NM_VPN_PLUGIN_CONNECT_TIMER,
|
|
|
|
connect_timer_expired,
|
|
|
|
plugin,
|
|
|
|
connect_timer_removed);
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
case NM_VPN_SERVICE_STATE_STOPPED:
|
2008-12-31 23:57:36 +00:00
|
|
|
priv->quit_timer = g_timeout_add_seconds_full (G_PRIORITY_DEFAULT,
|
|
|
|
NM_VPN_PLUGIN_QUIT_TIMER,
|
|
|
|
quit_timer_expired,
|
|
|
|
plugin,
|
|
|
|
quit_timer_removed);
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Clean up all timers we might have set up. */
|
|
|
|
if (priv->connect_timer)
|
|
|
|
g_source_remove (priv->connect_timer);
|
|
|
|
|
|
|
|
if (priv->quit_timer)
|
|
|
|
g_source_remove (priv->quit_timer);
|
|
|
|
|
2008-08-11 01:47:09 +00:00
|
|
|
if (priv->fail_stop_id) {
|
|
|
|
g_source_remove (priv->fail_stop_id);
|
|
|
|
priv->fail_stop_id = 0;
|
|
|
|
}
|
2007-09-12 16:23:53 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
nm_vpn_plugin_class_init (NMVPNPluginClass *plugin_class)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (plugin_class);
|
|
|
|
|
|
|
|
g_type_class_add_private (object_class, sizeof (NMVPNPluginPrivate));
|
|
|
|
|
|
|
|
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (plugin_class),
|
2012-05-04 13:53:19 +00:00
|
|
|
&dbus_glib_nm_vpn_plugin_object_info);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
/* virtual methods */
|
|
|
|
object_class->constructor = constructor;
|
|
|
|
object_class->set_property = set_property;
|
|
|
|
object_class->get_property = get_property;
|
|
|
|
object_class->dispose = dispose;
|
|
|
|
object_class->finalize = finalize;
|
|
|
|
|
|
|
|
plugin_class->state_changed = state_changed;
|
|
|
|
|
|
|
|
/* properties */
|
|
|
|
g_object_class_install_property
|
|
|
|
(object_class, PROP_DBUS_SERVICE_NAME,
|
|
|
|
g_param_spec_string (NM_VPN_PLUGIN_DBUS_SERVICE_NAME,
|
2012-05-04 13:53:19 +00:00
|
|
|
"DBus service name",
|
|
|
|
"DBus service name",
|
|
|
|
NULL,
|
|
|
|
G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
g_object_class_install_property
|
|
|
|
(object_class, PROP_STATE,
|
|
|
|
g_param_spec_uint (NM_VPN_PLUGIN_STATE,
|
2012-05-04 13:53:19 +00:00
|
|
|
"State",
|
|
|
|
"Current VPN service state",
|
|
|
|
NM_VPN_SERVICE_STATE_UNKNOWN,
|
|
|
|
NM_VPN_SERVICE_STATE_STOPPED,
|
|
|
|
NM_VPN_SERVICE_STATE_INIT,
|
|
|
|
G_PARAM_READWRITE));
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
/* signals */
|
|
|
|
signals[STATE_CHANGED] =
|
|
|
|
g_signal_new ("state-changed",
|
2012-05-04 13:53:19 +00:00
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, state_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__UINT,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_UINT);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
signals[CONFIG] =
|
|
|
|
g_signal_new ("config",
|
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, config),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__BOXED,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
DBUS_TYPE_G_MAP_OF_VARIANT);
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
signals[IP4_CONFIG] =
|
|
|
|
g_signal_new ("ip4-config",
|
2012-05-04 13:53:19 +00:00
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, ip4_config),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__BOXED,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
DBUS_TYPE_G_MAP_OF_VARIANT);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
vpn: support IPv6 over VPNs
Add new API to allow passing both IPv4 and IPv6 configuration
information from VPN plugins to the backend.
Now instead of a single Ip4Config, a plugin has Config, Ip4Config, and
Ip6Config. "Config" contains information which is neither IPv4 nor
IPv6 specific, and also indicates which of Ip4Config and Ip6Config are
present. Ip4Config now only contains the IPv4-specific bits of
configuration.
There is backward compatibility in both directions: if the daemon is
new and the VPN plugin is old, then NM will notice that the plugin
emitted the Ip4Config signal without having emitted the Config signal
first, and so will assume that it is IPv4-only, and that the generic
bits of configuration have been included with the Ip4Config. If the
daemon is old and the plugin is new, then NMVPNPlugin will copy the
values from the generic config into the IPv4 config as well. (In fact,
NMVPNPlugin *always* does this, because it's harmless, and it's easier
than actually checking the daemon version.)
Currently the VPN is still configured all-at-once, after both IPv4 and
IPv6 information has been received, but the APIs allow for the
possibility of configuring them one at a time in the future.
2012-05-04 19:50:07 +00:00
|
|
|
signals[IP6_CONFIG] =
|
|
|
|
g_signal_new ("ip6-config",
|
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, ip6_config),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__BOXED,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
DBUS_TYPE_G_MAP_OF_VARIANT);
|
|
|
|
|
2007-09-12 16:23:53 +00:00
|
|
|
signals[LOGIN_BANNER] =
|
|
|
|
g_signal_new ("login-banner",
|
2012-05-04 13:53:19 +00:00
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, login_banner),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__STRING,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_STRING);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
signals[FAILURE] =
|
|
|
|
g_signal_new ("failure",
|
2012-05-04 13:53:19 +00:00
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, failure),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__UINT,
|
|
|
|
G_TYPE_NONE, 1,
|
|
|
|
G_TYPE_UINT);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
signals[QUIT] =
|
|
|
|
g_signal_new ("quit",
|
2012-05-04 13:53:19 +00:00
|
|
|
G_OBJECT_CLASS_TYPE (object_class),
|
|
|
|
G_SIGNAL_RUN_FIRST,
|
|
|
|
G_STRUCT_OFFSET (NMVPNPluginClass, quit),
|
|
|
|
NULL, NULL,
|
|
|
|
g_cclosure_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0,
|
|
|
|
G_TYPE_NONE);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
dbus_g_error_domain_register (NM_VPN_PLUGIN_ERROR,
|
2012-05-04 13:53:19 +00:00
|
|
|
NULL,
|
|
|
|
NM_TYPE_VPN_PLUGIN_ERROR);
|
2007-09-12 16:23:53 +00:00
|
|
|
|
|
|
|
setup_unix_signal_handler ();
|
|
|
|
}
|