summary refs log tree commit diff
path: root/src/contrib
diff options
context:
space:
mode:
Diffstat (limited to 'src/contrib')
-rw-r--r--src/contrib/meson.build5
-rw-r--r--src/contrib/nm-compat.c76
-rw-r--r--src/contrib/nm-compat.h55
-rw-r--r--src/contrib/nm-vpn-editor-plugin-call.h167
-rw-r--r--src/contrib/nm-vpn-plugin-utils.c138
-rw-r--r--src/contrib/nm-vpn-plugin-utils.h25
-rw-r--r--src/contrib/tests/meson.build11
7 files changed, 477 insertions, 0 deletions
diff --git a/src/contrib/meson.build b/src/contrib/meson.build
new file mode 100644
index 00000000..2745087a
--- /dev/null
+++ b/src/contrib/meson.build
@@ -0,0 +1,5 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+nm_vpn_plugin_utils_source = files('nm-vpn-plugin-utils.c')
+
+src_contrib_nm_compat_source = files('nm-compat.c')
diff --git a/src/contrib/nm-compat.c b/src/contrib/nm-compat.c
new file mode 100644
index 00000000..f15c29c9
--- /dev/null
+++ b/src/contrib/nm-compat.c
@@ -0,0 +1,76 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ */
+
+#include "libnm-client-impl/nm-default-libnm.h"
+
+#include "nm-compat.h"
+
+/*****************************************************************************/
+
+static void
+_get_keys_cb(const char *key, const char *val, gpointer user_data)
+{
+    GPtrArray *a = user_data;
+
+    g_ptr_array_add(a, g_strdup(key));
+}
+
+static const char **
+_get_keys(NMSettingVpn *setting, gboolean is_secrets, guint *out_length)
+{
+    guint        len;
+    const char **keys = NULL;
+    GPtrArray *  a;
+
+    nm_assert(NM_IS_SETTING_VPN(setting));
+
+    if (is_secrets)
+        len = nm_setting_vpn_get_num_secrets(setting);
+    else
+        len = nm_setting_vpn_get_num_data_items(setting);
+
+    a = g_ptr_array_sized_new(len + 1);
+
+    if (is_secrets)
+        nm_setting_vpn_foreach_secret(setting, _get_keys_cb, a);
+    else
+        nm_setting_vpn_foreach_data_item(setting, _get_keys_cb, a);
+
+    len = a->len;
+    if (len) {
+        g_ptr_array_sort(a, nm_strcmp_p);
+        g_ptr_array_add(a, NULL);
+        keys = g_malloc(a->len * sizeof(gpointer));
+        memcpy(keys, a->pdata, a->len * sizeof(gpointer));
+
+        /* we need to cache the keys *somewhere*. */
+        g_object_set_qdata_full(G_OBJECT(setting),
+                                is_secrets
+                                    ? NM_CACHED_QUARK("libnm._nm_setting_vpn_get_secret_keys")
+                                    : NM_CACHED_QUARK("libnm._nm_setting_vpn_get_data_keys"),
+                                g_ptr_array_free(a, FALSE),
+                                (GDestroyNotify) g_strfreev);
+    } else
+        g_ptr_array_free(a, TRUE);
+
+    NM_SET_OUT(out_length, len);
+    return keys;
+}
+
+const char **
+_nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length)
+{
+    g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
+
+    return _get_keys(setting, FALSE, out_length);
+}
+
+const char **
+_nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length)
+{
+    g_return_val_if_fail(NM_IS_SETTING_VPN(setting), NULL);
+
+    return _get_keys(setting, TRUE, out_length);
+}
diff --git a/src/contrib/nm-compat.h b/src/contrib/nm-compat.h
new file mode 100644
index 00000000..33eaec12
--- /dev/null
+++ b/src/contrib/nm-compat.h
@@ -0,0 +1,55 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ */
+
+#ifndef __NM_COMPAT_H__
+#define __NM_COMPAT_H__
+
+#include "nm-setting-vpn.h"
+
+/*****************************************************************************/
+
+const char **_nm_setting_vpn_get_data_keys(NMSettingVpn *setting, guint *out_length);
+
+const char **_nm_setting_vpn_get_secret_keys(NMSettingVpn *setting, guint *out_length);
+
+#if NM_CHECK_VERSION(1, 11, 0)
+    #define nm_setting_vpn_get_data_keys(setting, out_length)  \
+        ({                                                     \
+            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                   \
+            nm_setting_vpn_get_data_keys(setting, out_length); \
+            G_GNUC_END_IGNORE_DEPRECATIONS                     \
+        })
+    #define nm_setting_vpn_get_secret_keys(setting, out_length)  \
+        ({                                                       \
+            G_GNUC_BEGIN_IGNORE_DEPRECATIONS                     \
+            nm_setting_vpn_get_secret_keys(setting, out_length); \
+            G_GNUC_END_IGNORE_DEPRECATIONS                       \
+        })
+#else
+    #define nm_setting_vpn_get_data_keys(setting, out_length) \
+        _nm_setting_vpn_get_data_keys(setting, out_length)
+    #define nm_setting_vpn_get_secret_keys(setting, out_length) \
+        _nm_setting_vpn_get_secret_keys(setting, out_length)
+#endif
+
+/*****************************************************************************/
+
+/* possibly missing defines from newer libnm API. */
+
+#ifndef NM_VPN_PLUGIN_CONFIG_PROXY_PAC
+    #define NM_VPN_PLUGIN_CONFIG_PROXY_PAC "pac"
+#endif
+
+#ifndef NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES
+    #define NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES "preserve-routes"
+#endif
+
+#ifndef NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES
+    #define NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES "preserve-routes"
+#endif
+
+/*****************************************************************************/
+
+#endif /* __NM_COMPAT_H__ */
diff --git a/src/contrib/nm-vpn-editor-plugin-call.h b/src/contrib/nm-vpn-editor-plugin-call.h
new file mode 100644
index 00000000..be0a6772
--- /dev/null
+++ b/src/contrib/nm-vpn-editor-plugin-call.h
@@ -0,0 +1,167 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_VPN_EDITOR_PLUGIN_CALL_H__
+#define __NM_VPN_EDITOR_PLUGIN_CALL_H__
+
+/* This header is an internal, header-only file that can be copied to
+ * other projects to call well-known service functions on VPN plugins.
+ *
+ * This uses the NMVpnEditorPluginVT and allows a user (nm-applet)
+ * to directly communicate with a VPN plugin using API that is newer
+ * then the current libnm version. That is, it allows to call to a VPN
+ * plugin bypassing libnm. */
+
+#include <NetworkManager.h>
+
+/* we make use of other internal header files, you need those too. */
+#include "libnm-glib-aux/nm-macros-internal.h"
+
+/*****************************************************************************/
+
+/**
+ * NMVpnEditorPluginServiceFlags:
+ * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE: no flags
+ * @NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD: whether the plugin can
+ *   add a new connection for the given service-type.
+ **/
+typedef enum { /*< skip >*/
+               NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_NONE    = 0x00,
+               NM_VPN_EDITOR_PLUGIN_SERVICE_FLAGS_CAN_ADD = 0x01,
+} NMVpnEditorPluginServiceFlags;
+
+struct _NMVpnEditorPluginVT {
+    gboolean (*fcn_get_service_info)(NMVpnEditorPlugin *            plugin,
+                                     const char *                   service_type,
+                                     char **                        out_short_name,
+                                     char **                        out_pretty_name,
+                                     char **                        out_description,
+                                     NMVpnEditorPluginServiceFlags *out_flags);
+    char **(*fcn_get_service_add_details)(NMVpnEditorPlugin *plugin, const char *service_name);
+    gboolean (*fcn_get_service_add_detail)(NMVpnEditorPlugin *plugin,
+                                           const char *       service_type,
+                                           const char *       add_detail,
+                                           char **            out_pretty_name,
+                                           char **            out_description,
+                                           char **            out_add_detail_key,
+                                           char **            out_add_detail_val,
+                                           guint *            out_flags);
+};
+
+/*****************************************************************************
+ * Call
+ *
+ * The following wrap the calling of generic functions for a VPN plugin.
+ * They are used by callers (for example nm-connection-editor).
+ *****************************************************************************/
+
+static inline gboolean
+nm_vpn_editor_plugin_get_service_info(NMVpnEditorPlugin *            plugin,
+                                      const char *                   service_type,
+                                      char **                        out_short_name,
+                                      char **                        out_pretty_name,
+                                      char **                        out_description,
+                                      NMVpnEditorPluginServiceFlags *out_flags)
+{
+    NMVpnEditorPluginVT vt;
+    gs_free char *      short_name_local  = NULL;
+    gs_free char *      pretty_name_local = NULL;
+    gs_free char *      description_local = NULL;
+    guint               flags_local       = 0;
+
+    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), FALSE);
+    g_return_val_if_fail(service_type, FALSE);
+
+    nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt));
+    if (!vt.fcn_get_service_info
+        || !vt.fcn_get_service_info(plugin,
+                                    service_type,
+                                    out_short_name ? &short_name_local : NULL,
+                                    out_pretty_name ? &pretty_name_local : NULL,
+                                    out_description ? &description_local : NULL,
+                                    out_flags ? &flags_local : NULL))
+        return FALSE;
+    NM_SET_OUT(out_short_name, g_steal_pointer(&short_name_local));
+    NM_SET_OUT(out_pretty_name, g_steal_pointer(&pretty_name_local));
+    NM_SET_OUT(out_description, g_steal_pointer(&description_local));
+    NM_SET_OUT(out_flags, flags_local);
+    return TRUE;
+}
+
+static inline char **
+nm_vpn_editor_plugin_get_service_add_details(NMVpnEditorPlugin *plugin, const char *service_name)
+{
+    NMVpnEditorPluginVT vt;
+    char **             details = NULL;
+
+    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), NULL);
+    g_return_val_if_fail(service_name, NULL);
+
+    nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt));
+    if (vt.fcn_get_service_add_details)
+        details = vt.fcn_get_service_add_details(plugin, service_name);
+    if (!details)
+        return g_new0(char *, 1);
+    return details;
+}
+
+static inline gboolean
+nm_vpn_editor_plugin_get_service_add_detail(NMVpnEditorPlugin *plugin,
+                                            const char *       service_type,
+                                            const char *       add_detail,
+                                            char **            out_pretty_name,
+                                            char **            out_description,
+                                            char **            out_add_detail_key,
+                                            char **            out_add_detail_val,
+                                            guint *            out_flags)
+{
+    NMVpnEditorPluginVT vt;
+    gs_free char *      pretty_name_local    = NULL;
+    gs_free char *      description_local    = NULL;
+    gs_free char *      add_detail_key_local = NULL;
+    gs_free char *      add_detail_val_local = NULL;
+    guint               flags_local          = 0;
+
+    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(plugin), FALSE);
+    g_return_val_if_fail(service_type, FALSE);
+    g_return_val_if_fail(add_detail, FALSE);
+
+    nm_vpn_editor_plugin_get_vt(plugin, &vt, sizeof(vt));
+    if (!vt.fcn_get_service_add_detail
+        || !vt.fcn_get_service_add_detail(plugin,
+                                          service_type,
+                                          add_detail,
+                                          out_pretty_name ? &pretty_name_local : NULL,
+                                          out_description ? &description_local : NULL,
+                                          out_add_detail_key ? &add_detail_key_local : NULL,
+                                          out_add_detail_val ? &add_detail_val_local : NULL,
+                                          out_flags ? &flags_local : NULL))
+        return FALSE;
+    NM_SET_OUT(out_pretty_name, g_steal_pointer(&pretty_name_local));
+    NM_SET_OUT(out_description, g_steal_pointer(&description_local));
+    NM_SET_OUT(out_add_detail_key, g_steal_pointer(&add_detail_key_local));
+    NM_SET_OUT(out_add_detail_val, g_steal_pointer(&add_detail_val_local));
+    NM_SET_OUT(out_flags, flags_local);
+    return TRUE;
+}
+
+/*****************************************************************************
+ * Implementation
+ *
+ * The following glue code can be used to implement calls in a VPN plugin.
+ *****************************************************************************/
+
+#define NM_VPN_EDITOR_PLUGIN_VT_DEFINE(vt_name, get_vt, ...)                                \
+    static const NMVpnEditorPluginVT  vt_name = {__VA_ARGS__};                              \
+    static const NMVpnEditorPluginVT *get_vt(NMVpnEditorPlugin *plugin, gsize *out_vt_size) \
+    {                                                                                       \
+        nm_assert(NM_IS_VPN_EDITOR_PLUGIN(plugin));                                         \
+        nm_assert(out_vt_size);                                                             \
+                                                                                            \
+        *out_vt_size = sizeof(vt_name);                                                     \
+        return &vt_name;                                                                    \
+    }
+
+#endif /* __NM_VPN_EDITOR_PLUGIN_CALL_H__ */
diff --git a/src/contrib/nm-vpn-plugin-utils.c b/src/contrib/nm-vpn-plugin-utils.c
new file mode 100644
index 00000000..b10695b7
--- /dev/null
+++ b/src/contrib/nm-vpn-plugin-utils.c
@@ -0,0 +1,138 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2016, 2018 Red Hat, Inc.
+ */
+
+#include "libnm-client-aux-extern/nm-default-client.h"
+
+#include "nm-vpn-plugin-utils.h"
+
+#include <dlfcn.h>
+
+/*****************************************************************************/
+
+NMVpnEditor *
+nm_vpn_plugin_utils_load_editor(const char *                  module_name,
+                                const char *                  factory_name,
+                                NMVpnPluginUtilsEditorFactory editor_factory,
+                                NMVpnEditorPlugin *           editor_plugin,
+                                NMConnection *                connection,
+                                gpointer                      user_data,
+                                GError **                     error)
+
+{
+    static struct {
+        gpointer factory;
+        void *   dl_module;
+        char *   module_name;
+        char *   factory_name;
+    } cached = {0};
+    NMVpnEditor * editor;
+    gs_free char *module_path = NULL;
+    gs_free char *dirname     = NULL;
+    Dl_info       plugin_info;
+
+    g_return_val_if_fail(module_name, NULL);
+    g_return_val_if_fail(factory_name && factory_name[0], NULL);
+    g_return_val_if_fail(editor_factory, NULL);
+    g_return_val_if_fail(NM_IS_VPN_EDITOR_PLUGIN(editor_plugin), NULL);
+    g_return_val_if_fail(NM_IS_CONNECTION(connection), NULL);
+    g_return_val_if_fail(!error || !*error, NULL);
+
+    if (!g_path_is_absolute(module_name)) {
+        /*
+         * Load an editor from the same directory this plugin is in.
+         * Ideally, we'd get our .so name from the NMVpnEditorPlugin if it
+         * would just have a property with it...
+         */
+        if (!dladdr(nm_vpn_plugin_utils_load_editor, &plugin_info)) {
+            /* Really a "can not happen" scenario. */
+            g_set_error(error,
+                        NM_VPN_PLUGIN_ERROR,
+                        NM_VPN_PLUGIN_ERROR_FAILED,
+                        _("unable to get editor plugin name: %s"),
+                        dlerror());
+        }
+
+        dirname     = g_path_get_dirname(plugin_info.dli_fname);
+        module_path = g_build_filename(dirname, module_name, NULL);
+    } else {
+        module_path = g_strdup(module_name);
+    }
+
+    /* we really expect this function to be called with unchanging @module_name
+     * and @factory_name. And we only want to load the module once, hence it would
+     * be more complicated to accept changing @module_name/@factory_name arguments.
+     *
+     * The reason for only loading once is that due to glib types, we cannot create a
+     * certain type-name more then once, so loading the same module or another version
+     * of the same module will fail horribly as both try to create a GType with the same
+     * name.
+     *
+     * Only support loading once, any future calls will reuse the handle. To simplify
+     * that, we enforce that the @factory_name and @module_name is the same. */
+    if (cached.factory) {
+        g_return_val_if_fail(cached.dl_module, NULL);
+        g_return_val_if_fail(cached.factory_name && nm_streq0(cached.factory_name, factory_name),
+                             NULL);
+        g_return_val_if_fail(cached.module_name && nm_streq0(cached.module_name, module_name),
+                             NULL);
+    } else {
+        gpointer factory;
+        void *   dl_module;
+
+        dl_module = dlopen(module_path, RTLD_LAZY | RTLD_LOCAL);
+        if (!dl_module) {
+            if (!g_file_test(module_path, G_FILE_TEST_EXISTS)) {
+                g_set_error(error,
+                            G_FILE_ERROR,
+                            G_FILE_ERROR_NOENT,
+                            _("missing plugin file \"%s\""),
+                            module_path);
+                return NULL;
+            }
+            g_set_error(error,
+                        NM_VPN_PLUGIN_ERROR,
+                        NM_VPN_PLUGIN_ERROR_FAILED,
+                        _("cannot load editor plugin: %s"),
+                        dlerror());
+            return NULL;
+        }
+
+        factory = dlsym(dl_module, factory_name);
+        if (!factory) {
+            g_set_error(error,
+                        NM_VPN_PLUGIN_ERROR,
+                        NM_VPN_PLUGIN_ERROR_FAILED,
+                        _("cannot load factory %s from plugin: %s"),
+                        factory_name,
+                        dlerror());
+            dlclose(dl_module);
+            return NULL;
+        }
+
+        /* we cannot ever unload the module because it creates glib types, which
+         * cannot be unregistered.
+         *
+         * Thus we just leak the dl_module handle indefinitely. */
+        cached.factory      = factory;
+        cached.dl_module    = dl_module;
+        cached.module_name  = g_strdup(module_name);
+        cached.factory_name = g_strdup(factory_name);
+    }
+
+    editor = editor_factory(cached.factory, editor_plugin, connection, user_data, error);
+    if (!editor) {
+        if (error && !*error) {
+            g_set_error_literal(error,
+                                NM_VPN_PLUGIN_ERROR,
+                                NM_VPN_PLUGIN_ERROR_FAILED,
+                                _("unknown error creating editor instance"));
+            g_return_val_if_reached(NULL);
+        }
+        return NULL;
+    }
+
+    g_return_val_if_fail(NM_IS_VPN_EDITOR(editor), NULL);
+    return editor;
+}
diff --git a/src/contrib/nm-vpn-plugin-utils.h b/src/contrib/nm-vpn-plugin-utils.h
new file mode 100644
index 00000000..288143ef
--- /dev/null
+++ b/src/contrib/nm-vpn-plugin-utils.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_VPN_PLUGIN_UTILS_H__
+#define __NM_VPN_PLUGIN_UTILS_H__
+
+#include <NetworkManager.h>
+
+typedef NMVpnEditor *(NMVpnPluginUtilsEditorFactory) (gpointer           factory,
+                                                      NMVpnEditorPlugin *editor_plugin,
+                                                      NMConnection *     connection,
+                                                      gpointer           user_data,
+                                                      GError **          error);
+
+NMVpnEditor *nm_vpn_plugin_utils_load_editor(const char *                  module_name,
+                                             const char *                  factory_name,
+                                             NMVpnPluginUtilsEditorFactory editor_factory,
+                                             NMVpnEditorPlugin *           editor_plugin,
+                                             NMConnection *                connection,
+                                             gpointer                      user_data,
+                                             GError **                     error);
+
+#endif /* __NM_VPN_PLUGIN_UTILS_H__ */
diff --git a/src/contrib/tests/meson.build b/src/contrib/tests/meson.build
new file mode 100644
index 00000000..b9b22ca8
--- /dev/null
+++ b/src/contrib/tests/meson.build
@@ -0,0 +1,11 @@
+# SPDX-License-Identifier: LGPL-2.1-or-later
+
+# just test, that we can build "nm-vpn-plugin-utils.c"
+static_library(
+  'nm-vpn-plugin-utils-test',
+  sources: nm_vpn_plugin_utils_source,
+  dependencies: [
+    libnm_dep,
+    glib_dep,
+  ],
+)