From 4f98910848bddc4761b5b9264cebf40fc2ec6c55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ji=C5=99=C3=AD=20Klime=C5=A1?= Date: Thu, 21 May 2015 13:19:02 +0200 Subject: [PATCH 01/14] libnm: NMVpnPluginOld fixes Change a{ss} to a{sv} because not all values are strings and never were. https://bugzilla.gnome.org/show_bug.cgi?id=749686 --- libnm/nm-vpn-plugin-old.c | 53 +++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/libnm/nm-vpn-plugin-old.c b/libnm/nm-vpn-plugin-old.c index 5748060ff0..9f3bc058c4 100644 --- a/libnm/nm-vpn-plugin-old.c +++ b/libnm/nm-vpn-plugin-old.c @@ -70,7 +70,7 @@ typedef struct { gboolean has_ip6, got_ip6; /* Config stuff copied from config to ip4config */ - char *banner, *tundev, *gateway, *mtu; + GVariant *banner, *tundev, *gateway, *mtu; } NMVpnPluginOldPrivate; #define NM_VPN_PLUGIN_OLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldPrivate)) @@ -300,14 +300,22 @@ nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, /* Record the items that need to also be inserted into the * ip4config, for compatibility with older daemons. */ - g_clear_pointer (&priv->banner, g_free); - (void) g_variant_lookup (config, NM_VPN_PLUGIN_CONFIG_BANNER, "&s", &priv->banner); - g_clear_pointer (&priv->tundev, g_free); - (void) g_variant_lookup (config, NM_VPN_PLUGIN_CONFIG_TUNDEV, "&s", &priv->tundev); - g_clear_pointer (&priv->gateway, g_free); - (void) g_variant_lookup (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, "&s", &priv->gateway); - g_clear_pointer (&priv->mtu, g_free); - (void) g_variant_lookup (config, NM_VPN_PLUGIN_CONFIG_MTU, "&s", &priv->mtu); + if (priv->banner) + g_variant_unref (priv->banner); + priv->banner = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_BANNER, + G_VARIANT_TYPE ("s")); + if (priv->tundev) + g_variant_unref (priv->tundev); + priv->tundev = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_TUNDEV, + G_VARIANT_TYPE ("s")); + if (priv->gateway) + g_variant_unref (priv->gateway); + priv->gateway = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, + G_VARIANT_TYPE ("u")); + if (priv->mtu) + g_variant_unref (priv->mtu); + priv->mtu = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_MTU, + G_VARIANT_TYPE ("u")); g_signal_emit (plugin, signals[CONFIG], 0, config); } @@ -320,7 +328,8 @@ nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, GVariant *combined_config; GVariantBuilder builder; GVariantIter iter; - const char *key, *value; + const char *key; + GVariant *value; g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); g_return_if_fail (ip4_config != NULL); @@ -340,19 +349,21 @@ nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, * being emitted. So just copy all of that data into the ip4 * config too. */ - g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{ss}")); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); g_variant_iter_init (&iter, ip4_config); - while (g_variant_iter_next (&iter, "{&s&s}", &key, &value)) - g_variant_builder_add (&builder, "{ss}", key, value); + while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) { + g_variant_builder_add (&builder, "{sv}", key, value); + g_variant_unref (value); + } if (priv->banner) - g_variant_builder_add (&builder, "{ss}", NM_VPN_PLUGIN_IP4_CONFIG_BANNER, &priv->banner); + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_BANNER, &priv->banner); if (priv->tundev) - g_variant_builder_add (&builder, "{ss}", NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, &priv->tundev); + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, &priv->tundev); if (priv->gateway) - g_variant_builder_add (&builder, "{ss}", NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY, &priv->gateway); + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY, &priv->gateway); if (priv->mtu) - g_variant_builder_add (&builder, "{ss}", NM_VPN_PLUGIN_IP4_CONFIG_MTU, &priv->mtu); + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_MTU, &priv->mtu); combined_config = g_variant_builder_end (&builder); g_variant_ref_sink (combined_config); @@ -1026,10 +1037,10 @@ finalize (GObject *object) nm_vpn_plugin_old_set_connection (plugin, NULL); g_free (priv->dbus_service_name); - g_clear_pointer (&priv->banner, g_free); - g_clear_pointer (&priv->tundev, g_free); - g_clear_pointer (&priv->gateway, g_free); - g_clear_pointer (&priv->mtu, g_free); + g_clear_pointer (&priv->banner, g_variant_unref); + g_clear_pointer (&priv->tundev, g_variant_unref); + g_clear_pointer (&priv->gateway, g_variant_unref); + g_clear_pointer (&priv->mtu, g_variant_unref); G_OBJECT_CLASS (nm_vpn_plugin_old_parent_class)->finalize (object); } From ec92ecedae28c9b7e78c2de5bc378fc7afc9eaf0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 22 May 2015 18:52:22 +0200 Subject: [PATCH 02/14] libnm: add NMUtilsStrStrDictKey utility When having a hash-of-hashes where each hash is indexed by a name, (such as GKeyFile), you can either implement it as a hash-of-hashes or define your own version of indexes that pack both levels of names into one key. This is an implementation of such a key. Use it as: GHashTable *hash = g_hash_table_new_full (_nm_utils_strstrdictkey_hash, _nm_utils_strstrdictkey_equal, g_free, _destroy_value); and create keys via: NMUtilsStrStrDictKey *k = _nm_utils_strstrdictkey_create (s1, s2); For lookup you can use static strings (note that the static string might increase the size of the binary): g_hash_table_contains (hash, _nm_utils_strstrdictkey_static ("outer", "inner")) --- libnm-core/nm-core-internal.h | 10 ++++ libnm-core/nm-utils.c | 99 +++++++++++++++++++++++++++++++++ libnm-core/tests/test-general.c | 49 ++++++++++++++++ 3 files changed, 158 insertions(+) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 2ff9e5348e..ac61737e47 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -202,4 +202,14 @@ int _nm_utils_dns_option_find_idx (GPtrArray *array, const char *option) /***********************************************************/ +typedef struct _NMUtilsStrStrDictKey NMUtilsStrStrDictKey; +guint _nm_utils_strstrdictkey_hash (gconstpointer a); +gboolean _nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b); +NMUtilsStrStrDictKey *_nm_utils_strstrdictkey_create (const char *v1, const char *v2); + +#define _nm_utils_strstrdictkey_static(v1, v2) \ + ( (NMUtilsStrStrDictKey *) ("\03" v1 "\0" v2 "") ) + +/***********************************************************/ + #endif diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index f6a9e5a05a..fec3999bce 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -3488,6 +3488,105 @@ nm_utils_bond_mode_string_to_int (const char *mode) /**********************************************************************************************/ +#define STRSTRDICTKEY_V1_SET 0x01 +#define STRSTRDICTKEY_V2_SET 0x02 +#define STRSTRDICTKEY_ALL_SET 0x03 + +struct _NMUtilsStrStrDictKey { + char type; + char data[1]; +}; + +guint +_nm_utils_strstrdictkey_hash (gconstpointer a) +{ + const NMUtilsStrStrDictKey *k = a; + const signed char *p; + guint32 h = 5381; + + if (k) { + if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET) + g_return_val_if_reached (0); + + h = (h << 5) + h + k->type; + if (k->type & STRSTRDICTKEY_ALL_SET) { + p = (void *) k->data; + for (; *p != '\0'; p++) + h = (h << 5) + h + *p; + if (k->type == STRSTRDICTKEY_ALL_SET) { + /* the key contains two strings. Continue... */ + h = (h << 5) + h + '\0'; + for (p++; *p != '\0'; p++) + h = (h << 5) + h + *p; + } + } + } + + return h; +} + +gboolean +_nm_utils_strstrdictkey_equal (gconstpointer a, gconstpointer b) +{ + const NMUtilsStrStrDictKey *k1 = a; + const NMUtilsStrStrDictKey *k2 = b; + + if (k1 == k2) + return TRUE; + if (!k1 || !k2) + return FALSE; + + if (k1->type != k2->type) + return FALSE; + + if (k1->type & STRSTRDICTKEY_ALL_SET) { + if (strcmp (k1->data, k2->data) != 0) + return FALSE; + + if (k1->type == STRSTRDICTKEY_ALL_SET) { + gsize l = strlen (k1->data) + 1; + + return strcmp (&k1->data[l], &k2->data[l]) == 0; + } + } + + return TRUE; +} + +NMUtilsStrStrDictKey * +_nm_utils_strstrdictkey_create (const char *v1, const char *v2) +{ + char type = 0; + gsize l1 = 0, l2 = 0; + NMUtilsStrStrDictKey *k; + + if (!v1 && !v2) + return g_malloc0 (1); + + /* we need to distinguish between ("",NULL) and (NULL,""). + * Thus, in @type we encode which strings we have present + * as not-NULL. */ + if (v1) { + type |= STRSTRDICTKEY_V1_SET; + l1 = strlen (v1) + 1; + } + if (v2) { + type |= STRSTRDICTKEY_V2_SET; + l2 = strlen (v2) + 1; + } + + k = g_malloc (G_STRUCT_OFFSET (NMUtilsStrStrDictKey, data) + l1 + l2); + k->type = type; + if (v1) + memcpy (&k->data[0], v1, l1); + if (v2) + memcpy (&k->data[l1], v2, l2); + + return k; +} + +/**********************************************************************************************/ + /* _nm_utils_ascii_str_to_int64: * * A wrapper for g_ascii_strtoll, that checks whether the whole string diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index e8e96bb756..dfe591298e 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -4281,6 +4281,54 @@ test_nm_utils_ascii_str_to_int64 (void) /******************************************************************************/ +static void +test_nm_utils_strstrdictkey () +{ +#define _VALUES_STATIC(_v1, _v2) { .v1 = _v1, .v2 = _v2, .v_static = _nm_utils_strstrdictkey_static (_v1, _v2), } + const struct { + const char *v1; + const char *v2; + NMUtilsStrStrDictKey *v_static; + } *val1, *val2, values[] = { + { NULL, NULL }, + { "", NULL }, + { NULL, "" }, + { "a", NULL }, + { NULL, "a" }, + _VALUES_STATIC ("", ""), + _VALUES_STATIC ("a", ""), + _VALUES_STATIC ("", "a"), + _VALUES_STATIC ("a", "b"), + }; + guint i, j; + + for (i = 0; i < G_N_ELEMENTS (values); i++) { + gs_free NMUtilsStrStrDictKey *key1 = NULL; + + val1 = &values[i]; + + key1 = _nm_utils_strstrdictkey_create (val1->v1, val1->v2); + if (val1->v_static) { + g_assert (_nm_utils_strstrdictkey_equal (key1, val1->v_static)); + g_assert (_nm_utils_strstrdictkey_equal (val1->v_static, key1)); + g_assert_cmpint (_nm_utils_strstrdictkey_hash (key1), ==, _nm_utils_strstrdictkey_hash (val1->v_static)); + } + + for (j = 0; j < G_N_ELEMENTS (values); j++) { + gs_free NMUtilsStrStrDictKey *key2 = NULL; + + val2 = &values[j]; + key2 = _nm_utils_strstrdictkey_create (val2->v1, val2->v2); + if (i != j) { + g_assert (!_nm_utils_strstrdictkey_equal (key1, key2)); + g_assert (!_nm_utils_strstrdictkey_equal (key2, key1)); + } + } + } +} + +/******************************************************************************/ + static void test_nm_utils_dns_option_validate_do (char *option, gboolean ipv6, const NMUtilsDNSOptionDesc *descs, gboolean exp_result, char *exp_name, gboolean exp_value) @@ -4764,6 +4812,7 @@ int main (int argc, char **argv) g_test_add_func ("/core/general/nm_utils_is_power_of_two", test_nm_utils_is_power_of_two); g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert); g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search); + g_test_add_func ("/core/general/_nm_utils_strstrdictkey", test_nm_utils_strstrdictkey); g_test_add_func ("/core/general/_nm_utils_dns_option_validate", test_nm_utils_dns_option_validate); g_test_add_func ("/core/general/_nm_utils_dns_option_find_idx", test_nm_utils_dns_option_find_idx); From ed381cb1e27d989a04b608b8ab3d67daebe58bfb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 28 May 2015 21:52:24 +0200 Subject: [PATCH 03/14] libnm: add _nm_utils_check_file() util --- libnm-core/nm-core-internal.h | 7 ++++ libnm-core/nm-utils.c | 71 +++++++++++++++++++++++++++++++++++ libnm-core/nm-utils.h | 4 ++ 3 files changed, 82 insertions(+) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index ac61737e47..1287b7a2f0 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -136,6 +136,13 @@ char ** _nm_utils_slist_to_strv (GSList *slist, gboolean deep_copy); GPtrArray * _nm_utils_strv_to_ptrarray (char **strv); char ** _nm_utils_ptrarray_to_strv (GPtrArray *ptrarray); +gboolean _nm_utils_check_file (const char *filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + struct stat *out_st, + GError **error); + #define NM_UTILS_UUID_TYPE_LEGACY 0 #define NM_UTILS_UUID_TYPE_VARIANT3 1 diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index fec3999bce..91bde5059e 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -30,6 +30,7 @@ #include #include #include +#include #include "nm-glib.h" #include "nm-utils.h" @@ -2409,6 +2410,76 @@ nm_utils_file_is_pkcs12 (const char *filename) /**********************************************************************************************/ +gboolean +_nm_utils_check_file (const char *filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + struct stat *out_st, + GError **error) +{ + struct stat st_backup; + + if (!out_st) + out_st = &st_backup; + + if (stat (filename, out_st) != 0) { + int errsv = errno; + + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("failed stat file %s: %s"), filename, strerror (errsv)); + return FALSE; + } + + /* ignore non-files. */ + if (!S_ISREG (out_st->st_mode)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("not a file (%s)"), filename); + return FALSE; + } + + /* with check_owner enabled, check that the file belongs to the + * owner or root. */ + if ( check_owner >= 0 + && (out_st->st_uid != 0 && (gint64) out_st->st_uid != check_owner)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("invalid file owner %d for %s"), out_st->st_uid, filename); + return FALSE; + } + + /* with check_owner enabled, check that the file cannot be modified + * by other users (except root). */ + if ( check_owner >= 0 + && NM_FLAGS_ANY (out_st->st_mode, S_IWGRP | S_IWOTH | S_ISUID)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("file permissions for %s"), filename); + return FALSE; + } + + if ( check_file + && !check_file (filename, out_st, user_data, error)) { + if (error && !*error) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("reject %s"), filename); + } + return FALSE; + } + + return TRUE; +} + +/**********************************************************************************************/ + /** * nm_utils_file_search_in_paths: * @progname: the helper program name, like "iptables" diff --git a/libnm-core/nm-utils.h b/libnm-core/nm-utils.h index c9a01d6e6e..64e57e875a 100644 --- a/libnm-core/nm-utils.h +++ b/libnm-core/nm-utils.h @@ -128,6 +128,10 @@ gboolean nm_utils_file_is_pkcs12 (const char *filename); typedef gboolean (*NMUtilsFileSearchInPathsPredicate) (const char *filename, gpointer user_data); +struct stat; + +typedef gboolean (*NMUtilsCheckFilePredicate) (const char *filename, const struct stat *stat, gpointer user_data, GError **error); + const char *nm_utils_file_search_in_paths (const char *progname, const char *try_first, const char *const *paths, From d6226bd987136e35d11f75948f6615c82fea71e0 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 22 May 2015 13:26:40 +0200 Subject: [PATCH 04/14] libnm: add NMVpnPluginInfo class NMVpnPluginInfo is little more then a wrapper around the GKeyFile that describes the VPN plugin settings, i.e. the name files under "/etc/NetworkManager/VPN/". Add this class to make the VPN API more explicit. Clients now can use NMVpnPluginInfo instead of concerning themselves with loading the keyfile and the meaning of its properties. Also add support for a new VPN plugins directory "/usr/lib/NetworkManager/VPN", which should replace "/etc/NetworkManager/VPN" in the future. But we have to consider both locations for backward compatibility. The content of the VPN directory is not user configuration, hence it should not be under "/etc". See related bug 738853. --- contrib/fedora/rpm/NetworkManager.spec | 2 + libnm-core/Makefile.am | 2 + libnm-core/Makefile.libnm-core | 6 +- libnm-core/nm-core-internal.h | 20 + libnm-core/nm-vpn-plugin-info.c | 895 +++++++++++++++++++++++++ libnm-core/nm-vpn-plugin-info.h | 103 +++ libnm/NetworkManager.h | 1 + libnm/libnm.ver | 16 + po/POTFILES.in | 1 + 9 files changed, 1044 insertions(+), 2 deletions(-) create mode 100644 libnm-core/nm-vpn-plugin-info.c create mode 100644 libnm-core/nm-vpn-plugin-info.h diff --git a/contrib/fedora/rpm/NetworkManager.spec b/contrib/fedora/rpm/NetworkManager.spec index c3769a2249..048cedae1f 100644 --- a/contrib/fedora/rpm/NetworkManager.spec +++ b/contrib/fedora/rpm/NetworkManager.spec @@ -440,6 +440,7 @@ make install DESTDIR=$RPM_BUILD_ROOT mkdir -p $RPM_BUILD_ROOT%{_sysconfdir}/%{name}/conf.d mkdir -p $RPM_BUILD_ROOT%{nmlibdir}/conf.d +mkdir -p $RPM_BUILD_ROOT%{nmlibdir}/VPN %{__cp} %{SOURCE2} $RPM_BUILD_ROOT%{nmlibdir}/conf.d/ %{__cp} %{SOURCE3} $RPM_BUILD_ROOT%{nmlibdir}/conf.d/ @@ -541,6 +542,7 @@ fi %dir %{_sysconfdir}/%{name}/conf.d %dir %{nmlibdir} %dir %{nmlibdir}/conf.d +%dir %{nmlibdir}/VPN %{_mandir}/man1/* %{_mandir}/man5/* %{_mandir}/man8/* diff --git a/libnm-core/Makefile.am b/libnm-core/Makefile.am index 73c5eaccf2..08f2afc86a 100644 --- a/libnm-core/Makefile.am +++ b/libnm-core/Makefile.am @@ -6,6 +6,8 @@ AM_CPPFLAGS = \ -I${top_srcdir}/include \ -DG_LOG_DOMAIN=\""libnm"\" \ -DLOCALEDIR=\"$(datadir)/locale\" \ + -DNMCONFDIR=\"$(nmconfdir)\" \ + -DNMLIBDIR=\"$(nmlibdir)\" \ -DNETWORKMANAGER_COMPILATION \ -DNM_VERSION_MAX_ALLOWED=NM_VERSION_NEXT_STABLE \ $(GLIB_CFLAGS) diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core index bbd504503a..a43ba895a3 100644 --- a/libnm-core/Makefile.libnm-core +++ b/libnm-core/Makefile.libnm-core @@ -42,7 +42,8 @@ libnm_core_headers = \ $(core)/nm-setting.h \ $(core)/nm-simple-connection.h \ $(core)/nm-utils.h \ - $(core)/nm-vpn-dbus-interface.h + $(core)/nm-vpn-dbus-interface.h \ + $(core)/nm-vpn-plugin-info.h libnm_core_private_headers = \ $(core)/crypto.h \ @@ -93,5 +94,6 @@ libnm_core_sources = \ $(core)/nm-setting-wireless.c \ $(core)/nm-setting.c \ $(core)/nm-simple-connection.c \ - $(core)/nm-utils.c + $(core)/nm-utils.c \ + $(core)/nm-vpn-plugin-info.c diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 1287b7a2f0..b1fb61b544 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -194,6 +194,26 @@ gboolean _nm_dbus_error_has_name (GError *error, /***********************************************************/ +gboolean _nm_vpn_plugin_info_check_file (const char *filename, + gboolean check_absolute, + gboolean do_validate_filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error); + +const char *_nm_vpn_plugin_info_get_default_dir_etc (void); +const char *_nm_vpn_plugin_info_get_default_dir_lib (void); +const char *_nm_vpn_plugin_info_get_default_dir_user (void); + +GSList *_nm_vpn_plugin_info_list_load_dir (const char *dirname, + gboolean do_validate_filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data); + +/***********************************************************/ + typedef struct { const char *name; gboolean numeric; diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c new file mode 100644 index 0000000000..2842ce2937 --- /dev/null +++ b/libnm-core/nm-vpn-plugin-info.c @@ -0,0 +1,895 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2015 Red Hat, Inc. + */ + +#include "config.h" + +#include "nm-vpn-plugin-info.h" + +#include +#include +#include +#include +#include + +#include "gsystem-local-alloc.h" +#include "nm-errors.h" +#include "nm-macros-internal.h" +#include "nm-core-internal.h" + +#define DEFAULT_DIR_ETC NMCONFDIR"/VPN" +#define DEFAULT_DIR_LIB NMLIBDIR"/VPN" + +enum { + PROP_0, + PROP_NAME, + PROP_FILENAME, + PROP_KEYFILE, + + LAST_PROP, +}; + +typedef struct { + char *filename; + char *name; + char *service; + GKeyFile *keyfile; + + /* It is convenient for nm_vpn_plugin_info_lookup_property() to return a const char *, + * contrary to what g_key_file_get_string() does. Hence we must cache the returned + * value somewhere... let's put it in an internal hash table. + * This contains a clone of all the strings in keyfile. */ + GHashTable *keys; +} NMVpnPluginInfoPrivate; + +static void nm_vpn_plugin_info_initable_iface_init (GInitableIface *iface); + +G_DEFINE_TYPE_WITH_CODE (NMVpnPluginInfo, nm_vpn_plugin_info, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_vpn_plugin_info_initable_iface_init); + ) + +#define NM_VPN_PLUGIN_INFO_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_PLUGIN_INFO, NMVpnPluginInfoPrivate)) + +/*********************************************************************/ + +/** + * nm_vpn_plugin_info_validate_filename: + * @filename: the filename to check + * + * Regular name files have a certain pattern. That basically means + * they have the file extension "name". Check if @filename + * is valid according to that pattern. + * + * Since: 1.2 + */ +gboolean +nm_vpn_plugin_info_validate_filename (const char *filename) +{ + if (!filename || !g_str_has_suffix (filename, ".name")) + return FALSE; + + /* originally, we didn't do further checks... but here we go. */ + if (filename[0] == '.') { + /* this also rejects name ".name" alone. */ + return FALSE; + } + return TRUE; +} + +static gboolean +nm_vpn_plugin_info_check_file_full (const char *filename, + gboolean check_absolute, + gboolean do_validate_filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + struct stat *out_st, + GError **error) +{ + if (!filename || !*filename) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("missing filename")); + return FALSE; + } + + if (check_absolute && !g_path_is_absolute (filename)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("filename must be an absolute path (%s)"), filename); + return FALSE; + } + + if ( do_validate_filename + && !nm_vpn_plugin_info_validate_filename (filename)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("filename has invalid format (%s)"), filename); + return FALSE; + } + + return _nm_utils_check_file (filename, + check_owner, + check_file, + user_data, + out_st, + error); +} + +/** + * _nm_vpn_plugin_info_check_file: + * @filename: + * @check_absolute: if %TRUE, only allow absolute path names. + * @do_validate_filename: if %TRUE, only accept the filename if + * nm_vpn_plugin_info_validate_filename() succeeds. + * @check_owner: if non-negative, only accept the file if the + * owner UID is equal to @check_owner or if the owner is 0. + * In this case, also check that the file is not writable by + * other users. + * @check_file: pass a callback to do your own validation. + * @user_data: user data for @check_file. + * @error: (allow-none): (out): the error reason if the check fails. + * + * Check whether the file exists and is a valid name file (in keyfile format). + * Additionally, also check for file permissions. + * + * Returns: %TRUE if a file @filename exists and has valid permissions. + * + * Since: 1.2 + */ +gboolean +_nm_vpn_plugin_info_check_file (const char *filename, + gboolean check_absolute, + gboolean do_validate_filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error) +{ + return nm_vpn_plugin_info_check_file_full (filename, check_absolute, do_validate_filename, check_owner, check_file, user_data, NULL, error); +} + +typedef struct { + NMVpnPluginInfo *plugin_info; + struct stat stat; +} LoadDirInfo; + +static int +_sort_files (LoadDirInfo *a, LoadDirInfo *b) +{ + time_t ta, tb; + + ta = MAX (a->stat.st_mtime, a->stat.st_ctime); + tb = MAX (b->stat.st_mtime, b->stat.st_ctime); + if (ta < tb) + return 1; + if (ta > tb) + return -1; + return g_strcmp0 (nm_vpn_plugin_info_get_filename (a->plugin_info), + nm_vpn_plugin_info_get_filename (b->plugin_info)); +} + +/** + * _nm_vpn_plugin_info_get_default_dir_etc: + * + * Returns: (transfer-none): compile time constant of the default + * VPN plugin directory. + */ +const char * +_nm_vpn_plugin_info_get_default_dir_etc () +{ + return DEFAULT_DIR_ETC; +} + +/** + * _nm_vpn_plugin_info_get_default_dir_lib: + * + * Returns: (transfer-none): compile time constant of the default + * VPN plugin directory. + */ +const char * +_nm_vpn_plugin_info_get_default_dir_lib () +{ + return DEFAULT_DIR_LIB; +} + +/** + * _nm_vpn_plugin_info_get_default_dir_user: + * + * Returns: The user can specify a different directory for VPN plugins + * by setting NM_VPN_PLUGIN_DIR environment variable. Return + * that directory. + */ +const char * +_nm_vpn_plugin_info_get_default_dir_user () +{ + return g_getenv ("NM_VPN_PLUGIN_DIR"); +} + +/** + * _nm_vpn_plugin_info_list_load_dir: + * @dirname: the name of the directory to load. + * @do_validate_filename: only consider filenames that have a certain + * pattern (i.e. end with ".name"). + * @check_owner: if set to a non-negative number, check that the file + * owner is either the same uid or 0. In that case, also check + * that the file is not writable by group or other. + * @check_file: (allow-none): callback to check whether the file is valid. + * @user_data: data for @check_file + * + * Iterate over the content of @dirname and load name files. + * + * Returns: (transfer-full): list of loaded plugin infos. + */ +GSList * +_nm_vpn_plugin_info_list_load_dir (const char *dirname, + gboolean do_validate_filename, + gint64 check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data) +{ + GDir *dir; + const char *fn; + GArray *array; + GSList *res = NULL; + guint i; + + g_return_val_if_fail (dirname && dirname[0], NULL); + + dir = g_dir_open (dirname, 0, NULL); + if (!dir) + return NULL; + + array = g_array_new (FALSE, FALSE, sizeof (LoadDirInfo)); + + while ((fn = g_dir_read_name (dir))) { + gs_free char *filename = NULL; + LoadDirInfo info = { 0 }; + + filename = g_build_filename (dirname, fn, NULL); + if (nm_vpn_plugin_info_check_file_full (filename, + FALSE, + do_validate_filename, + check_owner, + check_file, + user_data, + &info.stat, + NULL)) { + info.plugin_info = nm_vpn_plugin_info_new_from_file (filename, NULL); + if (info.plugin_info) { + g_array_append_val (array, info); + continue; + } + } + } + g_dir_close (dir); + + /* sort the files so that we have a stable behavior. The directory might contain + * duplicate VPNs, so while nm_vpn_plugin_info_list_load() would load them all, the + * caller probably wants to reject duplicates. Having a stable order means we always + * reject the same files in face of duplicates. */ + g_array_sort (array, (GCompareFunc) _sort_files); + + for (i = 0; i < array->len; i++) + res = g_slist_prepend (res, g_array_index (array, LoadDirInfo, i).plugin_info); + + g_array_unref (array); + + return g_slist_reverse (res); +} + +/** + * nm_vpn_plugin_info_list_load: + * + * Returns: (tranfer-full): list of plugins loaded from the default + * directories rejecting duplicates. + * + * Since: 1.2 + */ +GSList * +nm_vpn_plugin_info_list_load () +{ + int i; + gint64 uid; + GSList *list = NULL; + GSList *infos, *info; + const char *dir[] = { + /* We load plugins from NM_VPN_PLUGIN_DIR *and* DEFAULT_DIR*, with + * preference to the former. + * + * load user directory with highest priority. */ + _nm_vpn_plugin_info_get_default_dir_user (), + + /* lib directory has higher priority then etc. The reason is that + * etc is deprecated and used by old plugins. We expect newer plugins + * to install their file in lib, where they have higher priority. + * + * Optimally, there are no duplicates anyway, so it doesn't really matter. */ + _nm_vpn_plugin_info_get_default_dir_lib (), + _nm_vpn_plugin_info_get_default_dir_etc (), + }; + + uid = getuid (); + + for (i = 0; i < G_N_ELEMENTS (dir); i++) { + if ( !dir[i] + || _nm_utils_strv_find_first ((char **) dir, i, dir[i]) >= 0) + continue; + + infos = _nm_vpn_plugin_info_list_load_dir (dir[i], TRUE, uid, NULL, NULL); + + for (info = infos; info; info = info->next) + nm_vpn_plugin_info_list_add (&list, info->data, NULL); + + g_slist_free_full (infos, g_object_unref); + } + return list; +} + +/*********************************************************************/ + +static gboolean +_check_no_conflict (NMVpnPluginInfo *i1, NMVpnPluginInfo *i2, GError **error) +{ + NMVpnPluginInfoPrivate *priv1, *priv2; + uint i; + struct { + const char *group; + const char *key; + } check_list[] = { + { NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, "service" }, + { NM_VPN_PLUGIN_INFO_KF_GROUP_LIBNM, "plugin" }, + { NM_VPN_PLUGIN_INFO_KF_GROUP_GNOME, "properties" }, + }; + + priv1 = NM_VPN_PLUGIN_INFO_GET_PRIVATE (i1); + priv2 = NM_VPN_PLUGIN_INFO_GET_PRIVATE (i2); + + for (i = 0; i < G_N_ELEMENTS (check_list); i++) { + gs_free NMUtilsStrStrDictKey *k = NULL; + const char *s1, *s2; + + k = _nm_utils_strstrdictkey_create (check_list[i].group, check_list[i].key); + s1 = g_hash_table_lookup (priv1->keys, k); + if (!s1) + continue; + s2 = g_hash_table_lookup (priv2->keys, k); + if (!s2) + continue; + + if (strcmp (s1, s2) == 0) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("there exists a conflicting plugin (%s) that has the same %s.%s value"), + priv2->name, + check_list[i].group, check_list[i].key); + return FALSE; + } + } + return TRUE; +} + +/** + * nm_vpn_plugin_info_list_add: + * @list: list of plugins + * @plugin_info: instance to add + * @error: failure reason + * + * Returns: %TRUE if the plugin was added to @list. This will fail + * to add duplicate plugins. + * + * Since: 1.2 + */ +gboolean +nm_vpn_plugin_info_list_add (GSList **list, NMVpnPluginInfo *plugin_info, GError **error) +{ + GSList *iter; + const char *name; + + g_return_val_if_fail (list, FALSE); + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info), FALSE); + + name = nm_vpn_plugin_info_get_name (plugin_info); + for (iter = *list; iter; iter = iter->next) { + if (iter->data == plugin_info) + return TRUE; + + if (strcmp (nm_vpn_plugin_info_get_name (iter->data), name) == 0) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("there exists a conflicting plugin with the same name (%s)"), + name); + return FALSE; + } + + /* the plugin must have unique values for certain properties. E.g. two different + * plugins cannot share the same D-Bus service name. */ + if (!_check_no_conflict (plugin_info, iter->data, error)) + return FALSE; + } + + *list = g_slist_append (*list, g_object_ref (plugin_info)); + return TRUE; +} + +/** + * nm_vpn_plugin_info_list_remove: + * @list: list of plugins + * @plugin_info: instance + * + * Remove @plugin_info from @list. + * + * Returns: %TRUE if @plugin_info was in @list and successfully removed. + * + * Since: 1.2 + */ +gboolean +nm_vpn_plugin_info_list_remove (GSList **list, NMVpnPluginInfo *plugin_info) +{ + if (!plugin_info) + return FALSE; + + g_return_val_if_fail (list, FALSE); + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info), FALSE); + + if (!g_slist_find (*list, plugin_info)) + return FALSE; + + *list = g_slist_remove (*list, plugin_info); + g_object_unref (plugin_info); + return TRUE; +} + +/** + * nm_vpn_plugin_info_list_find_by_name: + * @list: list of plugins + * @name: name to search + * + * Returns: the first plugin with a matching @name (or %NULL). + * + * Since: 1.2 + */ +NMVpnPluginInfo * +nm_vpn_plugin_info_list_find_by_name (GSList *list, const char *name) +{ + GSList *iter; + + if (!name) + g_return_val_if_reached (NULL); + + for (iter = list; iter; iter = iter->next) { + if (strcmp (nm_vpn_plugin_info_get_name (iter->data), name) == 0) + return iter->data; + } + return NULL; +} + +/** + * nm_vpn_plugin_info_list_find_by_filename: + * @list: list of plugins + * @filename: filename to search + * + * Returns: the first plugin with a matching @filename (or %NULL). + * + * Since: 1.2 + */ +NMVpnPluginInfo * +nm_vpn_plugin_info_list_find_by_filename (GSList *list, const char *filename) +{ + GSList *iter; + + if (!filename) + g_return_val_if_reached (NULL); + + for (iter = list; iter; iter = iter->next) { + if (g_strcmp0 (nm_vpn_plugin_info_get_filename (iter->data), filename) == 0) + return iter->data; + } + return NULL; +} + +/** + * nm_vpn_plugin_info_list_find_by_service: + * @list: list of plugins + * @service: service to search + * + * Returns: the first plugin with a matching @service (or %NULL). + * + * Since: 1.2 + */ +NMVpnPluginInfo * +nm_vpn_plugin_info_list_find_by_service (GSList *list, const char *service) +{ + GSList *iter; + + if (!service) + g_return_val_if_reached (NULL); + + for (iter = list; iter; iter = iter->next) { + if (strcmp (nm_vpn_plugin_info_get_service (iter->data), service) == 0) + return iter->data; + } + return NULL; +} + +/*********************************************************************/ + +/** + * nm_vpn_plugin_info_get_filename: + * @self: plugin info instance + * + * Returns: (transfer-none): the filename. Can be %NULL. + * + * Since: 1.2 + */ +const char * +nm_vpn_plugin_info_get_filename (NMVpnPluginInfo *self) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + return NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->filename; +} + +/** + * nm_vpn_plugin_info_get_name: + * @self: plugin info instance + * + * Returns: (transfer-none): the name. Cannot be %NULL. + * + * Since: 1.2 + */ +const char * +nm_vpn_plugin_info_get_name (NMVpnPluginInfo *self) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + return NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->name; +} + +/** + * nm_vpn_plugin_info_get_service: + * @self: plugin info instance + * + * Returns: (transfer-none): the service. Cannot be %NULL. + * + * Since: 1.2 + */ +const char * +nm_vpn_plugin_info_get_service (NMVpnPluginInfo *self) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + return NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->service; +} + +/** + * nm_vpn_plugin_info_get_plugin: + * @self: plugin info instance + * + * Returns: (transfer-none): the plugin. Can be %NULL. + * + * Since: 1.2 + */ +const char * +nm_vpn_plugin_info_get_plugin (NMVpnPluginInfo *self) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + return g_hash_table_lookup (NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->keys, + _nm_utils_strstrdictkey_static (NM_VPN_PLUGIN_INFO_KF_GROUP_LIBNM, "plugin")); +} + +/** + * nm_vpn_plugin_info_get_program: + * @self: plugin info instance + * + * Returns: (transfer-none): the program. Can be %NULL. + * + * Since: 1.2 + */ +const char * +nm_vpn_plugin_info_get_program (NMVpnPluginInfo *self) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + return g_hash_table_lookup (NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->keys, + _nm_utils_strstrdictkey_static (NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, "program")); +} + +/** + * nm_vpn_plugin_info_lookup_property: + * @self: plugin info instance + * @group: group name + * @key: name of the property + * + * Returns: (transfer-none): #NMVpnPluginInfo is internally a #GKeyFile. Returns the matching + * property. + * + * Since: 1.2 + */ +const char * +nm_vpn_plugin_info_lookup_property (NMVpnPluginInfo *self, const char *group, const char *key) +{ + NMVpnPluginInfoPrivate *priv; + gs_free NMUtilsStrStrDictKey *k = NULL; + + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + g_return_val_if_fail (group, NULL); + g_return_val_if_fail (key, NULL); + + priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (self); + + k = _nm_utils_strstrdictkey_create (group, key); + return g_hash_table_lookup (priv->keys, k); +} + +/*********************************************************************/ + +/** + * nm_vpn_plugin_info_new_from_file: + * @filename: filename to read. + * @error: on failure, the error reason. + * + * Read the plugin info from file @filename. Does not do + * any further verification on the file. You might want to check + * file permissions and ownership of the file. + * + * Returns: %NULL if there is any error or a newly created + * #NMVpnPluginInfo instance. + * + * Since: 1.2 + */ +NMVpnPluginInfo * +nm_vpn_plugin_info_new_from_file (const char *filename, + GError **error) +{ + g_return_val_if_fail (filename, NULL); + + return NM_VPN_PLUGIN_INFO (g_initable_new (NM_TYPE_VPN_PLUGIN_INFO, + NULL, + error, + NM_VPN_PLUGIN_INFO_FILENAME, filename, + NULL)); +} + +/** + * nm_vpn_plugin_info_new_with_data: + * @filename: optional filename. + * @keyfile: inject data for the plugin info instance. + * @error: construction may fail if the keyfile lacks mandatory fields. + * In this case, return the error reason. + * + * This constructor does not read any data from file but + * takes instead a @keyfile argument. + * + * Returns: new plugin info instance. + * + * Since: 1.2 + */ +NMVpnPluginInfo * +nm_vpn_plugin_info_new_with_data (const char *filename, + GKeyFile *keyfile, + GError **error) +{ + g_return_val_if_fail (keyfile, NULL); + + return NM_VPN_PLUGIN_INFO (g_initable_new (NM_TYPE_VPN_PLUGIN_INFO, + NULL, + error, + NM_VPN_PLUGIN_INFO_FILENAME, filename, + NM_VPN_PLUGIN_INFO_KEYFILE, keyfile, + NULL)); +} + +/*********************************************************************/ + +static void +nm_vpn_plugin_info_init (NMVpnPluginInfo *plugin) +{ +} + +static gboolean +init_sync (GInitable *initable, GCancellable *cancellable, GError **error) +{ + NMVpnPluginInfo *self = NM_VPN_PLUGIN_INFO (initable); + NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (self); + gs_strfreev char **groups = NULL; + guint i, j; + + if (!priv->keyfile) { + if (!priv->filename) { + g_set_error_literal (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + _("missing filename to load VPN plugin info")); + return FALSE; + } + priv->keyfile = g_key_file_new (); + if (!g_key_file_load_from_file (priv->keyfile, priv->filename, G_KEY_FILE_NONE, error)) + return FALSE; + } + + /* we reqire at least a "name" */ + priv->name = g_key_file_get_string (priv->keyfile, NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, "name", NULL); + if (!priv->name || !priv->name[0]) { + g_set_error_literal (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + _("missing name for VPN plugin info")); + return FALSE; + } + + /* we also require "service", because that how we associate NMSettingVpn:service-type with the + * NMVpnPluginInfo. */ + priv->service = g_key_file_get_string (priv->keyfile, NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, "service", NULL); + if (!priv->service || !*priv->service) { + g_set_error_literal (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + _("missing service for VPN plugin info")); + return FALSE; + } + + priv->keys = g_hash_table_new_full (_nm_utils_strstrdictkey_hash, + _nm_utils_strstrdictkey_equal, + g_free, g_free); + groups = g_key_file_get_groups (priv->keyfile, NULL); + for (i = 0; groups && groups[i]; i++) { + gs_strfreev char **keys = NULL; + + keys = g_key_file_get_keys (priv->keyfile, groups[i], NULL, NULL); + for (j = 0; keys && keys[j]; j++) { + char *s; + + /* Lookup the value via get_string(). We want that behavior. + * You could still lookup the original values via g_key_file_get_value() + * based on priv->keyfile. */ + s = g_key_file_get_string (priv->keyfile, groups[i], keys[j], NULL); + if (s) + g_hash_table_insert (priv->keys, _nm_utils_strstrdictkey_create (groups[i], keys[j]), s); + } + } + + return TRUE; +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_FILENAME: + priv->filename = g_value_dup_string (value); + break; + case PROP_KEYFILE: + priv->keyfile = g_value_dup_boxed (value); + 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) +{ + NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_NAME: + g_value_set_string (value, priv->name); + break; + case PROP_FILENAME: + g_value_set_string (value, priv->filename); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +finalize (GObject *object) +{ + NMVpnPluginInfo *self = NM_VPN_PLUGIN_INFO (object); + NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (self); + + g_free (priv->name); + g_free (priv->service); + g_free (priv->filename); + g_key_file_unref (priv->keyfile); + g_hash_table_unref (priv->keys); + + G_OBJECT_CLASS (nm_vpn_plugin_info_parent_class)->finalize (object); +} + +static void +nm_vpn_plugin_info_class_init (NMVpnPluginInfoClass *plugin_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (plugin_class); + + g_type_class_add_private (object_class, sizeof (NMVpnPluginInfoPrivate)); + + /* virtual methods */ + object_class->set_property = set_property; + object_class->get_property = get_property; + object_class->finalize = finalize; + + /* properties */ + + /** + * NMVpnPluginInfo:name: + * + * The name of the VPN plugin. + * + * Since: 1.2 + */ + g_object_class_install_property + (object_class, PROP_NAME, + g_param_spec_string (NM_VPN_PLUGIN_INFO_NAME, "", "", + NULL, + G_PARAM_READABLE | + G_PARAM_STATIC_STRINGS)); + + /** + * NMVpnPluginInfo:filename: + * + * The filename from which the info was loaded. + * Can be %NULL if the instance was not loaded from + * a file (i.e. the keyfile instance was passed to the + * constructor). + * + * Since: 1.2 + */ + g_object_class_install_property + (object_class, PROP_FILENAME, + g_param_spec_string (NM_VPN_PLUGIN_INFO_FILENAME, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * NMVpnPluginInfo:keyfile: + * + * Initalize the instance with a different keyfile instance. + * When passing a keyfile instance, the constructor will not + * try to read from filename. + * + * Since: 1.2 + */ + g_object_class_install_property + (object_class, PROP_KEYFILE, + g_param_spec_boxed (NM_VPN_PLUGIN_INFO_KEYFILE, "", "", + G_TYPE_KEY_FILE, + G_PARAM_WRITABLE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); +} + +static void +nm_vpn_plugin_info_initable_iface_init (GInitableIface *iface) +{ + iface->init = init_sync; +} + diff --git a/libnm-core/nm-vpn-plugin-info.h b/libnm-core/nm-vpn-plugin-info.h new file mode 100644 index 0000000000..8e937b57b7 --- /dev/null +++ b/libnm-core/nm-vpn-plugin-info.h @@ -0,0 +1,103 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2015 Red Hat, Inc. + */ + +#ifndef __NM_VPN_PLUGIN_INFO_H__ +#define __NM_VPN_PLUGIN_INFO_H__ + +#include +#include + +#include "nm-utils.h" + +G_BEGIN_DECLS + +#define NM_TYPE_VPN_PLUGIN_INFO (nm_vpn_plugin_info_get_type ()) +#define NM_VPN_PLUGIN_INFO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_PLUGIN_INFO, NMVpnPluginInfo)) +#define NM_VPN_PLUGIN_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_PLUGIN_INFO, NMVpnPluginInfoClass)) +#define NM_IS_VPN_PLUGIN_INFO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_PLUGIN_INFO)) +#define NM_IS_VPN_PLUGIN_INFO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_PLUGIN_INFO)) +#define NM_VPN_PLUGIN_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_PLUGIN_INFO, NMVpnPluginInfoClass)) + +#define NM_VPN_PLUGIN_INFO_NAME "name" +#define NM_VPN_PLUGIN_INFO_FILENAME "filename" +#define NM_VPN_PLUGIN_INFO_KEYFILE "keyfile" + +#define NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION "VPN Connection" +#define NM_VPN_PLUGIN_INFO_KF_GROUP_LIBNM "libnm" +#define NM_VPN_PLUGIN_INFO_KF_GROUP_GNOME "GNOME" + +typedef struct { + NM_AVAILABLE_IN_1_2 + GObject parent; +} NMVpnPluginInfo NM_AVAILABLE_IN_1_2; + +typedef struct { + NM_AVAILABLE_IN_1_2 + GObjectClass parent; + + /*< private >*/ + NM_AVAILABLE_IN_1_2 + gpointer padding[8]; +} NMVpnPluginInfoClass NM_AVAILABLE_IN_1_2; + +NM_AVAILABLE_IN_1_2 +GType nm_vpn_plugin_info_get_type (void); + +NM_AVAILABLE_IN_1_2 +NMVpnPluginInfo *nm_vpn_plugin_info_new_from_file (const char *filename, + GError **error); + +NM_AVAILABLE_IN_1_2 +NMVpnPluginInfo *nm_vpn_plugin_info_new_with_data (const char *filename, + GKeyFile *keyfile, + GError **error); + +NM_AVAILABLE_IN_1_2 +const char *nm_vpn_plugin_info_get_name (NMVpnPluginInfo *self); +NM_AVAILABLE_IN_1_2 +const char *nm_vpn_plugin_info_get_filename (NMVpnPluginInfo *self); +NM_AVAILABLE_IN_1_2 +const char *nm_vpn_plugin_info_get_service (NMVpnPluginInfo *self); +NM_AVAILABLE_IN_1_2 +const char *nm_vpn_plugin_info_get_plugin (NMVpnPluginInfo *self); +NM_AVAILABLE_IN_1_2 +const char *nm_vpn_plugin_info_get_program (NMVpnPluginInfo *self); +NM_AVAILABLE_IN_1_2 +const char *nm_vpn_plugin_info_lookup_property (NMVpnPluginInfo *self, const char *group, const char *key); + +NM_AVAILABLE_IN_1_2 +gboolean nm_vpn_plugin_info_validate_filename (const char *filename); + +NM_AVAILABLE_IN_1_2 +GSList *nm_vpn_plugin_info_list_load (void); +NM_AVAILABLE_IN_1_2 +gboolean nm_vpn_plugin_info_list_add (GSList **list, NMVpnPluginInfo *plugin_info, GError **error); +NM_AVAILABLE_IN_1_2 +gboolean nm_vpn_plugin_info_list_remove (GSList **list, NMVpnPluginInfo *plugin_info); +NM_AVAILABLE_IN_1_2 +NMVpnPluginInfo *nm_vpn_plugin_info_list_find_by_name (GSList *list, const char *name); +NM_AVAILABLE_IN_1_2 +NMVpnPluginInfo *nm_vpn_plugin_info_list_find_by_filename (GSList *list, const char *filename); +NM_AVAILABLE_IN_1_2 +NMVpnPluginInfo *nm_vpn_plugin_info_list_find_by_service (GSList *list, const char *service); + +G_END_DECLS + +#endif /* __NM_VPN_PLUGIN_INFO_H__ */ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 251a042216..9f10cfe9f4 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -82,6 +82,7 @@ #include #include #include +#include #include #undef __NETWORKMANAGER_H_INSIDE__ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index c3a23cb574..885e063203 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -882,4 +882,20 @@ global: nm_utils_bond_mode_string_to_int; nm_utils_enum_from_str; nm_utils_enum_to_str; + nm_vpn_plugin_info_get_filename; + nm_vpn_plugin_info_get_name; + nm_vpn_plugin_info_get_plugin; + nm_vpn_plugin_info_get_program; + nm_vpn_plugin_info_get_service; + nm_vpn_plugin_info_get_type; + nm_vpn_plugin_info_lookup_property; + nm_vpn_plugin_info_new_from_file; + nm_vpn_plugin_info_new_with_data; + nm_vpn_plugin_info_validate_filename; + nm_vpn_plugin_info_list_add; + nm_vpn_plugin_info_list_find_by_filename; + nm_vpn_plugin_info_list_find_by_name; + nm_vpn_plugin_info_list_find_by_service; + nm_vpn_plugin_info_list_load; + nm_vpn_plugin_info_list_remove; } libnm_1_0_0; diff --git a/po/POTFILES.in b/po/POTFILES.in index 6ca4a33ff6..4b117109e7 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -77,6 +77,7 @@ libnm-core/nm-setting-wireless-security.c libnm-core/nm-setting-wireless.c libnm-core/nm-setting.c libnm-core/nm-utils.c +libnm-core/nm-vpn-plugin-info.c libnm-glib/nm-device.c libnm-glib/nm-remote-connection.c libnm-util/crypto.c From bce040daa2399688b437ac5609339f3d3e1b17b8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 25 May 2015 13:55:37 +0200 Subject: [PATCH 05/14] libnm: move NMVpnEditorPlugin to libnm-core/ Split the content of libnm/nm-vpn-editor-plugin.h and move NMVpnEditorPlugin to libnm-core/nm-vpn-editor-plugin.h. VPN plugins allow us to extend functionality about VPNs. This can be also useful for NetworkManager core, hence move that part to libnm-core. The name NMVpnEditorPlugin is slightly misleading but not completely wrong. The "editor" part stands no longer for bringing nm-applet functionality (alone), but enable general VPN functionality in the client. Especially because we already have NMVpnPluginOld with a different meaning (i.e. a base class of the plugin server implementation). --- libnm-core/Makefile.libnm-core | 2 + {libnm => libnm-core}/nm-vpn-editor-plugin.c | 48 +---------- {libnm => libnm-core}/nm-vpn-editor-plugin.h | 54 +----------- libnm/Makefile.am | 4 +- libnm/NetworkManager.h | 1 + libnm/nm-vpn-editor.c | 69 ++++++++++++++++ libnm/nm-vpn-editor.h | 86 ++++++++++++++++++++ 7 files changed, 166 insertions(+), 98 deletions(-) rename {libnm => libnm-core}/nm-vpn-editor-plugin.c (79%) rename {libnm => libnm-core}/nm-vpn-editor-plugin.h (73%) create mode 100644 libnm/nm-vpn-editor.c create mode 100644 libnm/nm-vpn-editor.h diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core index a43ba895a3..a3763f4e56 100644 --- a/libnm-core/Makefile.libnm-core +++ b/libnm-core/Makefile.libnm-core @@ -43,6 +43,7 @@ libnm_core_headers = \ $(core)/nm-simple-connection.h \ $(core)/nm-utils.h \ $(core)/nm-vpn-dbus-interface.h \ + $(core)/nm-vpn-editor-plugin.h \ $(core)/nm-vpn-plugin-info.h libnm_core_private_headers = \ @@ -95,5 +96,6 @@ libnm_core_sources = \ $(core)/nm-setting.c \ $(core)/nm-simple-connection.c \ $(core)/nm-utils.c \ + $(core)/nm-vpn-editor-plugin.c \ $(core)/nm-vpn-plugin-info.c diff --git a/libnm/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c similarity index 79% rename from libnm/nm-vpn-editor-plugin.c rename to libnm-core/nm-vpn-editor-plugin.c index 904a6be483..b36b736859 100644 --- a/libnm/nm-vpn-editor-plugin.c +++ b/libnm-core/nm-vpn-editor-plugin.c @@ -15,8 +15,9 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright 2008 - 2010 Red Hat, Inc. * Copyright 2008 Novell, Inc. + * Copyright 2008 - 2010 Red Hat, Inc. + * Copyright 2015 Red Hat, Inc. */ #include "config.h" @@ -134,48 +135,3 @@ nm_vpn_editor_plugin_get_suggested_filename (NMVpnEditorPlugin *plugin, return NULL; } - -static void nm_vpn_editor_default_init (NMVpnEditorInterface *iface); - -G_DEFINE_INTERFACE (NMVpnEditor, nm_vpn_editor, G_TYPE_OBJECT) - -static void -nm_vpn_editor_default_init (NMVpnEditorInterface *iface) -{ - GType iface_type = G_TYPE_FROM_INTERFACE (iface); - - /* Signals */ - g_signal_new ("changed", - iface_type, - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnEditorInterface, changed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); -} - -/** - * nm_vpn_editor_get_widget: - * - * Returns: (transfer none): - */ -GObject * -nm_vpn_editor_get_widget (NMVpnEditor *editor) -{ - g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), NULL); - - return NM_VPN_EDITOR_GET_INTERFACE (editor)->get_widget (editor); -} - -gboolean -nm_vpn_editor_update_connection (NMVpnEditor *editor, - NMConnection *connection, - GError **error) -{ - g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), FALSE); - - if (error) - g_return_val_if_fail (*error == NULL, FALSE); - - return NM_VPN_EDITOR_GET_INTERFACE (editor)->update_connection (editor, connection, error); -} diff --git a/libnm/nm-vpn-editor-plugin.h b/libnm-core/nm-vpn-editor-plugin.h similarity index 73% rename from libnm/nm-vpn-editor-plugin.h rename to libnm-core/nm-vpn-editor-plugin.h index 5910aa3653..a0b1f7aca2 100644 --- a/libnm/nm-vpn-editor-plugin.h +++ b/libnm-core/nm-vpn-editor-plugin.h @@ -15,8 +15,8 @@ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301 USA. * - * Copyright 2008 - 2014 Red Hat, Inc. * Copyright 2008 Novell, Inc. + * Copyright 2008 - 2015 Red Hat, Inc. */ #ifndef __NM_VPN_EDITOR_PLUGIN_H__ @@ -28,7 +28,8 @@ #include #include -#include + +#include "nm-connection.h" G_BEGIN_DECLS @@ -137,53 +138,6 @@ gboolean nm_vpn_editor_plugin_export (NMVpnEditorPlugin *pl char *nm_vpn_editor_plugin_get_suggested_filename (NMVpnEditorPlugin *plugin, NMConnection *connection); -/**************************************************/ -/* Editor interface */ -/**************************************************/ - -#define NM_TYPE_VPN_EDITOR (nm_vpn_editor_get_type ()) -#define NM_VPN_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_EDITOR, NMVpnEditor)) -#define NM_IS_VPN_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_EDITOR)) -#define NM_VPN_EDITOR_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_VPN_EDITOR, NMVpnEditorInterface)) - -/** - * NMVpnEditorInterface: - * @g_iface: the parent interface - * @get_widget: return the #GtkWidget for the VPN editor's UI - * @placeholder: not currently used - * @update_connection: called to save the user-entered options to the connection - * object. Should return %FALSE and set @error if the current options are - * invalid. @error should contain enough information for the plugin to - * determine which UI widget is invalid at a later point in time. For - * example, creating unique error codes for what error occurred and populating - * the message field of @error with the name of the invalid property. - * @changed: emitted when the value of a UI widget changes. May trigger a - * validity check via @update_connection to write values to the connection. - * - * Interface for editing a specific #NMConnection - */ -typedef struct { - GTypeInterface g_iface; - - GObject * (*get_widget) (NMVpnEditor *editor); - - void (*placeholder) (void); - - gboolean (*update_connection) (NMVpnEditor *editor, - NMConnection *connection, - GError **error); - - void (*changed) (NMVpnEditor *editor); -} NMVpnEditorInterface; - -GType nm_vpn_editor_get_type (void); - -GObject * nm_vpn_editor_get_widget (NMVpnEditor *editor); - -gboolean nm_vpn_editor_update_connection (NMVpnEditor *editor, - NMConnection *connection, - GError **error); - G_END_DECLS -#endif /* NM_VPN_EDITOR_PLUGIN_H */ +#endif /* __NM_VPN_EDITOR_PLUGIN_H__ */ diff --git a/libnm/Makefile.am b/libnm/Makefile.am index 2c9d94ef54..f6357dad1e 100644 --- a/libnm/Makefile.am +++ b/libnm/Makefile.am @@ -50,7 +50,7 @@ libnminclude_hfiles = \ nm-remote-connection.h \ nm-types.h \ nm-vpn-connection.h \ - nm-vpn-editor-plugin.h \ + nm-vpn-editor.h \ nm-wimax-nsp.h libnminclude_nointrospect_hfiles = \ @@ -108,7 +108,7 @@ libnm_la_csources = \ nm-secret-agent-old.c \ nm-vpn-connection.c \ nm-vpn-plugin-old.c \ - nm-vpn-editor-plugin.c \ + nm-vpn-editor.c \ nm-wimax-nsp.c libnm_la_SOURCES = \ diff --git a/libnm/NetworkManager.h b/libnm/NetworkManager.h index 9f10cfe9f4..085437e6f5 100644 --- a/libnm/NetworkManager.h +++ b/libnm/NetworkManager.h @@ -81,6 +81,7 @@ #include #include #include +#include #include #include #include diff --git a/libnm/nm-vpn-editor.c b/libnm/nm-vpn-editor.c new file mode 100644 index 0000000000..ba6bd5e03c --- /dev/null +++ b/libnm/nm-vpn-editor.c @@ -0,0 +1,69 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2008 - 2010 Red Hat, Inc. + * Copyright 2008 Novell, Inc. + */ + +#include "config.h" + +#include "nm-vpn-editor.h" + +static void nm_vpn_editor_default_init (NMVpnEditorInterface *iface); + +G_DEFINE_INTERFACE (NMVpnEditor, nm_vpn_editor, G_TYPE_OBJECT) + +static void +nm_vpn_editor_default_init (NMVpnEditorInterface *iface) +{ + GType iface_type = G_TYPE_FROM_INTERFACE (iface); + + /* Signals */ + g_signal_new ("changed", + iface_type, + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnEditorInterface, changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +/** + * nm_vpn_editor_get_widget: + * + * Returns: (transfer none): + */ +GObject * +nm_vpn_editor_get_widget (NMVpnEditor *editor) +{ + g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), NULL); + + return NM_VPN_EDITOR_GET_INTERFACE (editor)->get_widget (editor); +} + +gboolean +nm_vpn_editor_update_connection (NMVpnEditor *editor, + NMConnection *connection, + GError **error) +{ + g_return_val_if_fail (NM_IS_VPN_EDITOR (editor), FALSE); + + if (error) + g_return_val_if_fail (*error == NULL, FALSE); + + return NM_VPN_EDITOR_GET_INTERFACE (editor)->update_connection (editor, connection, error); +} diff --git a/libnm/nm-vpn-editor.h b/libnm/nm-vpn-editor.h new file mode 100644 index 0000000000..a11e9fd16d --- /dev/null +++ b/libnm/nm-vpn-editor.h @@ -0,0 +1,86 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2008 Novell, Inc. + * Copyright 2008 - 2015 Red Hat, Inc. + */ + +#ifndef __NM_VPN_EDITOR_H__ +#define __NM_VPN_EDITOR_H__ + +#if !defined (__NETWORKMANAGER_H_INSIDE__) && !defined (NETWORKMANAGER_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include +#include + +#include "nm-vpn-editor-plugin.h" + +G_BEGIN_DECLS + +/**************************************************/ +/* Editor interface */ +/**************************************************/ + +#define NM_TYPE_VPN_EDITOR (nm_vpn_editor_get_type ()) +#define NM_VPN_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_EDITOR, NMVpnEditor)) +#define NM_IS_VPN_EDITOR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_EDITOR)) +#define NM_VPN_EDITOR_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), NM_TYPE_VPN_EDITOR, NMVpnEditorInterface)) + +/** + * NMVpnEditorInterface: + * @g_iface: the parent interface + * @get_widget: return the #GtkWidget for the VPN editor's UI + * @placeholder: not currently used + * @update_connection: called to save the user-entered options to the connection + * object. Should return %FALSE and set @error if the current options are + * invalid. @error should contain enough information for the plugin to + * determine which UI widget is invalid at a later point in time. For + * example, creating unique error codes for what error occurred and populating + * the message field of @error with the name of the invalid property. + * @changed: emitted when the value of a UI widget changes. May trigger a + * validity check via @update_connection to write values to the connection. + * + * Interface for editing a specific #NMConnection + */ +typedef struct { + GTypeInterface g_iface; + + GObject * (*get_widget) (NMVpnEditor *editor); + + void (*placeholder) (void); + + gboolean (*update_connection) (NMVpnEditor *editor, + NMConnection *connection, + GError **error); + + void (*changed) (NMVpnEditor *editor); +} NMVpnEditorInterface; + +GType nm_vpn_editor_get_type (void); + +GObject * nm_vpn_editor_get_widget (NMVpnEditor *editor); + +gboolean nm_vpn_editor_update_connection (NMVpnEditor *editor, + NMConnection *connection, + GError **error); + +G_END_DECLS + +#endif /* __NM_VPN_EDITOR_H__ */ From b5cc017ba473de011881e40b26b3ee3433f1567c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 28 May 2015 22:07:55 +0200 Subject: [PATCH 06/14] libnm: add _nm_utils_check_module_file() --- libnm-core/nm-core-internal.h | 6 +++ libnm-core/nm-utils.c | 84 +++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+) diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index b1fb61b544..ea095a6510 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -143,6 +143,12 @@ gboolean _nm_utils_check_file (const char *filename, struct stat *out_st, GError **error); +char *_nm_utils_check_module_file (const char *name, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error); + #define NM_UTILS_UUID_TYPE_LEGACY 0 #define NM_UTILS_UUID_TYPE_VARIANT3 1 diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 91bde5059e..2cc6ed3955 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2478,6 +2478,90 @@ _nm_utils_check_file (const char *filename, return TRUE; } + +static char * +_resolve_module_file_name (const char *file_name) +{ + char *name = NULL; + + /* g_module_open() is searching for the exact file to load, + * but it doesn't give us a hook to check file permissions + * and ownership. Reimplement the file name resolution. + * + * Copied from g_module_open(). */ + + /* check whether we have a readable file right away */ + if (g_file_test (file_name, G_FILE_TEST_IS_REGULAR)) + name = g_strdup (file_name); + + /* try completing file name with standard library suffix */ + if ( !name + && !g_str_has_suffix (file_name, "." G_MODULE_SUFFIX)) { + name = g_strconcat (file_name, "." G_MODULE_SUFFIX, NULL); + if (!g_file_test (name, G_FILE_TEST_IS_REGULAR)) { + g_free (name); + name = NULL; + } + } + + /* g_module_open() would also try appending ".la". We don't do that + * because we require the user to specify a shared library (directly). */ + + return name; +} + +char * +_nm_utils_check_module_file (const char *name, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error) +{ + gs_free char *name_resolved = NULL; + char *s; + + if (!g_path_is_absolute (name)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("path is not absolute (%s)"), name); + return NULL; + } + + name_resolved = _resolve_module_file_name (name); + + if (!name_resolved) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("could not resolve plugin path (%s)"), name); + return NULL; + } + + if (g_str_has_suffix (name_resolved, ".la")) { + /* g_module_open() treats files that end with .la special. + * We don't want to parse the libtool archive. Just error out. */ + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("libtool archives are not supported (%s)"), name_resolved); + return NULL; + } + + if (!_nm_utils_check_file (name_resolved, + check_owner, + check_file, + user_data, + NULL, + error)) { + return NULL; + } + + s = name_resolved; + name_resolved = NULL; + return s; +} + /**********************************************************************************************/ /** From eed0d0c58f7f13638eb587e240737048d729cb68 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 28 May 2015 22:16:00 +0200 Subject: [PATCH 07/14] libnm: add nm_vpn_editor_plugin_load_from_file() function --- libnm-core/nm-vpn-editor-plugin.c | 147 ++++++++++++++++++++++++++++++ libnm-core/nm-vpn-editor-plugin.h | 10 ++ libnm/libnm.ver | 1 + po/POTFILES.in | 1 + 4 files changed, 159 insertions(+) diff --git a/libnm-core/nm-vpn-editor-plugin.c b/libnm-core/nm-vpn-editor-plugin.c index b36b736859..d5fa6d819b 100644 --- a/libnm-core/nm-vpn-editor-plugin.c +++ b/libnm-core/nm-vpn-editor-plugin.c @@ -24,6 +24,13 @@ #include "nm-vpn-editor-plugin.h" +#include +#include + +#include "nm-macros-internal.h" +#include "gsystem-local-alloc.h" +#include "nm-core-internal.h" + static void nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface); G_DEFINE_INTERFACE (NMVpnEditorPlugin, nm_vpn_editor_plugin, G_TYPE_OBJECT) @@ -67,6 +74,146 @@ nm_vpn_editor_plugin_default_init (NMVpnEditorPluginInterface *iface) G_PARAM_STATIC_STRINGS)); } +/*********************************************************************/ + +/** + * nm_vpn_editor_plugin_load_from_file: + * @plugin_filename: The path to the share library to load. + * Apply some common heuristics to find the library, such as + * appending "so" file ending. + * If the path is not an absolute path or no matching module + * can be found, lookup inside a directory defined at compile time. + * Due to this, @check_file might be called for two different paths. + * @check_name: if not-null, check that the loaded plugin has + * the given name. + * @check_service: if not-null, check that the loaded plugin advertises + * the given service. + * @check_owner: if non-negative, check whether the file is owned + * by UID @check_owner or by root. In this case also check that + * the file is not writable by anybody else. + * @check_file: optional callback to validate the file prior to + * loading the shared library. + * @user_data: user data for @check_file + * @error: on failure the error reason. + * + * Load the shared libary @plugin_filename and create a new + * #NMVpnEditorPlugin instace via the #NMVpnEditorPluginFactory + * function. + * + * Returns: (transfer-full): a new plugin instance or %NULL on error. + * + * Since: 1.2 + */ +NMVpnEditorPlugin * +nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, + const char *check_name, + const char *check_service, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error) +{ + GModule *module = NULL; + gs_free_error GError *local = NULL; + NMVpnEditorPluginFactory factory = NULL; + NMVpnEditorPlugin *editor_plugin = NULL; + + g_return_val_if_fail (plugin_filename && *plugin_filename, NULL); + + if (g_path_is_absolute (plugin_filename)) { + gs_free char *module_filename = NULL; + + module_filename = _nm_utils_check_module_file (plugin_filename, + check_owner, + check_file, + user_data, + &local); + if (module_filename) + module = g_module_open (module_filename, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); + } + + if (!module) { + if (local) { + g_propagate_error (error, local); + local = NULL; + } else { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("cannot load plugin %s"), plugin_filename); + } + return NULL; + } + g_clear_error (&local); + + if (g_module_symbol (module, "nm_vpn_editor_plugin_factory", (gpointer) &factory)) { + gs_free_error GError *factory_error = NULL; + gboolean success = FALSE; + + editor_plugin = factory (&factory_error); + + g_assert (!editor_plugin || G_IS_OBJECT (editor_plugin)); + + if (editor_plugin) { + gs_free char *plug_name = NULL, *plug_service = NULL; + + /* Validate plugin properties */ + + g_object_get (G_OBJECT (editor_plugin), + NM_VPN_EDITOR_PLUGIN_NAME, &plug_name, + NM_VPN_EDITOR_PLUGIN_SERVICE, &plug_service, + NULL); + + if (check_name && g_strcmp0 (plug_name, check_name) != 0) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("cannot load VPN plugin in '%s': invalid plugin name"), + g_module_name (module)); + } else if ( check_service + && g_strcmp0 (plug_service, check_service) != 0) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("cannot load VPN plugin in '%s': invalid service name"), + g_module_name (module)); + } else { + /* Success! */ + g_object_set_data_full (G_OBJECT (editor_plugin), "gmodule", module, + (GDestroyNotify) g_module_close); + success = TRUE; + } + } else { + if (factory_error) { + g_propagate_error (error, factory_error); + factory_error = NULL; + } else { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("unknown error initializing plugin %s"), plugin_filename); + } + } + + if (!success) { + g_module_close (module); + editor_plugin = NULL; + } + } else { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("failed to load nm_vpn_editor_plugin_factory() from %s (%s)"), + g_module_name (module), g_module_error ()); + g_module_close (module); + editor_plugin = NULL; + } + + return editor_plugin; +} + +/*********************************************************************/ + /** * nm_vpn_editor_plugin_get_editor: * diff --git a/libnm-core/nm-vpn-editor-plugin.h b/libnm-core/nm-vpn-editor-plugin.h index a0b1f7aca2..83d765d097 100644 --- a/libnm-core/nm-vpn-editor-plugin.h +++ b/libnm-core/nm-vpn-editor-plugin.h @@ -30,6 +30,7 @@ #include #include "nm-connection.h" +#include "nm-utils.h" G_BEGIN_DECLS @@ -138,6 +139,15 @@ gboolean nm_vpn_editor_plugin_export (NMVpnEditorPlugin *pl char *nm_vpn_editor_plugin_get_suggested_filename (NMVpnEditorPlugin *plugin, NMConnection *connection); +NM_AVAILABLE_IN_1_2 +NMVpnEditorPlugin *nm_vpn_editor_plugin_load_from_file (const char *plugin_filename, + const char *check_name, + const char *check_service, + int check_owner, + NMUtilsCheckFilePredicate check_file, + gpointer user_data, + GError **error); + G_END_DECLS #endif /* __NM_VPN_EDITOR_PLUGIN_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 885e063203..43684195e3 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -882,6 +882,7 @@ global: nm_utils_bond_mode_string_to_int; nm_utils_enum_from_str; nm_utils_enum_to_str; + nm_vpn_editor_plugin_load_from_file; nm_vpn_plugin_info_get_filename; nm_vpn_plugin_info_get_name; nm_vpn_plugin_info_get_plugin; diff --git a/po/POTFILES.in b/po/POTFILES.in index 4b117109e7..7b2c37ae94 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -77,6 +77,7 @@ libnm-core/nm-setting-wireless-security.c libnm-core/nm-setting-wireless.c libnm-core/nm-setting.c libnm-core/nm-utils.c +libnm-core/nm-vpn-editor-plugin.c libnm-core/nm-vpn-plugin-info.c libnm-glib/nm-device.c libnm-glib/nm-remote-connection.c From eafa6c3584421d14e09a18f76bad7b1b5ebc2288 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 28 May 2015 22:12:31 +0200 Subject: [PATCH 08/14] libnm: add load method to NMVpnPluginInfo https://bugzilla.gnome.org/show_bug.cgi?id=749877 --- libnm-core/nm-vpn-plugin-info.c | 121 ++++++++++++++++++++++++++++++++ libnm-core/nm-vpn-plugin-info.h | 11 +++ libnm/libnm.ver | 3 + 3 files changed, 135 insertions(+) diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c index 2842ce2937..762064a5b7 100644 --- a/libnm-core/nm-vpn-plugin-info.c +++ b/libnm-core/nm-vpn-plugin-info.c @@ -56,6 +56,9 @@ typedef struct { * value somewhere... let's put it in an internal hash table. * This contains a clone of all the strings in keyfile. */ GHashTable *keys; + + gboolean editor_plugin_loaded; + NMVpnEditorPlugin *editor_plugin; } NMVpnPluginInfoPrivate; static void nm_vpn_plugin_info_initable_iface_init (GInitableIface *iface); @@ -646,6 +649,112 @@ nm_vpn_plugin_info_lookup_property (NMVpnPluginInfo *self, const char *group, co /*********************************************************************/ +/** + * nm_vpn_plugin_info_get_editor_plugin: + * @self: plugin info instance + * + * Returns: the cached #NMVpnEditorPlugin instance. + * + * Since: 1.2 + */ +NMVpnEditorPlugin * +nm_vpn_plugin_info_get_editor_plugin (NMVpnPluginInfo *self) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + return NM_VPN_PLUGIN_INFO_GET_PRIVATE (self)->editor_plugin; +} + +/** + * nm_vpn_plugin_info_set_editor_plugin: + * @self: plugin info instance + * @plugin: (allow-none): plugin instance + * + * Set the internal plugin instance. If %NULL, only clear the previous instance. + * + * Since: 1.2 + */ +void +nm_vpn_plugin_info_set_editor_plugin (NMVpnPluginInfo *self, NMVpnEditorPlugin *plugin) +{ + NMVpnPluginInfoPrivate *priv; + NMVpnEditorPlugin *old; + + g_return_if_fail (NM_IS_VPN_PLUGIN_INFO (self)); + g_return_if_fail (!plugin || G_IS_OBJECT (plugin)); + + priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (self); + + if (!plugin) { + priv->editor_plugin_loaded = FALSE; + g_clear_object (&priv->editor_plugin); + } else { + old = priv->editor_plugin; + priv->editor_plugin = g_object_ref (plugin); + priv->editor_plugin_loaded = TRUE; + if (old) + g_object_unref (old); + } +} + +/** + * nm_vpn_plugin_info_load_editor_plugin: + * @self: plugin info instance + * @error: error reason on failure + * + * Returns: loads the plugin and returns the newly created instance. + * The plugin is owned by @self and can be later retrieved again + * via nm_vpn_plugin_info_get_editor_plugin(). You can load the + * plugin only once, unless you reset the state via + * nm_vpn_plugin_info_set_editor_plugin(). + * + * Since: 1.2 + */ +NMVpnEditorPlugin * +nm_vpn_plugin_info_load_editor_plugin (NMVpnPluginInfo *self, GError **error) +{ + NMVpnPluginInfoPrivate *priv; + const char *plugin_filename; + + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (self), NULL); + + priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (self); + + if (priv->editor_plugin) + return priv->editor_plugin; + + plugin_filename = nm_vpn_plugin_info_get_plugin (self); + if (!plugin_filename || !*plugin_filename) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("missing \"plugin\" setting")); + return NULL; + } + + /* We only try once to load the plugin. If we previously tried and it was + * unsuccessful, error out immediately. */ + if (priv->editor_plugin_loaded) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + _("%s: don't retry loading plugin which already failed previously"), priv->name); + return NULL; + } + + priv->editor_plugin_loaded = TRUE; + priv->editor_plugin = nm_vpn_editor_plugin_load_from_file (plugin_filename, + priv->name, + nm_vpn_plugin_info_get_service (self), + getuid (), + NULL, + NULL, + error); + return priv->editor_plugin; +} + +/*********************************************************************/ + /** * nm_vpn_plugin_info_new_from_file: * @filename: filename to read. @@ -808,6 +917,17 @@ get_property (GObject *object, guint prop_id, } } +static void +dispose (GObject *object) +{ + NMVpnPluginInfo *self = NM_VPN_PLUGIN_INFO (object); + NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE (self); + + g_clear_object (&priv->editor_plugin); + + G_OBJECT_CLASS (nm_vpn_plugin_info_parent_class)->dispose (object); +} + static void finalize (GObject *object) { @@ -833,6 +953,7 @@ nm_vpn_plugin_info_class_init (NMVpnPluginInfoClass *plugin_class) /* virtual methods */ object_class->set_property = set_property; object_class->get_property = get_property; + object_class->dispose = dispose; object_class->finalize = finalize; /* properties */ diff --git a/libnm-core/nm-vpn-plugin-info.h b/libnm-core/nm-vpn-plugin-info.h index 8e937b57b7..9a7246f840 100644 --- a/libnm-core/nm-vpn-plugin-info.h +++ b/libnm-core/nm-vpn-plugin-info.h @@ -25,6 +25,7 @@ #include #include "nm-utils.h" +#include "nm-vpn-editor-plugin.h" G_BEGIN_DECLS @@ -98,6 +99,16 @@ NMVpnPluginInfo *nm_vpn_plugin_info_list_find_by_filename (GSList *list, const c NM_AVAILABLE_IN_1_2 NMVpnPluginInfo *nm_vpn_plugin_info_list_find_by_service (GSList *list, const char *service); + +NM_AVAILABLE_IN_1_2 +NMVpnEditorPlugin *nm_vpn_plugin_info_get_editor_plugin (NMVpnPluginInfo *plugin_info); +NM_AVAILABLE_IN_1_2 +void nm_vpn_plugin_info_set_editor_plugin (NMVpnPluginInfo *self, + NMVpnEditorPlugin *plugin); +NM_AVAILABLE_IN_1_2 +NMVpnEditorPlugin *nm_vpn_plugin_info_load_editor_plugin (NMVpnPluginInfo *plugin_info, + GError **error); + G_END_DECLS #endif /* __NM_VPN_PLUGIN_INFO_H__ */ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 43684195e3..ce94276533 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -884,14 +884,17 @@ global: nm_utils_enum_to_str; nm_vpn_editor_plugin_load_from_file; nm_vpn_plugin_info_get_filename; + nm_vpn_plugin_info_get_editor_plugin; nm_vpn_plugin_info_get_name; nm_vpn_plugin_info_get_plugin; nm_vpn_plugin_info_get_program; nm_vpn_plugin_info_get_service; nm_vpn_plugin_info_get_type; + nm_vpn_plugin_info_load_editor_plugin; nm_vpn_plugin_info_lookup_property; nm_vpn_plugin_info_new_from_file; nm_vpn_plugin_info_new_with_data; + nm_vpn_plugin_info_set_editor_plugin; nm_vpn_plugin_info_validate_filename; nm_vpn_plugin_info_list_add; nm_vpn_plugin_info_list_find_by_filename; From d2d40cc75b13f03c986dc284d4f244c3640c1776 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 25 May 2015 17:49:12 +0200 Subject: [PATCH 09/14] vpn: refactor vpn-manager to use NMVpnPluginInfo Use NMVpnPluginInfo to load the plugins in NMVpnManager. This has the advantage of reusing the code from libnm to use the same approach to read the plugin config files. Another advantage is that we now check the file permissions of the config file. --- src/vpn-manager/nm-vpn-manager.c | 225 +++++++++++++++++-------------- src/vpn-manager/nm-vpn-service.c | 99 +++++--------- src/vpn-manager/nm-vpn-service.h | 6 +- 3 files changed, 154 insertions(+), 176 deletions(-) diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c index 2a6f48b79c..8dc46c41bf 100644 --- a/src/vpn-manager/nm-vpn-manager.c +++ b/src/vpn-manager/nm-vpn-manager.c @@ -29,44 +29,38 @@ #include "nm-vpn-connection.h" #include "nm-setting-vpn.h" #include "nm-vpn-dbus-interface.h" +#include "nm-core-internal.h" #include "nm-enum-types.h" #include "nm-logging.h" - -#define VPN_NAME_FILES_DIR NMCONFDIR "/VPN" +#include "gsystem-local-alloc.h" G_DEFINE_TYPE (NMVpnManager, nm_vpn_manager, G_TYPE_OBJECT) #define NM_VPN_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_MANAGER, NMVpnManagerPrivate)) typedef struct { - GHashTable *services; - GFileMonitor *monitor; - guint monitor_id; + GSList *services; + GFileMonitor *monitor_etc; + GFileMonitor *monitor_lib; + guint monitor_id_etc; + guint monitor_id_lib; } NMVpnManagerPrivate; - static NMVpnService * -get_service_by_namefile (NMVpnManager *self, const char *namefile) +_plugin_info_get_service (NMVpnPluginInfo *plugin_info) { - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - gpointer data; - - g_return_val_if_fail (namefile, NULL); - g_return_val_if_fail (g_path_is_absolute (namefile), NULL); - - g_hash_table_iter_init (&iter, priv->services); - while (g_hash_table_iter_next (&iter, NULL, &data)) { - NMVpnService *candidate = NM_VPN_SERVICE (data); - const char *service_namefile; - - service_namefile = nm_vpn_service_get_name_file (candidate); - if (!strcmp (namefile, service_namefile)) - return candidate; - } + if (plugin_info) + return NM_VPN_SERVICE (g_object_get_data (G_OBJECT (plugin_info), "service-instance")); return NULL; } +static void +_plugin_info_set_service (NMVpnPluginInfo *plugin_info, NMVpnService *service) +{ + g_object_set_data_full (G_OBJECT (plugin_info), "service-instance", service, + (GDestroyNotify) g_object_unref); +} + gboolean nm_vpn_manager_activate_connection (NMVpnManager *manager, NMVpnConnection *vpn, @@ -75,6 +69,7 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager, NMConnection *connection; NMSettingVpn *s_vpn; NMVpnService *service; + NMVpnPluginInfo *plugin_info; const char *service_name; NMDevice *device; @@ -98,8 +93,8 @@ nm_vpn_manager_activate_connection (NMVpnManager *manager, g_assert (s_vpn); service_name = nm_setting_vpn_get_service_type (s_vpn); - g_assert (service_name); - service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name); + plugin_info = nm_vpn_plugin_info_list_find_by_service (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name); + service = _plugin_info_get_service (plugin_info); if (!service) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_AVAILABLE, "The VPN service '%s' was not installed.", @@ -119,33 +114,31 @@ nm_vpn_manager_deactivate_connection (NMVpnManager *self, } static void -try_add_service (NMVpnManager *self, const char *namefile) +try_add_service (NMVpnManager *self, NMVpnPluginInfo *plugin_info) { NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); NMVpnService *service = NULL; - GHashTableIter iter; GError *error = NULL; - const char *service_name; - g_return_if_fail (g_path_is_absolute (namefile)); - - /* Make sure we don't add dupes */ - g_hash_table_iter_init (&iter, priv->services); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) { - if (g_strcmp0 (namefile, nm_vpn_service_get_name_file (service)) == 0) - return; - } + /* Make sure we don't add dupes. + * We don't really allow reload of the same file. What we do allow is however to + * delete a file and re-add it. */ + if (nm_vpn_plugin_info_list_find_by_filename (priv->services, + nm_vpn_plugin_info_get_filename (plugin_info))) + return; + if (!nm_vpn_plugin_info_list_add (&priv->services, plugin_info, NULL)) + return; /* New service */ - service = nm_vpn_service_new (namefile, &error); + service = nm_vpn_service_new (plugin_info, &error); if (service) { - service_name = nm_vpn_service_get_dbus_service (service); - g_hash_table_insert (priv->services, (char *) service_name, service); - nm_log_info (LOGD_VPN, "VPN: loaded %s", service_name); + _plugin_info_set_service (plugin_info, service); + nm_log_info (LOGD_VPN, "VPN: loaded %s - %s", + nm_vpn_plugin_info_get_name (plugin_info), + nm_vpn_service_get_dbus_service (service)); } else { - nm_log_warn (LOGD_VPN, "failed to load VPN service file %s: (%d) %s", - namefile, - error ? error->code : -1, + nm_log_warn (LOGD_VPN, "failed to load VPN service file %s: %s", + nm_vpn_plugin_info_get_filename (plugin_info), error && error->message ? error->message : "(unknown)"); g_clear_error (&error); } @@ -160,41 +153,65 @@ vpn_dir_changed (GFileMonitor *monitor, { NMVpnManager *self = NM_VPN_MANAGER (user_data); NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); + NMVpnPluginInfo *plugin_info; NMVpnService *service; - char *path; + gs_free char *path = NULL; + GError *error = NULL; path = g_file_get_path (file); - if (!g_str_has_suffix (path, ".name")) { - g_free (path); + if (!nm_vpn_plugin_info_validate_filename (path)) return; - } switch (event_type) { case G_FILE_MONITOR_EVENT_DELETED: - nm_log_dbg (LOGD_VPN, "service file %s deleted", path); + plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->services, path); + if (!plugin_info) + break; - service = get_service_by_namefile (self, path); + nm_log_dbg (LOGD_VPN, "vpn: service file %s deleted", path); + service = _plugin_info_get_service (plugin_info); if (service) { - const char *service_name = nm_vpn_service_get_dbus_service (service); - /* Stop active VPN connections and destroy the service */ nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); - nm_log_info (LOGD_VPN, "VPN: unloaded %s", service_name); - g_hash_table_remove (priv->services, service_name); + nm_log_info (LOGD_VPN, "VPN: unloaded %s", nm_vpn_service_get_dbus_service (service)); + + _plugin_info_set_service (plugin_info, NULL); } + nm_vpn_plugin_info_list_remove (&priv->services, plugin_info); break; case G_FILE_MONITOR_EVENT_CREATED: case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT: - nm_log_dbg (LOGD_VPN, "service file %s created or modified", path); - try_add_service (self, path); + plugin_info = nm_vpn_plugin_info_list_find_by_filename (priv->services, path); + if (plugin_info) { + /* we don't support reloading an existing plugin. You can only remove the file + * and re-add it. By reloading we want to support the use case of installing + * a VPN plugin after NM started. No need to burden ourself with a complete + * reload. */ + break; + } + + if (!_nm_vpn_plugin_info_check_file (path, TRUE, TRUE, 0, + NULL, NULL, &error)) { + nm_log_dbg (LOGD_VPN, "vpn: ignore changed service file %s (%s)", path, error->message); + g_clear_error (&error); + break; + } + plugin_info = nm_vpn_plugin_info_new_from_file (path, &error); + if (!plugin_info) { + nm_log_dbg (LOGD_VPN, "vpn: ignore changed service file %s due to invalid content (%s)", path, error->message); + g_clear_error (&error); + break; + } + + nm_log_dbg (LOGD_VPN, "vpn: service file %s created or modified", path); + try_add_service (self, plugin_info); + g_object_unref (plugin_info); break; default: - nm_log_dbg (LOGD_VPN, "service file %s change event %d", path, event_type); + nm_log_dbg (LOGD_VPN, "vpn: service file %s change event %d", path, event_type); break; } - - g_free (path); } /******************************************************************************/ @@ -206,50 +223,40 @@ nm_vpn_manager_init (NMVpnManager *self) { NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); GFile *file; - GDir *dir; - const char *fn; - char *path; - - priv->services = g_hash_table_new_full (g_str_hash, g_str_equal, - NULL, g_object_unref); + GSList *infos, *info; + const char *conf_dir_etc = _nm_vpn_plugin_info_get_default_dir_etc (); + const char *conf_dir_lib = _nm_vpn_plugin_info_get_default_dir_lib (); /* Watch the VPN directory for changes */ - file = g_file_new_for_path (VPN_NAME_FILES_DIR "/"); - priv->monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + file = g_file_new_for_path (conf_dir_lib); + priv->monitor_lib = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); g_object_unref (file); - if (priv->monitor) { - priv->monitor_id = g_signal_connect (priv->monitor, "changed", - G_CALLBACK (vpn_dir_changed), self); + if (priv->monitor_lib) { + priv->monitor_id_lib = g_signal_connect (priv->monitor_lib, "changed", + G_CALLBACK (vpn_dir_changed), self); } - /* Load VPN service files */ - dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL); - if (dir) { - while ((fn = g_dir_read_name (dir))) { - /* only parse filenames that end with .name */ - if (g_str_has_suffix (fn, ".name")) { - path = g_build_filename (VPN_NAME_FILES_DIR, fn, NULL); - try_add_service (self, path); - g_free (path); - } - } - g_dir_close (dir); + file = g_file_new_for_path (conf_dir_etc); + priv->monitor_etc = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL); + g_object_unref (file); + if (priv->monitor_etc) { + priv->monitor_id_etc = g_signal_connect (priv->monitor_etc, "changed", + G_CALLBACK (vpn_dir_changed), self); } -} -static void -stop_all_services (NMVpnManager *self) -{ - NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self); - GHashTableIter iter; - NMVpnService *service; + /* first read conf_dir_lib. The name files are not really user configuration, but + * plugin configuration. Hence we expect ~newer~ plugins to install their files + * in /usr/lib/NetworkManager. We want to prefer those files. + * In case of no-conflict, the order doesn't matter. */ + infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_lib, TRUE, 0, NULL, NULL); + for (info = infos; info; info = info->next) + try_add_service (self, info->data); + g_slist_free_full (infos, g_object_unref); - g_hash_table_iter_init (&iter, priv->services); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &service)) { - nm_vpn_service_stop_connections (service, - TRUE, - NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); - } + infos = _nm_vpn_plugin_info_list_load_dir (conf_dir_etc, TRUE, 0, NULL, NULL); + for (info = infos; info; info = info->next) + try_add_service (self, info->data); + g_slist_free_full (infos, g_object_unref); } static void @@ -257,17 +264,29 @@ dispose (GObject *object) { NMVpnManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (object); - if (priv->monitor) { - if (priv->monitor_id) - g_signal_handler_disconnect (priv->monitor, priv->monitor_id); - g_file_monitor_cancel (priv->monitor); - g_clear_object (&priv->monitor); + if (priv->monitor_etc) { + if (priv->monitor_id_etc) + g_signal_handler_disconnect (priv->monitor_etc, priv->monitor_id_etc); + g_file_monitor_cancel (priv->monitor_etc); + g_clear_object (&priv->monitor_etc); } - if (priv->services) { - stop_all_services (NM_VPN_MANAGER (object)); - g_hash_table_destroy (priv->services); - priv->services = NULL; + if (priv->monitor_lib) { + if (priv->monitor_id_lib) + g_signal_handler_disconnect (priv->monitor_lib, priv->monitor_id_lib); + g_file_monitor_cancel (priv->monitor_lib); + g_clear_object (&priv->monitor_lib); + } + + while (priv->services) { + NMVpnPluginInfo *plugin_info = priv->services->data; + NMVpnService *service = _plugin_info_get_service (plugin_info); + + if (service) { + nm_vpn_service_stop_connections (service, TRUE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); + _plugin_info_set_service (plugin_info, NULL); + } + nm_vpn_plugin_info_list_remove (&priv->services, plugin_info); } G_OBJECT_CLASS (nm_vpn_manager_parent_class)->dispose (object); diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c index 56cb6abe74..4661ab4223 100644 --- a/src/vpn-manager/nm-vpn-service.c +++ b/src/vpn-manager/nm-vpn-service.c @@ -35,10 +35,7 @@ G_DEFINE_TYPE (NMVpnService, nm_vpn_service, G_TYPE_OBJECT) typedef struct { - char *name; - char *dbus_service; - char *program; - char *namefile; + NMVpnPluginInfo *plugin_info; NMVpnConnection *active; GSList *pending; @@ -50,67 +47,50 @@ typedef struct { #define NM_VPN_SERVICE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_SERVICE, NMVpnServicePrivate)) -#define VPN_CONNECTION_GROUP "VPN Connection" - static gboolean start_pending_vpn (NMVpnService *self, GError **error); static void _name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data); NMVpnService * -nm_vpn_service_new (const char *namefile, GError **error) +nm_vpn_service_new (NMVpnPluginInfo *plugin_info, GError **error) { NMVpnService *self; NMVpnServicePrivate *priv; - GKeyFile *kf; - g_return_val_if_fail (namefile != NULL, NULL); - g_return_val_if_fail (g_path_is_absolute (namefile), NULL); + g_return_val_if_fail (NM_IS_VPN_PLUGIN_INFO (plugin_info), NULL); + g_return_val_if_fail (nm_vpn_plugin_info_get_filename (plugin_info), NULL); - kf = g_key_file_new (); - if (!g_key_file_load_from_file (kf, namefile, G_KEY_FILE_NONE, error)) { - g_key_file_free (kf); + if (!nm_vpn_plugin_info_get_program (plugin_info)) { + g_set_error (error, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_FAILED, + "missing \"program\" entry"); return NULL; } self = (NMVpnService *) g_object_new (NM_TYPE_VPN_SERVICE, NULL); priv = NM_VPN_SERVICE_GET_PRIVATE (self); - priv->namefile = g_strdup (namefile); - - priv->dbus_service = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "service", error); - if (!priv->dbus_service) - goto error; - - priv->program = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "program", error); - if (!priv->program) - goto error; - - priv->name = g_key_file_get_string (kf, VPN_CONNECTION_GROUP, "name", error); - if (!priv->name) - goto error; + priv->plugin_info = g_object_ref (plugin_info); priv->proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START, NULL, - priv->dbus_service, + nm_vpn_plugin_info_get_service (plugin_info), NM_VPN_DBUS_PLUGIN_PATH, NM_VPN_DBUS_PLUGIN_INTERFACE, NULL, error); - if (!priv->proxy) - goto error; + if (!priv->proxy) { + g_object_unref (self); + return NULL; + } g_signal_connect (priv->proxy, "notify::g-name-owner", G_CALLBACK (_name_owner_changed), self); _name_owner_changed (G_OBJECT (priv->proxy), NULL, self); - g_key_file_free (kf); return self; - -error: - g_object_unref (self); - g_key_file_free (kf); - return NULL; } const char * @@ -118,15 +98,7 @@ nm_vpn_service_get_dbus_service (NMVpnService *service) { g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL); - return NM_VPN_SERVICE_GET_PRIVATE (service)->dbus_service; -} - -const char * -nm_vpn_service_get_name_file (NMVpnService *service) -{ - g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL); - - return NM_VPN_SERVICE_GET_PRIVATE (service)->namefile; + return nm_vpn_plugin_info_get_service (NM_VPN_SERVICE_GET_PRIVATE (service)->plugin_info); } static void @@ -187,7 +159,7 @@ _daemon_exec_timeout (gpointer data) NMVpnService *self = NM_VPN_SERVICE (data); NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - nm_log_warn (LOGD_VPN, "VPN service '%s' start timed out", priv->name); + nm_log_warn (LOGD_VPN, "VPN service '%s' start timed out", nm_vpn_plugin_info_get_name (priv->plugin_info)); priv->start_timeout = 0; nm_vpn_service_stop_connections (self, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_START_TIMEOUT); return G_SOURCE_REMOVE; @@ -204,17 +176,21 @@ nm_vpn_service_daemon_exec (NMVpnService *service, GError **error) g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE); - vpn_argv[0] = priv->program; + vpn_argv[0] = (char *) nm_vpn_plugin_info_get_program (priv->plugin_info); vpn_argv[1] = NULL; + g_assert (vpn_argv[0]); + success = g_spawn_async (NULL, vpn_argv, NULL, 0, nm_utils_setpgid, NULL, &pid, &spawn_error); if (success) { nm_log_info (LOGD_VPN, "VPN service '%s' started (%s), PID %ld", - priv->name, priv->dbus_service, (long int) pid); + nm_vpn_plugin_info_get_name (priv->plugin_info), + nm_vpn_service_get_dbus_service (service), + (long int) pid); priv->start_timeout = g_timeout_add_seconds (5, _daemon_exec_timeout, service); } else { nm_log_warn (LOGD_VPN, "VPN service '%s': could not launch the VPN service. error: (%d) %s.", - priv->name, + nm_vpn_plugin_info_get_name (priv->plugin_info), spawn_error ? spawn_error->code : -1, spawn_error && spawn_error->message ? spawn_error->message : "(unknown)"); @@ -244,7 +220,7 @@ start_active_vpn (NMVpnService *self, GError **error) return TRUE; } else if (priv->start_timeout == 0) { /* VPN service not running, start it */ - nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", priv->name); + nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", nm_vpn_plugin_info_get_name (priv->plugin_info)); return nm_vpn_service_daemon_exec (self, error); } @@ -324,14 +300,14 @@ _name_owner_changed (GObject *object, if (owner && !priv->service_running) { /* service appeared */ priv->service_running = TRUE; - nm_log_info (LOGD_VPN, "VPN service '%s' appeared; activating connections", priv->name); + nm_log_info (LOGD_VPN, "VPN service '%s' appeared; activating connections", nm_vpn_plugin_info_get_name (priv->plugin_info)); /* Expect success because the VPN service has already appeared */ success = start_active_vpn (service, NULL); g_warn_if_fail (success); } else if (!owner && priv->service_running) { /* service went away */ priv->service_running = FALSE; - nm_log_info (LOGD_VPN, "VPN service '%s' disappeared", priv->name); + nm_log_info (LOGD_VPN, "VPN service '%s' disappeared", nm_vpn_plugin_info_get_name (priv->plugin_info)); nm_vpn_service_stop_connections (service, FALSE, NM_VPN_CONNECTION_STATE_REASON_SERVICE_STOPPED); } @@ -351,10 +327,9 @@ dispose (GObject *object) NMVpnService *self = NM_VPN_SERVICE (object); NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (self); - if (priv->start_timeout) { - g_source_remove (priv->start_timeout); - priv->start_timeout = 0; - } + nm_clear_g_source (&priv->start_timeout); + + g_clear_object (&priv->plugin_info); /* VPNService owner is required to stop connections before releasing */ g_assert (priv->active == NULL); @@ -370,19 +345,6 @@ dispose (GObject *object) G_OBJECT_CLASS (nm_vpn_service_parent_class)->dispose (object); } -static void -finalize (GObject *object) -{ - NMVpnServicePrivate *priv = NM_VPN_SERVICE_GET_PRIVATE (object); - - g_free (priv->name); - g_free (priv->dbus_service); - g_free (priv->program); - g_free (priv->namefile); - - G_OBJECT_CLASS (nm_vpn_service_parent_class)->finalize (object); -} - static void nm_vpn_service_class_init (NMVpnServiceClass *service_class) { @@ -392,5 +354,4 @@ nm_vpn_service_class_init (NMVpnServiceClass *service_class) /* virtual methods */ object_class->dispose = dispose; - object_class->finalize = finalize; } diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h index 6e935950e2..a748d32f39 100644 --- a/src/vpn-manager/nm-vpn-service.h +++ b/src/vpn-manager/nm-vpn-service.h @@ -25,6 +25,7 @@ #include "nm-glib.h" #include "nm-device.h" #include "nm-vpn-connection.h" +#include "nm-vpn-plugin-info.h" #define NM_TYPE_VPN_SERVICE (nm_vpn_service_get_type ()) #define NM_VPN_SERVICE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_SERVICE, NMVpnService)) @@ -43,14 +44,11 @@ typedef struct { GType nm_vpn_service_get_type (void); -NMVpnService * nm_vpn_service_new (const char *namefile, GError **error); +NMVpnService * nm_vpn_service_new (NMVpnPluginInfo *plugin_info, GError **error); /* Returns the VPN service's D-Bus service name */ const char *nm_vpn_service_get_dbus_service (NMVpnService *service); -/* Returns the path of the VPN service's .name file */ -const char *nm_vpn_service_get_name_file (NMVpnService *service); - gboolean nm_vpn_service_activate (NMVpnService *service, NMVpnConnection *vpn, GError **error); From b378ae19fceac3626a5173c7122e5939ddd62506 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 26 May 2015 11:10:12 +0200 Subject: [PATCH 10/14] tui: use NMVpnPluginInfo in vpn-helper.c vpn-helper.c is currently not yet used. It was added for future VPN support for nmtui. Refactor it to make use of the new vpn helper functions in libnm. --- clients/tui/vpn-helpers.c | 151 +++++++------------------------------- clients/tui/vpn-helpers.h | 9 +-- 2 files changed, 28 insertions(+), 132 deletions(-) diff --git a/clients/tui/vpn-helpers.c b/clients/tui/vpn-helpers.c index be8f538463..9cf8ce84c0 100644 --- a/clients/tui/vpn-helpers.c +++ b/clients/tui/vpn-helpers.c @@ -34,142 +34,41 @@ #include #include -#include -#include -#include - #include "nm-glib.h" #include "vpn-helpers.h" -#define NM_VPN_API_SUBJECT_TO_CHANGE -#include "nm-vpn-plugin-ui-interface.h" +#include "nm-macros-internal.h" -#define VPN_NAME_FILES_DIR SYSCONFDIR"/NetworkManager/VPN" +static gboolean plugins_loaded; +static GSList *plugins = NULL; -static GHashTable *plugins = NULL; - -G_DEFINE_QUARK (NMA_ERROR, nma_error) -#define NMA_ERROR nma_error_quark () -#define NMA_ERROR_GENERIC 0 - -NMVpnPluginUiInterface * +NMVpnEditorPlugin * vpn_get_plugin_by_service (const char *service) { + NMVpnEditorPlugin *plugin = NULL; + NMVpnPluginInfo *plugin_info; + g_return_val_if_fail (service != NULL, NULL); - return g_hash_table_lookup (plugins, service); + if (G_UNLIKELY (!plugins_loaded)) + vpn_get_plugins (); + + plugin_info = nm_vpn_plugin_info_list_find_by_service (plugins, service); + if (plugin_info) { + plugin = nm_vpn_plugin_info_get_editor_plugin (plugin_info); + if (!plugin) + plugin = nm_vpn_plugin_info_load_editor_plugin (plugin_info, NULL); + } + return plugin; } -GHashTable * -vpn_get_plugins (GError **error) +GSList * +vpn_get_plugins () { - GDir *dir; - const char *f; - - if (error) - g_return_val_if_fail (*error == NULL, NULL); - - if (plugins) + if (G_LIKELY (plugins_loaded)) return plugins; - - dir = g_dir_open (VPN_NAME_FILES_DIR, 0, NULL); - if (!dir) { - g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "Couldn't read VPN .name files directory " VPN_NAME_FILES_DIR "."); - return NULL; - } - - plugins = g_hash_table_new_full (g_str_hash, g_str_equal, - (GDestroyNotify) g_free, (GDestroyNotify) g_object_unref); - - while ((f = g_dir_read_name (dir))) { - char *path = NULL, *service = NULL; - char *so_path = NULL, *so_name = NULL; - GKeyFile *keyfile = NULL; - GModule *module; - NMVpnPluginUiFactory factory = NULL; - - if (!g_str_has_suffix (f, ".name")) - continue; - - path = g_strdup_printf ("%s/%s", VPN_NAME_FILES_DIR, f); - - keyfile = g_key_file_new (); - if (!g_key_file_load_from_file (keyfile, path, 0, NULL)) - goto next; - - service = g_key_file_get_string (keyfile, "VPN Connection", "service", NULL); - if (!service) - goto next; - - so_path = g_key_file_get_string (keyfile, "GNOME", "properties", NULL); - if (!so_path) - goto next; - - /* Remove any path and extension components, then reconstruct path - * to the SO in LIBDIR - */ - so_name = g_path_get_basename (so_path); - g_free (so_path); - so_path = g_strdup_printf ("%s/NetworkManager/%s", LIBDIR, so_name); - g_free (so_name); - - module = g_module_open (so_path, G_MODULE_BIND_LAZY | G_MODULE_BIND_LOCAL); - if (!module) { - g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "Cannot load the VPN plugin which provides the " - "service '%s'.", service); - goto next; - } - - if (g_module_symbol (module, "nm_vpn_plugin_ui_factory", (gpointer) &factory)) { - NMVpnPluginUiInterface *plugin; - GError *factory_error = NULL; - gboolean success = FALSE; - - plugin = factory (&factory_error); - if (plugin) { - char *plug_name = NULL, *plug_service = NULL; - - /* Validate plugin properties */ - g_object_get (G_OBJECT (plugin), - NM_VPN_PLUGIN_UI_INTERFACE_NAME, &plug_name, - NM_VPN_PLUGIN_UI_INTERFACE_SERVICE, &plug_service, - NULL); - if (!plug_name || !strlen (plug_name)) { - g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot load VPN plugin in '%s': missing plugin name", - g_module_name (module)); - } else if (!plug_service || strcmp (plug_service, service)) { - g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot load VPN plugin in '%s': invalid service name", - g_module_name (module)); - } else { - /* Success! */ - g_object_set_data_full (G_OBJECT (plugin), "gmodule", module, - (GDestroyNotify) g_module_close); - g_hash_table_insert (plugins, g_strdup (service), plugin); - success = TRUE; - } - g_free (plug_name); - g_free (plug_service); - } else { - g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot load VPN plugin in '%s': %s", - g_module_name (module), g_module_error ()); - } - - if (!success) - g_module_close (module); - } else { - g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, "cannot locate nm_vpn_plugin_ui_factory() in '%s': %s", - g_module_name (module), g_module_error ()); - g_module_close (module); - } - - next: - g_free (so_path); - g_free (service); - g_key_file_free (keyfile); - g_free (path); - } - g_dir_close (dir); - + plugins_loaded = TRUE; + plugins = nm_vpn_plugin_info_list_load (); return plugins; } @@ -409,7 +308,7 @@ vpn_supports_ipv6 (NMConnection *connection) { NMSettingVpn *s_vpn; const char *service_type; - NMVpnPluginUiInterface *plugin; + NMVpnEditorPlugin *plugin; guint32 capabilities; s_vpn = nm_connection_get_setting_vpn (connection); @@ -421,6 +320,6 @@ vpn_supports_ipv6 (NMConnection *connection) plugin = vpn_get_plugin_by_service (service_type); g_return_val_if_fail (plugin != NULL, FALSE); - capabilities = nm_vpn_plugin_ui_interface_get_capabilities (plugin); - return (capabilities & NM_VPN_PLUGIN_UI_CAPABILITY_IPV6) != 0; + capabilities = nm_vpn_editor_plugin_get_capabilities (plugin); + return NM_FLAGS_HAS (capabilities, NM_VPN_EDITOR_PLUGIN_CAPABILITY_IPV6); } diff --git a/clients/tui/vpn-helpers.h b/clients/tui/vpn-helpers.h index 3bb26c6d76..4503b8178f 100644 --- a/clients/tui/vpn-helpers.h +++ b/clients/tui/vpn-helpers.h @@ -19,16 +19,13 @@ #ifndef _VPN_HELPERS_H_ #define _VPN_HELPERS_H_ -#include - -#define NM_VPN_API_SUBJECT_TO_CHANGE -#include +#include #include "nm-glib.h" -GHashTable *vpn_get_plugins (GError **error); +GSList *vpn_get_plugins (void); -NMVpnPluginUiInterface *vpn_get_plugin_by_service (const char *service); +NMVpnEditorPlugin *vpn_get_plugin_by_service (const char *service); typedef void (*VpnImportSuccessCallback) (NMConnection *connection, gpointer user_data); void vpn_import (VpnImportSuccessCallback callback, gpointer user_data); From 87f631f2f137271b7e4c86377c2d941608a81a9d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 2 Jun 2015 11:30:58 +0200 Subject: [PATCH 11/14] libnm/vpn: copy 'nm-vpn-plugin-old' files to 'nm-vpn-service-plugin' Files are yet unchanged, only copy them to get a nicer history. /bin/cp libnm/nm-vpn-plugin-old.c libnm/nm-vpn-service-plugin.c /bin/cp libnm/nm-vpn-plugin-old.h libnm/nm-vpn-service-plugin.h --- libnm/nm-vpn-service-plugin.c | 1199 +++++++++++++++++++++++++++++++++ libnm/nm-vpn-service-plugin.h | 136 ++++ 2 files changed, 1335 insertions(+) create mode 100644 libnm/nm-vpn-service-plugin.c create mode 100644 libnm/nm-vpn-service-plugin.h diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c new file mode 100644 index 0000000000..9f3bc058c4 --- /dev/null +++ b/libnm/nm-vpn-service-plugin.c @@ -0,0 +1,1199 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2007 - 2008 Novell, Inc. + * Copyright 2007 - 2008 Red Hat, Inc. + */ + +/* This interface is expected to be deprecated in NM 1.2, at which point there + * will be a new "NMVpnPlugin" class to replace it. + */ + +#include "config.h" + +#include +#include +#include + +#include + +#include "nm-glib.h" +#include "nm-vpn-plugin-old.h" +#include "nm-enum-types.h" +#include "nm-utils.h" +#include "nm-connection.h" +#include "nm-dbus-helpers.h" +#include "nm-core-internal.h" +#include "nm-simple-connection.h" +#include "nm-macros-internal.h" + +#include "nmdbus-vpn-plugin.h" + +#define NM_VPN_PLUGIN_OLD_QUIT_TIMER 20 + +static void nm_vpn_plugin_old_initable_iface_init (GInitableIface *iface); + +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMVpnPluginOld, nm_vpn_plugin_old, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_vpn_plugin_old_initable_iface_init); + ) + +typedef struct { + NMVpnServiceState state; + + /* DBUS-y stuff */ + GDBusConnection *connection; + NMDBusVpnPlugin *dbus_vpn_plugin_old; + char *dbus_service_name; + + /* Temporary stuff */ + guint connect_timer; + guint quit_timer; + guint fail_stop_id; + gboolean interactive; + + gboolean got_config; + gboolean has_ip4, got_ip4; + gboolean has_ip6, got_ip6; + + /* Config stuff copied from config to ip4config */ + GVariant *banner, *tundev, *gateway, *mtu; +} NMVpnPluginOldPrivate; + +#define NM_VPN_PLUGIN_OLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldPrivate)) + +enum { + STATE_CHANGED, + CONFIG, + IP4_CONFIG, + IP6_CONFIG, + LOGIN_BANNER, + FAILURE, + QUIT, + SECRETS_REQUIRED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +enum { + PROP_0, + PROP_DBUS_SERVICE_NAME, + PROP_STATE, + + LAST_PROP +}; + +static GSList *active_plugins = NULL; + + +static void +nm_vpn_plugin_old_set_connection (NMVpnPluginOld *plugin, + GDBusConnection *connection) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + g_clear_object (&priv->connection); + + if (connection) + priv->connection = g_object_ref (connection); +} + +/** + * nm_vpn_plugin_old_get_connection: + * + * Returns: (transfer full): + */ +GDBusConnection * +nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin) +{ + GDBusConnection *connection; + + g_return_val_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin), NULL); + + connection = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin)->connection; + + if (connection) + g_object_ref (connection); + + return connection; +} + +NMVpnServiceState +nm_vpn_plugin_old_get_state (NMVpnPluginOld *plugin) +{ + g_return_val_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin), NM_VPN_SERVICE_STATE_UNKNOWN); + + return NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin)->state; +} + +void +nm_vpn_plugin_old_set_state (NMVpnPluginOld *plugin, + NMVpnServiceState state) +{ + NMVpnPluginOldPrivate *priv; + + g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + + priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + if (priv->state != state) { + priv->state = state; + g_signal_emit (plugin, signals[STATE_CHANGED], 0, state); + } +} + +void +nm_vpn_plugin_old_set_login_banner (NMVpnPluginOld *plugin, + const char *banner) +{ + g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (banner != NULL); + + g_signal_emit (plugin, signals[LOGIN_BANNER], 0, banner); +} + +void +nm_vpn_plugin_old_failure (NMVpnPluginOld *plugin, + NMVpnPluginFailure reason) +{ + g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + + g_signal_emit (plugin, signals[FAILURE], 0, reason); +} + +gboolean +nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, GError **err) +{ + gboolean ret = FALSE; + NMVpnServiceState state; + + g_return_val_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin), FALSE); + + state = nm_vpn_plugin_old_get_state (plugin); + switch (state) { + case NM_VPN_SERVICE_STATE_STOPPING: + g_set_error (err, + 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."); + break; + case NM_VPN_SERVICE_STATE_STOPPED: + g_set_error (err, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_ALREADY_STOPPED, + "%s", + "Could not process the request because no VPN connection was active."); + break; + case NM_VPN_SERVICE_STATE_STARTING: + case NM_VPN_SERVICE_STATE_STARTED: + nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPING); + ret = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->disconnect (plugin, err); + nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPED); + break; + case NM_VPN_SERVICE_STATE_INIT: + ret = TRUE; + break; + + default: + g_warning ("Unhandled VPN service state %d", state); + g_assert_not_reached (); + break; + } + + return ret; +} + +static void +nm_vpn_plugin_old_emit_quit (NMVpnPluginOld *plugin) +{ + g_signal_emit (plugin, signals[QUIT], 0); +} + +static gboolean +connect_timer_expired (gpointer data) +{ + NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (data); + GError *err = NULL; + + NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin)->connect_timer = 0; + g_message ("Connect timer expired, disconnecting."); + nm_vpn_plugin_old_disconnect (plugin, &err); + if (err) { + g_warning ("Disconnect failed: %s", err->message); + g_error_free (err); + } + + return G_SOURCE_REMOVE; +} + +static gboolean +quit_timer_expired (gpointer data) +{ + NMVpnPluginOld *self = NM_VPN_PLUGIN_OLD (data); + + NM_VPN_PLUGIN_OLD_GET_PRIVATE (self)->quit_timer = 0; + nm_vpn_plugin_old_emit_quit (self); + return G_SOURCE_REMOVE; +} + +static void +schedule_quit_timer (NMVpnPluginOld *self) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (self); + + nm_clear_g_source (&priv->quit_timer); + priv->quit_timer = g_timeout_add_seconds (NM_VPN_PLUGIN_OLD_QUIT_TIMER, + quit_timer_expired, + self); +} + +static gboolean +fail_stop (gpointer data) +{ + NMVpnPluginOld *self = NM_VPN_PLUGIN_OLD (data); + + NM_VPN_PLUGIN_OLD_GET_PRIVATE (self)->fail_stop_id = 0; + nm_vpn_plugin_old_set_state (self, NM_VPN_SERVICE_STATE_STOPPED); + return G_SOURCE_REMOVE; +} + +static void +schedule_fail_stop (NMVpnPluginOld *plugin) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + nm_clear_g_source (&priv->fail_stop_id); + priv->fail_stop_id = g_idle_add (fail_stop, plugin); +} + +void +nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, + GVariant *config) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (config != NULL); + + priv->got_config = TRUE; + + (void) g_variant_lookup (config, NM_VPN_PLUGIN_CONFIG_HAS_IP4, "b", &priv->has_ip4); + (void) g_variant_lookup (config, NM_VPN_PLUGIN_CONFIG_HAS_IP6, "b", &priv->has_ip6); + + 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. + */ + if (priv->banner) + g_variant_unref (priv->banner); + priv->banner = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_BANNER, + G_VARIANT_TYPE ("s")); + if (priv->tundev) + g_variant_unref (priv->tundev); + priv->tundev = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_TUNDEV, + G_VARIANT_TYPE ("s")); + if (priv->gateway) + g_variant_unref (priv->gateway); + priv->gateway = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_EXT_GATEWAY, + G_VARIANT_TYPE ("u")); + if (priv->mtu) + g_variant_unref (priv->mtu); + priv->mtu = g_variant_lookup_value (config, NM_VPN_PLUGIN_CONFIG_MTU, + G_VARIANT_TYPE ("u")); + + g_signal_emit (plugin, signals[CONFIG], 0, config); +} + +void +nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, + GVariant *ip4_config) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + GVariant *combined_config; + GVariantBuilder builder; + GVariantIter iter; + const char *key; + GVariant *value; + + g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (ip4_config != NULL); + + priv->got_ip4 = TRUE; + + /* Old plugins won't send the "config" signal and thus can't send + * NM_VPN_PLUGIN_OLD_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; + + /* 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. + */ + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_iter_init (&iter, ip4_config); + while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) { + g_variant_builder_add (&builder, "{sv}", key, value); + g_variant_unref (value); + } + + if (priv->banner) + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_BANNER, &priv->banner); + if (priv->tundev) + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_TUNDEV, &priv->tundev); + if (priv->gateway) + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_EXT_GATEWAY, &priv->gateway); + if (priv->mtu) + g_variant_builder_add (&builder, "{sv}", NM_VPN_PLUGIN_IP4_CONFIG_MTU, &priv->mtu); + + combined_config = g_variant_builder_end (&builder); + g_variant_ref_sink (combined_config); + g_signal_emit (plugin, signals[IP4_CONFIG], 0, combined_config); + g_variant_unref (combined_config); + + if ( priv->has_ip4 == priv->got_ip4 + && priv->has_ip6 == priv->got_ip6) + nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); +} + +void +nm_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, + GVariant *ip6_config) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (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_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); +} + +static void +connect_timer_start (NMVpnPluginOld *plugin) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + priv->connect_timer = g_timeout_add_seconds (60, connect_timer_expired, plugin); +} + +static void +_connect_generic (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *properties, + GVariant *details) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnPluginOldClass *vpn_class = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin); + NMConnection *connection; + gboolean success = FALSE; + GError *error = NULL; + + if (priv->state != NM_VPN_SERVICE_STATE_STOPPED && + priv->state != NM_VPN_SERVICE_STATE_INIT) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_WRONG_STATE, + "Could not start connection: wrong plugin state %d", + priv->state); + return; + } + + connection = nm_simple_connection_new_from_dbus (properties, &error); + if (!connection) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Invalid connection: (%d) %s", + error->code, error->message); + g_clear_error (&error); + } + + priv->interactive = FALSE; + if (details && !vpn_class->connect_interactive) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED, + "Plugin does not implement ConnectInteractive()"); + return; + } + + nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + + if (details) { + priv->interactive = TRUE; + success = vpn_class->connect_interactive (plugin, connection, details, &error); + } else + success = vpn_class->connect (plugin, connection, &error); + + if (success) { + g_dbus_method_invocation_return_value (context, NULL); + + /* Add a timer to make sure we do not wait indefinitely for the successful connect. */ + connect_timer_start (plugin); + } else { + g_dbus_method_invocation_take_error (context, error); + + /* Stop the plugin from an idle handler so that the Connect + * method return gets sent before the STOP StateChanged signal. + */ + schedule_fail_stop (plugin); + } + + g_object_unref (connection); +} + +static void +impl_vpn_plugin_old_connect (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *connection, + gpointer user_data) +{ + _connect_generic (plugin, context, connection, NULL); +} + +static void +impl_vpn_plugin_old_connect_interactive (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *connection, + GVariant *details, + gpointer user_data) +{ + _connect_generic (plugin, context, connection, details); +} + +/***************************************************************/ + +static void +impl_vpn_plugin_old_need_secrets (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *properties, + gpointer user_data) +{ + NMConnection *connection; + const char *setting_name; + gboolean needed; + GError *error = NULL; + + connection = nm_simple_connection_new_from_dbus (properties, &error); + if (!connection) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_INVALID_CONNECTION, + "The connection was invalid: %s", + error->message); + g_error_free (error); + return; + } + + if (!NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->need_secrets) { + g_dbus_method_invocation_return_value (context, + g_variant_new ("(s)", "")); + return; + } + + needed = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->need_secrets (plugin, connection, &setting_name, &error); + if (error) { + g_dbus_method_invocation_take_error (context, error); + return; + } + + if (needed) { + /* Push back the quit timer so the VPN plugin doesn't quit in the + * middle of asking the user for secrets. + */ + schedule_quit_timer (plugin); + + g_assert (setting_name); + g_dbus_method_invocation_return_value (context, + g_variant_new ("(s)", setting_name)); + } else { + /* No secrets required */ + g_dbus_method_invocation_return_value (context, + g_variant_new ("(s)", "")); + } +} + +static void +impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *properties, + gpointer user_data) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMConnection *connection; + GError *error = NULL; + gboolean success; + + if (priv->state != NM_VPN_SERVICE_STATE_STARTING) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_WRONG_STATE, + "Could not accept new secrets: wrong plugin state %d", + priv->state); + return; + } + + connection = nm_simple_connection_new_from_dbus (properties, &error); + if (!connection) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + "Invalid connection: (%d) %s", + error->code, error->message); + g_clear_error (&error); + return; + } + + if (!NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->new_secrets) { + g_dbus_method_invocation_return_error (context, + NM_VPN_PLUGIN_ERROR, + NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED, + "Could not accept new secrets: plugin cannot process interactive secrets"); + g_object_unref (connection); + return; + } + + success = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->new_secrets (plugin, connection, &error); + if (success) { + g_dbus_method_invocation_return_value (context, NULL); + + /* Add a timer to make sure we do not wait indefinitely for the successful connect. */ + connect_timer_start (plugin); + } else { + g_dbus_method_invocation_take_error (context, error); + + /* Stop the plugin from and idle handler so that the NewSecrets + * method return gets sent before the STOP StateChanged signal. + */ + schedule_fail_stop (plugin); + } + + g_object_unref (connection); +} + +/** + * nm_vpn_plugin_old_secrets_required: + * @plugin: the #NMVpnPluginOld + * @message: an information message about why secrets are required, if any + * @hints: VPN specific secret names for required new secrets + * + * Called by VPN plugin implementations to signal to NetworkManager that secrets + * are required during the connection process. This signal may be used to + * request new secrets when the secrets originally provided by NetworkManager + * are insufficient, or the VPN process indicates that it needs additional + * information to complete the request. + */ +void +nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, + const char *message, + const char **hints) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + /* Plugin must be able to accept the new secrets if it calls this method */ + g_return_if_fail (NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->new_secrets); + + /* Plugin cannot call this method if NetworkManager didn't originally call + * ConnectInteractive(). + */ + g_return_if_fail (priv->interactive == TRUE); + + /* Cancel the connect timer since secrets might take a while. It'll + * get restarted when the secrets come back via NewSecrets(). + */ + nm_clear_g_source (&priv->connect_timer); + + g_signal_emit (plugin, signals[SECRETS_REQUIRED], 0, message, hints); +} + +/***************************************************************/ + +#define DATA_KEY_TAG "DATA_KEY=" +#define DATA_VAL_TAG "DATA_VAL=" +#define SECRET_KEY_TAG "SECRET_KEY=" +#define SECRET_VAL_TAG "SECRET_VAL=" + +static void +free_secret (gpointer data) +{ + char *secret = data; + + memset (secret, 0, strlen (secret)); + g_free (secret); +} + +/** + * nm_vpn_plugin_old_read_vpn_details: + * @fd: file descriptor to read from, usually stdin (0) + * @out_data: (out) (transfer full): on successful return, a hash table + * (mapping char*:char*) containing the key/value pairs of VPN data items + * @out_secrets: (out) (transfer full): on successful return, a hash table + * (mapping char*:char*) containing the key/value pairsof VPN secrets + * + * Parses key/value pairs from a file descriptor (normally stdin) passed by + * an applet when the applet calls the authentication dialog of the VPN plugin. + * + * Returns: %TRUE if reading values was successful, %FALSE if not + **/ +gboolean +nm_vpn_plugin_old_read_vpn_details (int fd, + GHashTable **out_data, + GHashTable **out_secrets) +{ + GHashTable *data, *secrets; + gboolean success = FALSE; + char *key = NULL, *val = NULL; + GString *line; + gchar c; + + if (out_data) + g_return_val_if_fail (*out_data == NULL, FALSE); + if (out_secrets) + g_return_val_if_fail (*out_secrets == NULL, FALSE); + + data = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + secrets = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, free_secret); + + line = g_string_new (NULL); + + /* Read stdin for data and secret items until we get a DONE */ + while (1) { + ssize_t nr; + GHashTable *hash = NULL; + + errno = 0; + nr = read (fd, &c, 1); + if (nr == -1) { + if (errno == EAGAIN) { + g_usleep (100); + continue; + } + break; + } + + if (c != '\n') { + g_string_append_c (line, c); + continue; + } + + /* Check for the finish marker */ + if (strcmp (line->str, "DONE") == 0) + break; + + /* Otherwise it's a data/secret item */ + if (strncmp (line->str, DATA_KEY_TAG, strlen (DATA_KEY_TAG)) == 0) { + hash = data; + key = g_strdup (line->str + strlen (DATA_KEY_TAG)); + } else if (strncmp (line->str, DATA_VAL_TAG, strlen (DATA_VAL_TAG)) == 0) { + hash = data; + val = g_strdup (line->str + strlen (DATA_VAL_TAG)); + } else if (strncmp (line->str, SECRET_KEY_TAG, strlen (SECRET_KEY_TAG)) == 0) { + hash = secrets; + key = g_strdup (line->str + strlen (SECRET_KEY_TAG)); + } else if (strncmp (line->str, SECRET_VAL_TAG, strlen (SECRET_VAL_TAG)) == 0) { + hash = secrets; + val = g_strdup (line->str + strlen (SECRET_VAL_TAG)); + } + g_string_truncate (line, 0); + + if (key && val && hash) { + g_hash_table_insert (hash, key, val); + key = NULL; + val = NULL; + success = TRUE; /* Got at least one value */ + } + } + + if (success) { + if (out_data) + *out_data = data; + else + g_hash_table_destroy (data); + + if (out_secrets) + *out_secrets = secrets; + else + g_hash_table_destroy (secrets); + } else { + g_hash_table_destroy (data); + g_hash_table_destroy (secrets); + } + + g_string_free (line, TRUE); + return success; +} + +/** + * nm_vpn_plugin_old_get_secret_flags: + * @data: hash table containing VPN key/value pair data items + * @secret_name: VPN secret key name for which to retrieve flags for + * @out_flags: (out): on success, the flags associated with @secret_name + * + * Given a VPN secret key name, attempts to find the corresponding flags data + * item in @data. If found, converts the flags data item to + * #NMSettingSecretFlags and returns it. + * + * Returns: %TRUE if the flag data item was found and successfully converted + * to flags, %FALSE if not + **/ +gboolean +nm_vpn_plugin_old_get_secret_flags (GHashTable *data, + const char *secret_name, + NMSettingSecretFlags *out_flags) +{ + char *flag_name; + const char *val; + unsigned long tmp; + gboolean success = FALSE; + + g_return_val_if_fail (data != NULL, FALSE); + g_return_val_if_fail (secret_name != NULL, FALSE); + g_return_val_if_fail (out_flags != NULL, FALSE); + g_return_val_if_fail (*out_flags == NM_SETTING_SECRET_FLAG_NONE, FALSE); + + flag_name = g_strdup_printf ("%s-flags", secret_name); + + /* Try new flags value first */ + val = g_hash_table_lookup (data, flag_name); + if (val) { + errno = 0; + tmp = strtoul (val, NULL, 10); + if (errno == 0 && tmp <= NM_SETTING_SECRET_FLAGS_ALL) { + *out_flags = (NMSettingSecretFlags) tmp; + success = TRUE; + } + } + + g_free (flag_name); + return success; +} + +/***************************************************************/ + +static void +impl_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + gpointer user_data) +{ + GError *error = NULL; + + if (nm_vpn_plugin_old_disconnect (plugin, &error)) + g_dbus_method_invocation_return_value (context, NULL); + else + g_dbus_method_invocation_take_error (context, error); +} + +static void +impl_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *config, + gpointer user_data) +{ + nm_vpn_plugin_old_set_config (plugin, config); + g_dbus_method_invocation_return_value (context, NULL); +} + +static void +impl_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *config, + gpointer user_data) +{ + nm_vpn_plugin_old_set_ip4_config (plugin, config); + g_dbus_method_invocation_return_value (context, NULL); +} + +static void +impl_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + GVariant *config, + gpointer user_data) +{ + nm_vpn_plugin_old_set_ip6_config (plugin, config); + g_dbus_method_invocation_return_value (context, NULL); +} + +static void +impl_vpn_plugin_old_set_failure (NMVpnPluginOld *plugin, + GDBusMethodInvocation *context, + char *reason, + gpointer user_data) +{ + nm_vpn_plugin_old_failure (plugin, NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG); + g_dbus_method_invocation_return_value (context, NULL); +} + +/*********************************************************************/ + +static void +sigterm_handler (int signum) +{ + g_slist_foreach (active_plugins, (GFunc) nm_vpn_plugin_old_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, + GObject *object) +{ + active_plugins = g_slist_remove (active_plugins, object); +} + +static void +nm_vpn_plugin_old_init (NMVpnPluginOld *plugin) +{ + active_plugins = g_slist_append (active_plugins, plugin); + g_object_weak_ref (G_OBJECT (plugin), + one_plugin_destroyed, + NULL); +} + +static gboolean +init_sync (GInitable *initable, GCancellable *cancellable, GError **error) +{ + NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (initable); + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + GDBusConnection *connection = NULL; + GDBusProxy *proxy; + GVariant *ret; + gboolean success = FALSE; + + if (!priv->dbus_service_name) { + g_set_error_literal (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS, + _("No service name specified")); + return FALSE; + } + + connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, error); + if (!connection) + return FALSE; + + proxy = g_dbus_proxy_new_sync (connection, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + NULL, + DBUS_SERVICE_DBUS, + DBUS_PATH_DBUS, + DBUS_INTERFACE_DBUS, + cancellable, error); + if (!proxy) + goto out; + + ret = g_dbus_proxy_call_sync (proxy, + "RequestName", + g_variant_new ("(su)", priv->dbus_service_name, 0), + G_DBUS_CALL_FLAGS_NONE, -1, + cancellable, error); + g_object_unref (proxy); + if (!ret) { + if (error && *error) + g_dbus_error_strip_remote_error (*error); + goto out; + } + g_variant_unref (ret); + + priv->dbus_vpn_plugin_old = nmdbus_vpn_plugin_skeleton_new (); + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_vpn_plugin_old), + connection, + NM_VPN_DBUS_PLUGIN_PATH, + error)) + goto out; + + _nm_dbus_bind_properties (plugin, priv->dbus_vpn_plugin_old); + _nm_dbus_bind_methods (plugin, priv->dbus_vpn_plugin_old, + "Connect", impl_vpn_plugin_old_connect, + "ConnectInteractive", impl_vpn_plugin_old_connect_interactive, + "NeedSecrets", impl_vpn_plugin_old_need_secrets, + "NewSecrets", impl_vpn_plugin_old_new_secrets, + "Disconnect", impl_vpn_plugin_old_disconnect, + "SetConfig", impl_vpn_plugin_old_set_config, + "SetIp4Config", impl_vpn_plugin_old_set_ip4_config, + "SetIp6Config", impl_vpn_plugin_old_set_ip6_config, + "SetFailure", impl_vpn_plugin_old_set_failure, + NULL); + + nm_vpn_plugin_old_set_connection (plugin, connection); + nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_INIT); + + success = TRUE; + + out: + g_clear_object (&connection); + + return success; +} + +static void +set_property (GObject *object, guint prop_id, + const GValue *value, GParamSpec *pspec) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (object); + + switch (prop_id) { + case PROP_DBUS_SERVICE_NAME: + /* Construct-only */ + priv->dbus_service_name = g_value_dup_string (value); + break; + case PROP_STATE: + nm_vpn_plugin_old_set_state (NM_VPN_PLUGIN_OLD (object), + (NMVpnServiceState) g_value_get_enum (value)); + 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) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_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_enum (value, nm_vpn_plugin_old_get_state (NM_VPN_PLUGIN_OLD (object))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +dispose (GObject *object) +{ + NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (object); + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServiceState state; + GError *err = NULL; + + nm_clear_g_source (&priv->fail_stop_id); + nm_clear_g_source (&priv->quit_timer); + nm_clear_g_source (&priv->connect_timer); + + state = nm_vpn_plugin_old_get_state (plugin); + + if (state == NM_VPN_SERVICE_STATE_STARTED || + state == NM_VPN_SERVICE_STATE_STARTING) + nm_vpn_plugin_old_disconnect (plugin, &err); + + if (err) { + g_warning ("Error disconnecting VPN connection: %s", err->message); + g_error_free (err); + } + + G_OBJECT_CLASS (nm_vpn_plugin_old_parent_class)->dispose (object); +} + +static void +finalize (GObject *object) +{ + NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (object); + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + nm_vpn_plugin_old_set_connection (plugin, NULL); + g_free (priv->dbus_service_name); + + g_clear_pointer (&priv->banner, g_variant_unref); + g_clear_pointer (&priv->tundev, g_variant_unref); + g_clear_pointer (&priv->gateway, g_variant_unref); + g_clear_pointer (&priv->mtu, g_variant_unref); + + G_OBJECT_CLASS (nm_vpn_plugin_old_parent_class)->finalize (object); +} + +static void +state_changed (NMVpnPluginOld *plugin, NMVpnServiceState state) +{ + NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + + switch (state) { + case NM_VPN_SERVICE_STATE_STARTING: + nm_clear_g_source (&priv->quit_timer); + nm_clear_g_source (&priv->fail_stop_id); + break; + case NM_VPN_SERVICE_STATE_STOPPED: + schedule_quit_timer (plugin); + break; + default: + /* Clean up all timers we might have set up. */ + nm_clear_g_source (&priv->connect_timer); + nm_clear_g_source (&priv->quit_timer); + nm_clear_g_source (&priv->fail_stop_id); + break; + } +} + +static void +nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (plugin_class); + + g_type_class_add_private (object_class, sizeof (NMVpnPluginOldPrivate)); + + /* virtual methods */ + 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 */ + + /** + * NMVpnPluginOld:service-name: + * + * The D-Bus service name of this plugin. + */ + g_object_class_install_property + (object_class, PROP_DBUS_SERVICE_NAME, + g_param_spec_string (NM_VPN_PLUGIN_OLD_DBUS_SERVICE_NAME, "", "", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + /** + * NMVpnPluginOld:state: + * + * The state of the plugin. + */ + g_object_class_install_property + (object_class, PROP_STATE, + g_param_spec_enum (NM_VPN_PLUGIN_OLD_STATE, "", "", + NM_TYPE_VPN_SERVICE_STATE, + NM_VPN_SERVICE_STATE_INIT, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + + /* signals */ + signals[STATE_CHANGED] = + g_signal_new ("state-changed", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, state_changed), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_UINT); + + signals[SECRETS_REQUIRED] = + g_signal_new ("secrets-required", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + NULL, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRV); + + signals[CONFIG] = + g_signal_new ("config", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, config), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_VARIANT); + + signals[IP4_CONFIG] = + g_signal_new ("ip4-config", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, ip4_config), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_VARIANT); + + signals[IP6_CONFIG] = + g_signal_new ("ip6-config", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, ip6_config), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_VARIANT); + + signals[LOGIN_BANNER] = + g_signal_new ("login-banner", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, login_banner), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_STRING); + + signals[FAILURE] = + g_signal_new ("failure", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, failure), + NULL, NULL, + NULL, + G_TYPE_NONE, 1, + G_TYPE_UINT); + + signals[QUIT] = + g_signal_new ("quit", + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMVpnPluginOldClass, quit), + NULL, NULL, + NULL, + G_TYPE_NONE, 0, + G_TYPE_NONE); + + setup_unix_signal_handler (); +} + +static void +nm_vpn_plugin_old_initable_iface_init (GInitableIface *iface) +{ + iface->init = init_sync; +} diff --git a/libnm/nm-vpn-service-plugin.h b/libnm/nm-vpn-service-plugin.h new file mode 100644 index 0000000000..af8f4ff61b --- /dev/null +++ b/libnm/nm-vpn-service-plugin.h @@ -0,0 +1,136 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* + * 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 2007 - 2008 Novell, Inc. + * Copyright 2007 - 2013 Red Hat, Inc. + */ + +#ifndef __NM_VPN_PLUGIN_OLD_H__ +#define __NM_VPN_PLUGIN_OLD_H__ + +#include +#include +#include + +G_BEGIN_DECLS + +#define NM_TYPE_VPN_PLUGIN_OLD (nm_vpn_plugin_old_get_type ()) +#define NM_VPN_PLUGIN_OLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOld)) +#define NM_VPN_PLUGIN_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldClass)) +#define NM_IS_VPN_PLUGIN_OLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_PLUGIN_OLD)) +#define NM_IS_VPN_PLUGIN_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_PLUGIN_OLD)) +#define NM_VPN_PLUGIN_OLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldClass)) + +#define NM_VPN_PLUGIN_OLD_DBUS_SERVICE_NAME "service-name" +#define NM_VPN_PLUGIN_OLD_STATE "state" + +typedef struct { + GObject parent; +} NMVpnPluginOld; + +typedef struct { + GObjectClass parent; + + /* Signals */ + void (*state_changed) (NMVpnPluginOld *plugin, + NMVpnServiceState state); + + void (*ip4_config) (NMVpnPluginOld *plugin, + GVariant *ip4_config); + + void (*login_banner) (NMVpnPluginOld *plugin, + const char *banner); + + void (*failure) (NMVpnPluginOld *plugin, + NMVpnPluginFailure reason); + + void (*quit) (NMVpnPluginOld *plugin); + + void (*config) (NMVpnPluginOld *plugin, + GVariant *config); + + void (*ip6_config) (NMVpnPluginOld *plugin, + GVariant *config); + + /* virtual methods */ + gboolean (*connect) (NMVpnPluginOld *plugin, + NMConnection *connection, + GError **err); + + gboolean (*need_secrets) (NMVpnPluginOld *plugin, + NMConnection *connection, + const char **setting_name, + GError **error); + + gboolean (*disconnect) (NMVpnPluginOld *plugin, + GError **err); + + gboolean (*new_secrets) (NMVpnPluginOld *plugin, + NMConnection *connection, + GError **error); + + gboolean (*connect_interactive) (NMVpnPluginOld *plugin, + NMConnection *connection, + GVariant *details, + GError **error); + + /*< private >*/ + gpointer padding[8]; +} NMVpnPluginOldClass; + +GType nm_vpn_plugin_old_get_type (void); + +GDBusConnection *nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin); +NMVpnServiceState nm_vpn_plugin_old_get_state (NMVpnPluginOld *plugin); +void nm_vpn_plugin_old_set_state (NMVpnPluginOld *plugin, + NMVpnServiceState state); + +void nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, + const char *message, + const char **hints); + +void nm_vpn_plugin_old_set_login_banner (NMVpnPluginOld *plugin, + const char *banner); + +void nm_vpn_plugin_old_failure (NMVpnPluginOld *plugin, + NMVpnPluginFailure reason); + +void nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, + GVariant *config); + +void nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, + GVariant *ip4_config); + +void nm_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, + GVariant *ip6_config); + +gboolean nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, + GError **err); + +/* Utility functions */ + +gboolean nm_vpn_plugin_old_read_vpn_details (int fd, + GHashTable **out_data, + GHashTable **out_secrets); + +gboolean nm_vpn_plugin_old_get_secret_flags (GHashTable *data, + const char *secret_name, + NMSettingSecretFlags *out_flags); + +G_END_DECLS + +#endif /* __NM_VPN_PLUGIN_OLD_H__ */ From 867227dd4aac8371b3cacc366b32a3fa96eba42a Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 2 Jun 2015 10:50:29 +0200 Subject: [PATCH 12/14] libnm/vpn: add new NMVpnServicePlugin class After copying "nm-vpn-plugin-old.*" to "nm-vpn-service-plugin.*", rename the class and add it to the Makefile. This will become the new VPN Service API for libnm 1.2. No changes done yet except renaming of the classes and functions. Rename the previous classes NMVpnPlugin(Old) to NMVpnServicePlugin to have a distinct name from NMVpnEditorPlugin. Buth are plugins, but with a different use. https://bugzilla.gnome.org/show_bug.cgi?id=749951 --- docs/libnm/Makefile.am | 1 + libnm/Makefile.am | 4 +- libnm/libnm.ver | 22 +- libnm/nm-vpn-service-plugin.c | 371 +++++++++++++++++----------------- libnm/nm-vpn-service-plugin.h | 104 +++++----- po/POTFILES.in | 1 + 6 files changed, 252 insertions(+), 251 deletions(-) diff --git a/docs/libnm/Makefile.am b/docs/libnm/Makefile.am index 2525856d5f..23631ddc24 100644 --- a/docs/libnm/Makefile.am +++ b/docs/libnm/Makefile.am @@ -54,6 +54,7 @@ IGNORE_HFILES= \ nm-types.h \ nm-utils-private.h \ nm-vpn-plugin-old.h \ + nm-vpn-service-plugin.h \ nm-core-tests-enum-types.h # Images to copy into HTML directory. diff --git a/libnm/Makefile.am b/libnm/Makefile.am index f6357dad1e..0a41ab5752 100644 --- a/libnm/Makefile.am +++ b/libnm/Makefile.am @@ -55,7 +55,8 @@ libnminclude_hfiles = \ libnminclude_nointrospect_hfiles = \ nm-secret-agent-old.h \ - nm-vpn-plugin-old.h + nm-vpn-plugin-old.h \ + nm-vpn-service-plugin.h libnminclude_HEADERS = \ $(libnminclude_hfiles) \ @@ -109,6 +110,7 @@ libnm_la_csources = \ nm-vpn-connection.c \ nm-vpn-plugin-old.c \ nm-vpn-editor.c \ + nm-vpn-service-plugin.c \ nm-wimax-nsp.c libnm_la_SOURCES = \ diff --git a/libnm/libnm.ver b/libnm/libnm.ver index ce94276533..6e1eda21b9 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -821,17 +821,6 @@ global: nm_vpn_plugin_error_get_type; nm_vpn_plugin_error_quark; nm_vpn_plugin_failure_get_type; - nm_vpn_plugin_old_disconnect; - nm_vpn_plugin_old_failure; - nm_vpn_plugin_old_get_connection; - nm_vpn_plugin_old_get_secret_flags; - nm_vpn_plugin_old_get_state; - nm_vpn_plugin_old_get_type; - nm_vpn_plugin_old_read_vpn_details; - nm_vpn_plugin_old_secrets_required; - nm_vpn_plugin_old_set_ip4_config; - nm_vpn_plugin_old_set_login_banner; - nm_vpn_plugin_old_set_state; nm_vpn_service_state_get_type; nm_wep_key_type_get_type; nm_wimax_nsp_connection_valid; @@ -902,4 +891,15 @@ global: nm_vpn_plugin_info_list_find_by_service; nm_vpn_plugin_info_list_load; nm_vpn_plugin_info_list_remove; + nm_vpn_service_plugin_disconnect; + nm_vpn_service_plugin_failure; + nm_vpn_service_plugin_get_connection; + nm_vpn_service_plugin_get_secret_flags; + nm_vpn_service_plugin_get_state; + nm_vpn_service_plugin_get_type; + nm_vpn_service_plugin_read_vpn_details; + nm_vpn_service_plugin_secrets_required; + nm_vpn_service_plugin_set_ip4_config; + nm_vpn_service_plugin_set_login_banner; + nm_vpn_service_plugin_set_state; } libnm_1_0_0; diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 9f3bc058c4..969b5f0ea3 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -16,15 +16,13 @@ * Boston, MA 02110-1301 USA. * * Copyright 2007 - 2008 Novell, Inc. - * Copyright 2007 - 2008 Red Hat, Inc. - */ - -/* This interface is expected to be deprecated in NM 1.2, at which point there - * will be a new "NMVpnPlugin" class to replace it. + * Copyright 2007 - 2015 Red Hat, Inc. */ #include "config.h" +#include "nm-vpn-service-plugin.h" + #include #include #include @@ -32,7 +30,6 @@ #include #include "nm-glib.h" -#include "nm-vpn-plugin-old.h" #include "nm-enum-types.h" #include "nm-utils.h" #include "nm-connection.h" @@ -43,12 +40,12 @@ #include "nmdbus-vpn-plugin.h" -#define NM_VPN_PLUGIN_OLD_QUIT_TIMER 20 +#define NM_VPN_SERVICE_PLUGIN_QUIT_TIMER 20 -static void nm_vpn_plugin_old_initable_iface_init (GInitableIface *iface); +static void nm_vpn_service_plugin_initable_iface_init (GInitableIface *iface); -G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMVpnPluginOld, nm_vpn_plugin_old, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_vpn_plugin_old_initable_iface_init); +G_DEFINE_ABSTRACT_TYPE_WITH_CODE (NMVpnServicePlugin, nm_vpn_service_plugin, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE, nm_vpn_service_plugin_initable_iface_init); ) typedef struct { @@ -56,7 +53,7 @@ typedef struct { /* DBUS-y stuff */ GDBusConnection *connection; - NMDBusVpnPlugin *dbus_vpn_plugin_old; + NMDBusVpnPlugin *dbus_vpn_service_plugin; char *dbus_service_name; /* Temporary stuff */ @@ -71,9 +68,9 @@ typedef struct { /* Config stuff copied from config to ip4config */ GVariant *banner, *tundev, *gateway, *mtu; -} NMVpnPluginOldPrivate; +} NMVpnServicePluginPrivate; -#define NM_VPN_PLUGIN_OLD_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldPrivate)) +#define NM_VPN_SERVICE_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_VPN_SERVICE_PLUGIN, NMVpnServicePluginPrivate)) enum { STATE_CHANGED, @@ -102,10 +99,10 @@ static GSList *active_plugins = NULL; static void -nm_vpn_plugin_old_set_connection (NMVpnPluginOld *plugin, - GDBusConnection *connection) +nm_vpn_service_plugin_set_connection (NMVpnServicePlugin *plugin, + GDBusConnection *connection) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); g_clear_object (&priv->connection); @@ -114,18 +111,18 @@ nm_vpn_plugin_old_set_connection (NMVpnPluginOld *plugin, } /** - * nm_vpn_plugin_old_get_connection: + * nm_vpn_service_plugin_get_connection: * * Returns: (transfer full): */ GDBusConnection * -nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin) +nm_vpn_service_plugin_get_connection (NMVpnServicePlugin *plugin) { GDBusConnection *connection; - g_return_val_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin), NULL); + g_return_val_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin), NULL); - connection = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin)->connection; + connection = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin)->connection; if (connection) g_object_ref (connection); @@ -134,22 +131,22 @@ nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin) } NMVpnServiceState -nm_vpn_plugin_old_get_state (NMVpnPluginOld *plugin) +nm_vpn_service_plugin_get_state (NMVpnServicePlugin *plugin) { - g_return_val_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin), NM_VPN_SERVICE_STATE_UNKNOWN); + g_return_val_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin), NM_VPN_SERVICE_STATE_UNKNOWN); - return NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin)->state; + return NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin)->state; } void -nm_vpn_plugin_old_set_state (NMVpnPluginOld *plugin, - NMVpnServiceState state) +nm_vpn_service_plugin_set_state (NMVpnServicePlugin *plugin, + NMVpnServiceState state) { - NMVpnPluginOldPrivate *priv; + NMVpnServicePluginPrivate *priv; - g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin)); - priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); if (priv->state != state) { priv->state = state; g_signal_emit (plugin, signals[STATE_CHANGED], 0, state); @@ -157,33 +154,33 @@ nm_vpn_plugin_old_set_state (NMVpnPluginOld *plugin, } void -nm_vpn_plugin_old_set_login_banner (NMVpnPluginOld *plugin, - const char *banner) +nm_vpn_service_plugin_set_login_banner (NMVpnServicePlugin *plugin, + const char *banner) { - g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin)); g_return_if_fail (banner != NULL); g_signal_emit (plugin, signals[LOGIN_BANNER], 0, banner); } void -nm_vpn_plugin_old_failure (NMVpnPluginOld *plugin, - NMVpnPluginFailure reason) +nm_vpn_service_plugin_failure (NMVpnServicePlugin *plugin, + NMVpnPluginFailure reason) { - g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin)); g_signal_emit (plugin, signals[FAILURE], 0, reason); } gboolean -nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, GError **err) +nm_vpn_service_plugin_disconnect (NMVpnServicePlugin *plugin, GError **err) { gboolean ret = FALSE; NMVpnServiceState state; - g_return_val_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin), FALSE); + g_return_val_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin), FALSE); - state = nm_vpn_plugin_old_get_state (plugin); + state = nm_vpn_service_plugin_get_state (plugin); switch (state) { case NM_VPN_SERVICE_STATE_STOPPING: g_set_error (err, @@ -201,9 +198,9 @@ nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, GError **err) break; case NM_VPN_SERVICE_STATE_STARTING: case NM_VPN_SERVICE_STATE_STARTED: - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPING); - ret = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->disconnect (plugin, err); - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPED); + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPING); + ret = NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->disconnect (plugin, err); + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STOPPED); break; case NM_VPN_SERVICE_STATE_INIT: ret = TRUE; @@ -219,7 +216,7 @@ nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, GError **err) } static void -nm_vpn_plugin_old_emit_quit (NMVpnPluginOld *plugin) +nm_vpn_service_plugin_emit_quit (NMVpnServicePlugin *plugin) { g_signal_emit (plugin, signals[QUIT], 0); } @@ -227,12 +224,12 @@ nm_vpn_plugin_old_emit_quit (NMVpnPluginOld *plugin) static gboolean connect_timer_expired (gpointer data) { - NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (data); + NMVpnServicePlugin *plugin = NM_VPN_SERVICE_PLUGIN (data); GError *err = NULL; - NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin)->connect_timer = 0; + NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin)->connect_timer = 0; g_message ("Connect timer expired, disconnecting."); - nm_vpn_plugin_old_disconnect (plugin, &err); + nm_vpn_service_plugin_disconnect (plugin, &err); if (err) { g_warning ("Disconnect failed: %s", err->message); g_error_free (err); @@ -244,20 +241,20 @@ connect_timer_expired (gpointer data) static gboolean quit_timer_expired (gpointer data) { - NMVpnPluginOld *self = NM_VPN_PLUGIN_OLD (data); + NMVpnServicePlugin *self = NM_VPN_SERVICE_PLUGIN (data); - NM_VPN_PLUGIN_OLD_GET_PRIVATE (self)->quit_timer = 0; - nm_vpn_plugin_old_emit_quit (self); + NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (self)->quit_timer = 0; + nm_vpn_service_plugin_emit_quit (self); return G_SOURCE_REMOVE; } static void -schedule_quit_timer (NMVpnPluginOld *self) +schedule_quit_timer (NMVpnServicePlugin *self) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (self); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (self); nm_clear_g_source (&priv->quit_timer); - priv->quit_timer = g_timeout_add_seconds (NM_VPN_PLUGIN_OLD_QUIT_TIMER, + priv->quit_timer = g_timeout_add_seconds (NM_VPN_SERVICE_PLUGIN_QUIT_TIMER, quit_timer_expired, self); } @@ -265,29 +262,29 @@ schedule_quit_timer (NMVpnPluginOld *self) static gboolean fail_stop (gpointer data) { - NMVpnPluginOld *self = NM_VPN_PLUGIN_OLD (data); + NMVpnServicePlugin *self = NM_VPN_SERVICE_PLUGIN (data); - NM_VPN_PLUGIN_OLD_GET_PRIVATE (self)->fail_stop_id = 0; - nm_vpn_plugin_old_set_state (self, NM_VPN_SERVICE_STATE_STOPPED); + NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (self)->fail_stop_id = 0; + nm_vpn_service_plugin_set_state (self, NM_VPN_SERVICE_STATE_STOPPED); return G_SOURCE_REMOVE; } static void -schedule_fail_stop (NMVpnPluginOld *plugin) +schedule_fail_stop (NMVpnServicePlugin *plugin) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); nm_clear_g_source (&priv->fail_stop_id); priv->fail_stop_id = g_idle_add (fail_stop, plugin); } void -nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, - GVariant *config) +nm_vpn_service_plugin_set_config (NMVpnServicePlugin *plugin, + GVariant *config) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); - g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin)); g_return_if_fail (config != NULL); priv->got_config = TRUE; @@ -321,23 +318,23 @@ nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, } void -nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, - GVariant *ip4_config) +nm_vpn_service_plugin_set_ip4_config (NMVpnServicePlugin *plugin, + GVariant *ip4_config) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); GVariant *combined_config; GVariantBuilder builder; GVariantIter iter; const char *key; GVariant *value; - g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin)); g_return_if_fail (ip4_config != NULL); priv->got_ip4 = TRUE; /* Old plugins won't send the "config" signal and thus can't send - * NM_VPN_PLUGIN_OLD_CONFIG_HAS_IP4 either. But since they don't support IPv6, + * NM_VPN_SERVICE_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. */ @@ -372,16 +369,16 @@ nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, if ( priv->has_ip4 == priv->got_ip4 && priv->has_ip6 == priv->got_ip6) - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); } void -nm_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, - GVariant *ip6_config) +nm_vpn_service_plugin_set_ip6_config (NMVpnServicePlugin *plugin, + GVariant *ip6_config) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); - g_return_if_fail (NM_IS_VPN_PLUGIN_OLD (plugin)); + g_return_if_fail (NM_IS_VPN_SERVICE_PLUGIN (plugin)); g_return_if_fail (ip6_config != NULL); priv->got_ip6 = TRUE; @@ -389,25 +386,25 @@ nm_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, if ( priv->has_ip4 == priv->got_ip4 && priv->has_ip6 == priv->got_ip6) - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTED); } static void -connect_timer_start (NMVpnPluginOld *plugin) +connect_timer_start (NMVpnServicePlugin *plugin) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); priv->connect_timer = g_timeout_add_seconds (60, connect_timer_expired, plugin); } static void -_connect_generic (NMVpnPluginOld *plugin, +_connect_generic (NMVpnServicePlugin *plugin, GDBusMethodInvocation *context, GVariant *properties, GVariant *details) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); - NMVpnPluginOldClass *vpn_class = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); + NMVpnServicePluginClass *vpn_class = NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin); NMConnection *connection; gboolean success = FALSE; GError *error = NULL; @@ -441,7 +438,7 @@ _connect_generic (NMVpnPluginOld *plugin, return; } - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_STARTING); if (details) { priv->interactive = TRUE; @@ -467,20 +464,20 @@ _connect_generic (NMVpnPluginOld *plugin, } static void -impl_vpn_plugin_old_connect (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - GVariant *connection, - gpointer user_data) +impl_vpn_service_plugin_connect (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + GVariant *connection, + gpointer user_data) { _connect_generic (plugin, context, connection, NULL); } static void -impl_vpn_plugin_old_connect_interactive (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - GVariant *connection, - GVariant *details, - gpointer user_data) +impl_vpn_service_plugin_connect_interactive (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + GVariant *connection, + GVariant *details, + gpointer user_data) { _connect_generic (plugin, context, connection, details); } @@ -488,10 +485,10 @@ impl_vpn_plugin_old_connect_interactive (NMVpnPluginOld *plugin, /***************************************************************/ static void -impl_vpn_plugin_old_need_secrets (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - GVariant *properties, - gpointer user_data) +impl_vpn_service_plugin_need_secrets (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + GVariant *properties, + gpointer user_data) { NMConnection *connection; const char *setting_name; @@ -509,13 +506,13 @@ impl_vpn_plugin_old_need_secrets (NMVpnPluginOld *plugin, return; } - if (!NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->need_secrets) { + if (!NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->need_secrets) { g_dbus_method_invocation_return_value (context, g_variant_new ("(s)", "")); return; } - needed = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->need_secrets (plugin, connection, &setting_name, &error); + needed = NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->need_secrets (plugin, connection, &setting_name, &error); if (error) { g_dbus_method_invocation_take_error (context, error); return; @@ -538,12 +535,12 @@ impl_vpn_plugin_old_need_secrets (NMVpnPluginOld *plugin, } static void -impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - GVariant *properties, - gpointer user_data) +impl_vpn_service_plugin_new_secrets (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + GVariant *properties, + gpointer user_data) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); NMConnection *connection; GError *error = NULL; gboolean success; @@ -568,7 +565,7 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, return; } - if (!NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->new_secrets) { + if (!NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->new_secrets) { g_dbus_method_invocation_return_error (context, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED, @@ -577,7 +574,7 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, return; } - success = NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->new_secrets (plugin, connection, &error); + success = NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->new_secrets (plugin, connection, &error); if (success) { g_dbus_method_invocation_return_value (context, NULL); @@ -596,8 +593,8 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, } /** - * nm_vpn_plugin_old_secrets_required: - * @plugin: the #NMVpnPluginOld + * nm_vpn_service_plugin_secrets_required: + * @plugin: the #NMVpnServicePlugin * @message: an information message about why secrets are required, if any * @hints: VPN specific secret names for required new secrets * @@ -608,14 +605,14 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, * information to complete the request. */ void -nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, - const char *message, - const char **hints) +nm_vpn_service_plugin_secrets_required (NMVpnServicePlugin *plugin, + const char *message, + const char **hints) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); /* Plugin must be able to accept the new secrets if it calls this method */ - g_return_if_fail (NM_VPN_PLUGIN_OLD_GET_CLASS (plugin)->new_secrets); + g_return_if_fail (NM_VPN_SERVICE_PLUGIN_GET_CLASS (plugin)->new_secrets); /* Plugin cannot call this method if NetworkManager didn't originally call * ConnectInteractive(). @@ -647,7 +644,7 @@ free_secret (gpointer data) } /** - * nm_vpn_plugin_old_read_vpn_details: + * nm_vpn_service_plugin_read_vpn_details: * @fd: file descriptor to read from, usually stdin (0) * @out_data: (out) (transfer full): on successful return, a hash table * (mapping char*:char*) containing the key/value pairs of VPN data items @@ -660,9 +657,9 @@ free_secret (gpointer data) * Returns: %TRUE if reading values was successful, %FALSE if not **/ gboolean -nm_vpn_plugin_old_read_vpn_details (int fd, - GHashTable **out_data, - GHashTable **out_secrets) +nm_vpn_service_plugin_read_vpn_details (int fd, + GHashTable **out_data, + GHashTable **out_secrets) { GHashTable *data, *secrets; gboolean success = FALSE; @@ -748,7 +745,7 @@ nm_vpn_plugin_old_read_vpn_details (int fd, } /** - * nm_vpn_plugin_old_get_secret_flags: + * nm_vpn_service_plugin_get_secret_flags: * @data: hash table containing VPN key/value pair data items * @secret_name: VPN secret key name for which to retrieve flags for * @out_flags: (out): on success, the flags associated with @secret_name @@ -761,9 +758,9 @@ nm_vpn_plugin_old_read_vpn_details (int fd, * to flags, %FALSE if not **/ gboolean -nm_vpn_plugin_old_get_secret_flags (GHashTable *data, - const char *secret_name, - NMSettingSecretFlags *out_flags) +nm_vpn_service_plugin_get_secret_flags (GHashTable *data, + const char *secret_name, + NMSettingSecretFlags *out_flags) { char *flag_name; const char *val; @@ -795,55 +792,55 @@ nm_vpn_plugin_old_get_secret_flags (GHashTable *data, /***************************************************************/ static void -impl_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - gpointer user_data) +impl_vpn_service_plugin_disconnect (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + gpointer user_data) { GError *error = NULL; - if (nm_vpn_plugin_old_disconnect (plugin, &error)) + if (nm_vpn_service_plugin_disconnect (plugin, &error)) g_dbus_method_invocation_return_value (context, NULL); else g_dbus_method_invocation_take_error (context, error); } static void -impl_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - GVariant *config, - gpointer user_data) -{ - nm_vpn_plugin_old_set_config (plugin, config); - g_dbus_method_invocation_return_value (context, NULL); -} - -static void -impl_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, +impl_vpn_service_plugin_set_config (NMVpnServicePlugin *plugin, GDBusMethodInvocation *context, GVariant *config, gpointer user_data) { - nm_vpn_plugin_old_set_ip4_config (plugin, config); + nm_vpn_service_plugin_set_config (plugin, config); g_dbus_method_invocation_return_value (context, NULL); } static void -impl_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - GVariant *config, - gpointer user_data) +impl_vpn_service_plugin_set_ip4_config (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + GVariant *config, + gpointer user_data) { - nm_vpn_plugin_old_set_ip6_config (plugin, config); + nm_vpn_service_plugin_set_ip4_config (plugin, config); g_dbus_method_invocation_return_value (context, NULL); } static void -impl_vpn_plugin_old_set_failure (NMVpnPluginOld *plugin, - GDBusMethodInvocation *context, - char *reason, - gpointer user_data) +impl_vpn_service_plugin_set_ip6_config (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + GVariant *config, + gpointer user_data) { - nm_vpn_plugin_old_failure (plugin, NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG); + nm_vpn_service_plugin_set_ip6_config (plugin, config); + g_dbus_method_invocation_return_value (context, NULL); +} + +static void +impl_vpn_service_plugin_set_failure (NMVpnServicePlugin *plugin, + GDBusMethodInvocation *context, + char *reason, + gpointer user_data) +{ + nm_vpn_service_plugin_failure (plugin, NM_VPN_PLUGIN_FAILURE_BAD_IP_CONFIG); g_dbus_method_invocation_return_value (context, NULL); } @@ -852,7 +849,7 @@ impl_vpn_plugin_old_set_failure (NMVpnPluginOld *plugin, static void sigterm_handler (int signum) { - g_slist_foreach (active_plugins, (GFunc) nm_vpn_plugin_old_emit_quit, NULL); + g_slist_foreach (active_plugins, (GFunc) nm_vpn_service_plugin_emit_quit, NULL); } static void @@ -879,7 +876,7 @@ one_plugin_destroyed (gpointer data, } static void -nm_vpn_plugin_old_init (NMVpnPluginOld *plugin) +nm_vpn_service_plugin_init (NMVpnServicePlugin *plugin) { active_plugins = g_slist_append (active_plugins, plugin); g_object_weak_ref (G_OBJECT (plugin), @@ -890,8 +887,8 @@ nm_vpn_plugin_old_init (NMVpnPluginOld *plugin) static gboolean init_sync (GInitable *initable, GCancellable *cancellable, GError **error) { - NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (initable); - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePlugin *plugin = NM_VPN_SERVICE_PLUGIN (initable); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); GDBusConnection *connection = NULL; GDBusProxy *proxy; GVariant *ret; @@ -931,28 +928,28 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error) } g_variant_unref (ret); - priv->dbus_vpn_plugin_old = nmdbus_vpn_plugin_skeleton_new (); - if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_vpn_plugin_old), + priv->dbus_vpn_service_plugin = nmdbus_vpn_plugin_skeleton_new (); + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (priv->dbus_vpn_service_plugin), connection, NM_VPN_DBUS_PLUGIN_PATH, error)) goto out; - _nm_dbus_bind_properties (plugin, priv->dbus_vpn_plugin_old); - _nm_dbus_bind_methods (plugin, priv->dbus_vpn_plugin_old, - "Connect", impl_vpn_plugin_old_connect, - "ConnectInteractive", impl_vpn_plugin_old_connect_interactive, - "NeedSecrets", impl_vpn_plugin_old_need_secrets, - "NewSecrets", impl_vpn_plugin_old_new_secrets, - "Disconnect", impl_vpn_plugin_old_disconnect, - "SetConfig", impl_vpn_plugin_old_set_config, - "SetIp4Config", impl_vpn_plugin_old_set_ip4_config, - "SetIp6Config", impl_vpn_plugin_old_set_ip6_config, - "SetFailure", impl_vpn_plugin_old_set_failure, + _nm_dbus_bind_properties (plugin, priv->dbus_vpn_service_plugin); + _nm_dbus_bind_methods (plugin, priv->dbus_vpn_service_plugin, + "Connect", impl_vpn_service_plugin_connect, + "ConnectInteractive", impl_vpn_service_plugin_connect_interactive, + "NeedSecrets", impl_vpn_service_plugin_need_secrets, + "NewSecrets", impl_vpn_service_plugin_new_secrets, + "Disconnect", impl_vpn_service_plugin_disconnect, + "SetConfig", impl_vpn_service_plugin_set_config, + "SetIp4Config", impl_vpn_service_plugin_set_ip4_config, + "SetIp6Config", impl_vpn_service_plugin_set_ip6_config, + "SetFailure", impl_vpn_service_plugin_set_failure, NULL); - nm_vpn_plugin_old_set_connection (plugin, connection); - nm_vpn_plugin_old_set_state (plugin, NM_VPN_SERVICE_STATE_INIT); + nm_vpn_service_plugin_set_connection (plugin, connection); + nm_vpn_service_plugin_set_state (plugin, NM_VPN_SERVICE_STATE_INIT); success = TRUE; @@ -966,7 +963,7 @@ static void set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (object); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (object); switch (prop_id) { case PROP_DBUS_SERVICE_NAME: @@ -974,7 +971,7 @@ set_property (GObject *object, guint prop_id, priv->dbus_service_name = g_value_dup_string (value); break; case PROP_STATE: - nm_vpn_plugin_old_set_state (NM_VPN_PLUGIN_OLD (object), + nm_vpn_service_plugin_set_state (NM_VPN_SERVICE_PLUGIN (object), (NMVpnServiceState) g_value_get_enum (value)); break; default: @@ -987,14 +984,14 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (object); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_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_enum (value, nm_vpn_plugin_old_get_state (NM_VPN_PLUGIN_OLD (object))); + g_value_set_enum (value, nm_vpn_service_plugin_get_state (NM_VPN_SERVICE_PLUGIN (object))); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); @@ -1005,8 +1002,8 @@ get_property (GObject *object, guint prop_id, static void dispose (GObject *object) { - NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (object); - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePlugin *plugin = NM_VPN_SERVICE_PLUGIN (object); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); NMVpnServiceState state; GError *err = NULL; @@ -1014,27 +1011,27 @@ dispose (GObject *object) nm_clear_g_source (&priv->quit_timer); nm_clear_g_source (&priv->connect_timer); - state = nm_vpn_plugin_old_get_state (plugin); + state = nm_vpn_service_plugin_get_state (plugin); if (state == NM_VPN_SERVICE_STATE_STARTED || state == NM_VPN_SERVICE_STATE_STARTING) - nm_vpn_plugin_old_disconnect (plugin, &err); + nm_vpn_service_plugin_disconnect (plugin, &err); if (err) { g_warning ("Error disconnecting VPN connection: %s", err->message); g_error_free (err); } - G_OBJECT_CLASS (nm_vpn_plugin_old_parent_class)->dispose (object); + G_OBJECT_CLASS (nm_vpn_service_plugin_parent_class)->dispose (object); } static void finalize (GObject *object) { - NMVpnPluginOld *plugin = NM_VPN_PLUGIN_OLD (object); - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePlugin *plugin = NM_VPN_SERVICE_PLUGIN (object); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); - nm_vpn_plugin_old_set_connection (plugin, NULL); + nm_vpn_service_plugin_set_connection (plugin, NULL); g_free (priv->dbus_service_name); g_clear_pointer (&priv->banner, g_variant_unref); @@ -1042,13 +1039,13 @@ finalize (GObject *object) g_clear_pointer (&priv->gateway, g_variant_unref); g_clear_pointer (&priv->mtu, g_variant_unref); - G_OBJECT_CLASS (nm_vpn_plugin_old_parent_class)->finalize (object); + G_OBJECT_CLASS (nm_vpn_service_plugin_parent_class)->finalize (object); } static void -state_changed (NMVpnPluginOld *plugin, NMVpnServiceState state) +state_changed (NMVpnServicePlugin *plugin, NMVpnServiceState state) { - NMVpnPluginOldPrivate *priv = NM_VPN_PLUGIN_OLD_GET_PRIVATE (plugin); + NMVpnServicePluginPrivate *priv = NM_VPN_SERVICE_PLUGIN_GET_PRIVATE (plugin); switch (state) { case NM_VPN_SERVICE_STATE_STARTING: @@ -1068,11 +1065,11 @@ state_changed (NMVpnPluginOld *plugin, NMVpnServiceState state) } static void -nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) +nm_vpn_service_plugin_class_init (NMVpnServicePluginClass *plugin_class) { GObjectClass *object_class = G_OBJECT_CLASS (plugin_class); - g_type_class_add_private (object_class, sizeof (NMVpnPluginOldPrivate)); + g_type_class_add_private (object_class, sizeof (NMVpnServicePluginPrivate)); /* virtual methods */ object_class->set_property = set_property; @@ -1085,26 +1082,26 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) /* properties */ /** - * NMVpnPluginOld:service-name: + * NMVpnServicePlugin:service-name: * * The D-Bus service name of this plugin. */ g_object_class_install_property (object_class, PROP_DBUS_SERVICE_NAME, - g_param_spec_string (NM_VPN_PLUGIN_OLD_DBUS_SERVICE_NAME, "", "", + g_param_spec_string (NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME, "", "", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); /** - * NMVpnPluginOld:state: + * NMVpnServicePlugin:state: * * The state of the plugin. */ g_object_class_install_property (object_class, PROP_STATE, - g_param_spec_enum (NM_VPN_PLUGIN_OLD_STATE, "", "", + g_param_spec_enum (NM_VPN_SERVICE_PLUGIN_STATE, "", "", NM_TYPE_VPN_SERVICE_STATE, NM_VPN_SERVICE_STATE_INIT, G_PARAM_READWRITE | @@ -1115,7 +1112,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("state-changed", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, state_changed), + G_STRUCT_OFFSET (NMVpnServicePluginClass, state_changed), NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -1133,7 +1130,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("config", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, config), + G_STRUCT_OFFSET (NMVpnServicePluginClass, config), NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -1143,7 +1140,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("ip4-config", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, ip4_config), + G_STRUCT_OFFSET (NMVpnServicePluginClass, ip4_config), NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -1153,7 +1150,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("ip6-config", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, ip6_config), + G_STRUCT_OFFSET (NMVpnServicePluginClass, ip6_config), NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -1163,7 +1160,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("login-banner", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, login_banner), + G_STRUCT_OFFSET (NMVpnServicePluginClass, login_banner), NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -1173,7 +1170,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("failure", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, failure), + G_STRUCT_OFFSET (NMVpnServicePluginClass, failure), NULL, NULL, NULL, G_TYPE_NONE, 1, @@ -1183,7 +1180,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) g_signal_new ("quit", G_OBJECT_CLASS_TYPE (object_class), G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMVpnPluginOldClass, quit), + G_STRUCT_OFFSET (NMVpnServicePluginClass, quit), NULL, NULL, NULL, G_TYPE_NONE, 0, @@ -1193,7 +1190,7 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) } static void -nm_vpn_plugin_old_initable_iface_init (GInitableIface *iface) +nm_vpn_service_plugin_initable_iface_init (GInitableIface *iface) { iface->init = init_sync; } diff --git a/libnm/nm-vpn-service-plugin.h b/libnm/nm-vpn-service-plugin.h index af8f4ff61b..fca6f7ebfa 100644 --- a/libnm/nm-vpn-service-plugin.h +++ b/libnm/nm-vpn-service-plugin.h @@ -16,11 +16,11 @@ * Boston, MA 02110-1301 USA. * * Copyright 2007 - 2008 Novell, Inc. - * Copyright 2007 - 2013 Red Hat, Inc. + * Copyright 2007 - 2015 Red Hat, Inc. */ -#ifndef __NM_VPN_PLUGIN_OLD_H__ -#define __NM_VPN_PLUGIN_OLD_H__ +#ifndef __NM_VPN_SERVICE_PLUGIN_H__ +#define __NM_VPN_SERVICE_PLUGIN_H__ #include #include @@ -28,109 +28,109 @@ G_BEGIN_DECLS -#define NM_TYPE_VPN_PLUGIN_OLD (nm_vpn_plugin_old_get_type ()) -#define NM_VPN_PLUGIN_OLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOld)) -#define NM_VPN_PLUGIN_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldClass)) -#define NM_IS_VPN_PLUGIN_OLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_PLUGIN_OLD)) -#define NM_IS_VPN_PLUGIN_OLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_PLUGIN_OLD)) -#define NM_VPN_PLUGIN_OLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_PLUGIN_OLD, NMVpnPluginOldClass)) +#define NM_TYPE_VPN_SERVICE_PLUGIN (nm_vpn_service_plugin_get_type ()) +#define NM_VPN_SERVICE_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_SERVICE_PLUGIN, NMVpnServicePlugin)) +#define NM_VPN_SERVICE_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_VPN_SERVICE_PLUGIN, NMVpnServicePluginClass)) +#define NM_IS_VPN_SERVICE_PLUGIN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_VPN_SERVICE_PLUGIN)) +#define NM_IS_VPN_SERVICE_PLUGIN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_VPN_SERVICE_PLUGIN)) +#define NM_VPN_SERVICE_PLUGIN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_VPN_SERVICE_PLUGIN, NMVpnServicePluginClass)) -#define NM_VPN_PLUGIN_OLD_DBUS_SERVICE_NAME "service-name" -#define NM_VPN_PLUGIN_OLD_STATE "state" +#define NM_VPN_SERVICE_PLUGIN_DBUS_SERVICE_NAME "service-name" +#define NM_VPN_SERVICE_PLUGIN_STATE "state" typedef struct { GObject parent; -} NMVpnPluginOld; +} NMVpnServicePlugin; typedef struct { GObjectClass parent; /* Signals */ - void (*state_changed) (NMVpnPluginOld *plugin, + void (*state_changed) (NMVpnServicePlugin *plugin, NMVpnServiceState state); - void (*ip4_config) (NMVpnPluginOld *plugin, + void (*ip4_config) (NMVpnServicePlugin *plugin, GVariant *ip4_config); - void (*login_banner) (NMVpnPluginOld *plugin, + void (*login_banner) (NMVpnServicePlugin *plugin, const char *banner); - void (*failure) (NMVpnPluginOld *plugin, + void (*failure) (NMVpnServicePlugin *plugin, NMVpnPluginFailure reason); - void (*quit) (NMVpnPluginOld *plugin); + void (*quit) (NMVpnServicePlugin *plugin); - void (*config) (NMVpnPluginOld *plugin, + void (*config) (NMVpnServicePlugin *plugin, GVariant *config); - void (*ip6_config) (NMVpnPluginOld *plugin, + void (*ip6_config) (NMVpnServicePlugin *plugin, GVariant *config); /* virtual methods */ - gboolean (*connect) (NMVpnPluginOld *plugin, + gboolean (*connect) (NMVpnServicePlugin *plugin, NMConnection *connection, GError **err); - gboolean (*need_secrets) (NMVpnPluginOld *plugin, + gboolean (*need_secrets) (NMVpnServicePlugin *plugin, NMConnection *connection, const char **setting_name, GError **error); - gboolean (*disconnect) (NMVpnPluginOld *plugin, + gboolean (*disconnect) (NMVpnServicePlugin *plugin, GError **err); - gboolean (*new_secrets) (NMVpnPluginOld *plugin, + gboolean (*new_secrets) (NMVpnServicePlugin *plugin, NMConnection *connection, GError **error); - gboolean (*connect_interactive) (NMVpnPluginOld *plugin, + gboolean (*connect_interactive) (NMVpnServicePlugin *plugin, NMConnection *connection, GVariant *details, GError **error); /*< private >*/ gpointer padding[8]; -} NMVpnPluginOldClass; +} NMVpnServicePluginClass; -GType nm_vpn_plugin_old_get_type (void); +GType nm_vpn_service_plugin_get_type (void); -GDBusConnection *nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin); -NMVpnServiceState nm_vpn_plugin_old_get_state (NMVpnPluginOld *plugin); -void nm_vpn_plugin_old_set_state (NMVpnPluginOld *plugin, - NMVpnServiceState state); +GDBusConnection *nm_vpn_service_plugin_get_connection (NMVpnServicePlugin *plugin); +NMVpnServiceState nm_vpn_service_plugin_get_state (NMVpnServicePlugin *plugin); +void nm_vpn_service_plugin_set_state (NMVpnServicePlugin *plugin, + NMVpnServiceState state); -void nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, - const char *message, - const char **hints); +void nm_vpn_service_plugin_secrets_required (NMVpnServicePlugin *plugin, + const char *message, + const char **hints); -void nm_vpn_plugin_old_set_login_banner (NMVpnPluginOld *plugin, - const char *banner); +void nm_vpn_service_plugin_set_login_banner (NMVpnServicePlugin *plugin, + const char *banner); -void nm_vpn_plugin_old_failure (NMVpnPluginOld *plugin, - NMVpnPluginFailure reason); +void nm_vpn_service_plugin_failure (NMVpnServicePlugin *plugin, + NMVpnPluginFailure reason); -void nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, - GVariant *config); +void nm_vpn_service_plugin_set_config (NMVpnServicePlugin *plugin, + GVariant *config); -void nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, - GVariant *ip4_config); +void nm_vpn_service_plugin_set_ip4_config (NMVpnServicePlugin *plugin, + GVariant *ip4_config); -void nm_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, - GVariant *ip6_config); +void nm_vpn_service_plugin_set_ip6_config (NMVpnServicePlugin *plugin, + GVariant *ip6_config); -gboolean nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, - GError **err); +gboolean nm_vpn_service_plugin_disconnect (NMVpnServicePlugin *plugin, + GError **err); /* Utility functions */ -gboolean nm_vpn_plugin_old_read_vpn_details (int fd, - GHashTable **out_data, - GHashTable **out_secrets); +gboolean nm_vpn_service_plugin_read_vpn_details (int fd, + GHashTable **out_data, + GHashTable **out_secrets); -gboolean nm_vpn_plugin_old_get_secret_flags (GHashTable *data, - const char *secret_name, - NMSettingSecretFlags *out_flags); +gboolean nm_vpn_service_plugin_get_secret_flags (GHashTable *data, + const char *secret_name, + NMSettingSecretFlags *out_flags); G_END_DECLS -#endif /* __NM_VPN_PLUGIN_OLD_H__ */ +#endif /* __NM_VPN_SERVICE_PLUGIN_H__ */ diff --git a/po/POTFILES.in b/po/POTFILES.in index 7b2c37ae94..8bffd707a9 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -129,6 +129,7 @@ libnm/nm-object.c libnm/nm-remote-connection.c libnm/nm-remote-settings.c libnm/nm-vpn-plugin-old.c +libnm/nm-vpn-service-plugin.c policy/org.freedesktop.NetworkManager.policy.in.in src/NetworkManagerUtils.c src/main.c From 6ea0b9efee78a08f5d4cd4ca169d937be30afa14 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 2 Jun 2015 10:56:16 +0200 Subject: [PATCH 13/14] libnm/vpn: deprecated NMVpnPluginOld In hindsight, the NMVpnPluginOld should never have made public for nm-1-0 as there are no users and we don't want to support this API. For now, just deprecate it. --- libnm/nm-vpn-plugin-old.c | 16 ++++++++++++---- libnm/nm-vpn-plugin-old.h | 34 +++++++++++++++++++++++++++++++--- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/libnm/nm-vpn-plugin-old.c b/libnm/nm-vpn-plugin-old.c index 9f3bc058c4..ff7ce834a8 100644 --- a/libnm/nm-vpn-plugin-old.c +++ b/libnm/nm-vpn-plugin-old.c @@ -19,10 +19,6 @@ * Copyright 2007 - 2008 Red Hat, Inc. */ -/* This interface is expected to be deprecated in NM 1.2, at which point there - * will be a new "NMVpnPlugin" class to replace it. - */ - #include "config.h" #include @@ -117,6 +113,8 @@ nm_vpn_plugin_old_set_connection (NMVpnPluginOld *plugin, * nm_vpn_plugin_old_get_connection: * * Returns: (transfer full): + * + * Deprecated: 1.2: replaced by NMVpnServicePlugin */ GDBusConnection * nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin) @@ -606,6 +604,8 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin, * request new secrets when the secrets originally provided by NetworkManager * are insufficient, or the VPN process indicates that it needs additional * information to complete the request. + * + * Deprecated: 1.2: replaced by NMVpnServicePlugin */ void nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, @@ -658,6 +658,8 @@ free_secret (gpointer data) * an applet when the applet calls the authentication dialog of the VPN plugin. * * Returns: %TRUE if reading values was successful, %FALSE if not + * + * Deprecated: 1.2: replaced by NMVpnServicePlugin **/ gboolean nm_vpn_plugin_old_read_vpn_details (int fd, @@ -759,6 +761,8 @@ nm_vpn_plugin_old_read_vpn_details (int fd, * * Returns: %TRUE if the flag data item was found and successfully converted * to flags, %FALSE if not + * + * Deprecated: 1.2: replaced by NMVpnServicePlugin **/ gboolean nm_vpn_plugin_old_get_secret_flags (GHashTable *data, @@ -1088,6 +1092,8 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) * NMVpnPluginOld:service-name: * * The D-Bus service name of this plugin. + * + * Deprecated: 1.2: replaced by NMVpnServicePlugin */ g_object_class_install_property (object_class, PROP_DBUS_SERVICE_NAME, @@ -1101,6 +1107,8 @@ nm_vpn_plugin_old_class_init (NMVpnPluginOldClass *plugin_class) * NMVpnPluginOld:state: * * The state of the plugin. + * + * Deprecated: 1.2: replaced by NMVpnServicePlugin */ g_object_class_install_property (object_class, PROP_STATE, diff --git a/libnm/nm-vpn-plugin-old.h b/libnm/nm-vpn-plugin-old.h index af8f4ff61b..59cf4600c5 100644 --- a/libnm/nm-vpn-plugin-old.h +++ b/libnm/nm-vpn-plugin-old.h @@ -16,7 +16,7 @@ * Boston, MA 02110-1301 USA. * * Copyright 2007 - 2008 Novell, Inc. - * Copyright 2007 - 2013 Red Hat, Inc. + * Copyright 2007 - 2015 Red Hat, Inc. */ #ifndef __NM_VPN_PLUGIN_OLD_H__ @@ -39,94 +39,122 @@ G_BEGIN_DECLS #define NM_VPN_PLUGIN_OLD_STATE "state" typedef struct { + NM_DEPRECATED_IN_1_2 GObject parent; -} NMVpnPluginOld; +} NMVpnPluginOld NM_DEPRECATED_IN_1_2; typedef struct { + NM_DEPRECATED_IN_1_2 GObjectClass parent; /* Signals */ + NM_DEPRECATED_IN_1_2 void (*state_changed) (NMVpnPluginOld *plugin, NMVpnServiceState state); + NM_DEPRECATED_IN_1_2 void (*ip4_config) (NMVpnPluginOld *plugin, GVariant *ip4_config); + NM_DEPRECATED_IN_1_2 void (*login_banner) (NMVpnPluginOld *plugin, const char *banner); + NM_DEPRECATED_IN_1_2 void (*failure) (NMVpnPluginOld *plugin, NMVpnPluginFailure reason); + NM_DEPRECATED_IN_1_2 void (*quit) (NMVpnPluginOld *plugin); + NM_DEPRECATED_IN_1_2 void (*config) (NMVpnPluginOld *plugin, GVariant *config); + NM_DEPRECATED_IN_1_2 void (*ip6_config) (NMVpnPluginOld *plugin, GVariant *config); /* virtual methods */ + NM_DEPRECATED_IN_1_2 gboolean (*connect) (NMVpnPluginOld *plugin, NMConnection *connection, GError **err); + NM_DEPRECATED_IN_1_2 gboolean (*need_secrets) (NMVpnPluginOld *plugin, NMConnection *connection, const char **setting_name, GError **error); + NM_DEPRECATED_IN_1_2 gboolean (*disconnect) (NMVpnPluginOld *plugin, GError **err); + NM_DEPRECATED_IN_1_2 gboolean (*new_secrets) (NMVpnPluginOld *plugin, NMConnection *connection, GError **error); + NM_DEPRECATED_IN_1_2 gboolean (*connect_interactive) (NMVpnPluginOld *plugin, NMConnection *connection, GVariant *details, GError **error); /*< private >*/ + NM_DEPRECATED_IN_1_2 gpointer padding[8]; -} NMVpnPluginOldClass; +} NMVpnPluginOldClass NM_DEPRECATED_IN_1_2; +NM_DEPRECATED_IN_1_2 GType nm_vpn_plugin_old_get_type (void); +NM_DEPRECATED_IN_1_2 GDBusConnection *nm_vpn_plugin_old_get_connection (NMVpnPluginOld *plugin); +NM_DEPRECATED_IN_1_2 NMVpnServiceState nm_vpn_plugin_old_get_state (NMVpnPluginOld *plugin); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_set_state (NMVpnPluginOld *plugin, NMVpnServiceState state); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_secrets_required (NMVpnPluginOld *plugin, const char *message, const char **hints); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_set_login_banner (NMVpnPluginOld *plugin, const char *banner); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_failure (NMVpnPluginOld *plugin, NMVpnPluginFailure reason); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_set_config (NMVpnPluginOld *plugin, GVariant *config); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_set_ip4_config (NMVpnPluginOld *plugin, GVariant *ip4_config); +NM_DEPRECATED_IN_1_2 void nm_vpn_plugin_old_set_ip6_config (NMVpnPluginOld *plugin, GVariant *ip6_config); +NM_DEPRECATED_IN_1_2 gboolean nm_vpn_plugin_old_disconnect (NMVpnPluginOld *plugin, GError **err); /* Utility functions */ +NM_DEPRECATED_IN_1_2 gboolean nm_vpn_plugin_old_read_vpn_details (int fd, GHashTable **out_data, GHashTable **out_secrets); +NM_DEPRECATED_IN_1_2 gboolean nm_vpn_plugin_old_get_secret_flags (GHashTable *data, const char *secret_name, NMSettingSecretFlags *out_flags); From 6be8a1f5495a6fb73f591cb47dd53a00cfda778b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 2 Jun 2015 11:02:49 +0200 Subject: [PATCH 14/14] libnm/vpn: add annotations for new NMVpnServicePlugin API --- libnm/nm-vpn-service-plugin.c | 12 ++++++++++++ libnm/nm-vpn-service-plugin.h | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 42 insertions(+), 2 deletions(-) diff --git a/libnm/nm-vpn-service-plugin.c b/libnm/nm-vpn-service-plugin.c index 969b5f0ea3..1f25be6e82 100644 --- a/libnm/nm-vpn-service-plugin.c +++ b/libnm/nm-vpn-service-plugin.c @@ -114,6 +114,8 @@ nm_vpn_service_plugin_set_connection (NMVpnServicePlugin *plugin, * nm_vpn_service_plugin_get_connection: * * Returns: (transfer full): + * + * Since: 1.2 */ GDBusConnection * nm_vpn_service_plugin_get_connection (NMVpnServicePlugin *plugin) @@ -603,6 +605,8 @@ impl_vpn_service_plugin_new_secrets (NMVpnServicePlugin *plugin, * request new secrets when the secrets originally provided by NetworkManager * are insufficient, or the VPN process indicates that it needs additional * information to complete the request. + * + * Since: 1.2 */ void nm_vpn_service_plugin_secrets_required (NMVpnServicePlugin *plugin, @@ -655,6 +659,8 @@ free_secret (gpointer data) * an applet when the applet calls the authentication dialog of the VPN plugin. * * Returns: %TRUE if reading values was successful, %FALSE if not + * + * Since: 1.2 **/ gboolean nm_vpn_service_plugin_read_vpn_details (int fd, @@ -756,6 +762,8 @@ nm_vpn_service_plugin_read_vpn_details (int fd, * * Returns: %TRUE if the flag data item was found and successfully converted * to flags, %FALSE if not + * + * Since: 1.2 **/ gboolean nm_vpn_service_plugin_get_secret_flags (GHashTable *data, @@ -1085,6 +1093,8 @@ nm_vpn_service_plugin_class_init (NMVpnServicePluginClass *plugin_class) * NMVpnServicePlugin:service-name: * * The D-Bus service name of this plugin. + * + * Since: 1.2 */ g_object_class_install_property (object_class, PROP_DBUS_SERVICE_NAME, @@ -1098,6 +1108,8 @@ nm_vpn_service_plugin_class_init (NMVpnServicePluginClass *plugin_class) * NMVpnServicePlugin:state: * * The state of the plugin. + * + * Since: 1.2 */ g_object_class_install_property (object_class, PROP_STATE, diff --git a/libnm/nm-vpn-service-plugin.h b/libnm/nm-vpn-service-plugin.h index fca6f7ebfa..81ba40457f 100644 --- a/libnm/nm-vpn-service-plugin.h +++ b/libnm/nm-vpn-service-plugin.h @@ -39,94 +39,122 @@ G_BEGIN_DECLS #define NM_VPN_SERVICE_PLUGIN_STATE "state" typedef struct { + NM_AVAILABLE_IN_1_2 GObject parent; -} NMVpnServicePlugin; +} NMVpnServicePlugin NM_AVAILABLE_IN_1_2; typedef struct { + NM_AVAILABLE_IN_1_2 GObjectClass parent; /* Signals */ + NM_AVAILABLE_IN_1_2 void (*state_changed) (NMVpnServicePlugin *plugin, NMVpnServiceState state); + NM_AVAILABLE_IN_1_2 void (*ip4_config) (NMVpnServicePlugin *plugin, GVariant *ip4_config); + NM_AVAILABLE_IN_1_2 void (*login_banner) (NMVpnServicePlugin *plugin, const char *banner); + NM_AVAILABLE_IN_1_2 void (*failure) (NMVpnServicePlugin *plugin, NMVpnPluginFailure reason); + NM_AVAILABLE_IN_1_2 void (*quit) (NMVpnServicePlugin *plugin); + NM_AVAILABLE_IN_1_2 void (*config) (NMVpnServicePlugin *plugin, GVariant *config); + NM_AVAILABLE_IN_1_2 void (*ip6_config) (NMVpnServicePlugin *plugin, GVariant *config); /* virtual methods */ + NM_AVAILABLE_IN_1_2 gboolean (*connect) (NMVpnServicePlugin *plugin, NMConnection *connection, GError **err); + NM_AVAILABLE_IN_1_2 gboolean (*need_secrets) (NMVpnServicePlugin *plugin, NMConnection *connection, const char **setting_name, GError **error); + NM_AVAILABLE_IN_1_2 gboolean (*disconnect) (NMVpnServicePlugin *plugin, GError **err); + NM_AVAILABLE_IN_1_2 gboolean (*new_secrets) (NMVpnServicePlugin *plugin, NMConnection *connection, GError **error); + NM_AVAILABLE_IN_1_2 gboolean (*connect_interactive) (NMVpnServicePlugin *plugin, NMConnection *connection, GVariant *details, GError **error); /*< private >*/ + NM_AVAILABLE_IN_1_2 gpointer padding[8]; -} NMVpnServicePluginClass; +} NMVpnServicePluginClass NM_AVAILABLE_IN_1_2; +NM_AVAILABLE_IN_1_2 GType nm_vpn_service_plugin_get_type (void); +NM_AVAILABLE_IN_1_2 GDBusConnection *nm_vpn_service_plugin_get_connection (NMVpnServicePlugin *plugin); +NM_AVAILABLE_IN_1_2 NMVpnServiceState nm_vpn_service_plugin_get_state (NMVpnServicePlugin *plugin); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_set_state (NMVpnServicePlugin *plugin, NMVpnServiceState state); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_secrets_required (NMVpnServicePlugin *plugin, const char *message, const char **hints); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_set_login_banner (NMVpnServicePlugin *plugin, const char *banner); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_failure (NMVpnServicePlugin *plugin, NMVpnPluginFailure reason); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_set_config (NMVpnServicePlugin *plugin, GVariant *config); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_set_ip4_config (NMVpnServicePlugin *plugin, GVariant *ip4_config); +NM_AVAILABLE_IN_1_2 void nm_vpn_service_plugin_set_ip6_config (NMVpnServicePlugin *plugin, GVariant *ip6_config); +NM_AVAILABLE_IN_1_2 gboolean nm_vpn_service_plugin_disconnect (NMVpnServicePlugin *plugin, GError **err); /* Utility functions */ +NM_AVAILABLE_IN_1_2 gboolean nm_vpn_service_plugin_read_vpn_details (int fd, GHashTable **out_data, GHashTable **out_secrets); +NM_AVAILABLE_IN_1_2 gboolean nm_vpn_service_plugin_get_secret_flags (GHashTable *data, const char *secret_name, NMSettingSecretFlags *out_flags);