diff options
Diffstat (limited to 'libnm-core/nm-vpn-plugin-info.c')
| -rw-r--r-- | libnm-core/nm-vpn-plugin-info.c | 1354 |
1 files changed, 0 insertions, 1354 deletions
diff --git a/libnm-core/nm-vpn-plugin-info.c b/libnm-core/nm-vpn-plugin-info.c deleted file mode 100644 index cb739510..00000000 --- a/libnm-core/nm-vpn-plugin-info.c +++ /dev/null @@ -1,1354 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "libnm-core/nm-default-libnm-core.h" - -#include "nm-vpn-plugin-info.h" - -#include <sys/stat.h> - -#include "nm-errors.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; - char * auth_dialog; - char ** aliases; - 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; - - gboolean editor_plugin_loaded; - NMVpnEditorPlugin *editor_plugin; -} NMVpnPluginInfoPrivate; - -/** - * NMVpnPluginInfo: - */ -struct _NMVpnPluginInfo { - GObject parent; - NMVpnPluginInfoPrivate _priv; -}; - -struct _NMVpnPluginInfoClass { - GObjectClass parent; -}; - -#define NM_VPN_PLUGIN_INFO_GET_PRIVATE(self) \ - _NM_GET_PRIVATE(self, NMVpnPluginInfo, NM_IS_VPN_PLUGIN_INFO) - -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);) - -/*****************************************************************************/ - -static NMVpnPluginInfo *_list_find_by_service(GSList *list, const char *name, const char *service); - -/*****************************************************************************/ - -/** - * 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: the file to check - * @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 nm_str_not_empty(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) (element-type NMVpnPluginInfo): 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, NULL); - - if (!dirname[0]) - return 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: (element-type NMVpnPluginInfo) (transfer 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 *const 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; -} - -/** - * nm_vpn_plugin_info_new_search_file: - * @name: (allow-none): the name to search for. Either @name or @service - * must be present. - * @service: (allow-none): the service to search for. Either @name or - * @service must be present. - * - * This has the same effect as doing a full nm_vpn_plugin_info_list_load() - * followed by a search for the first matching VPN plugin info that has the - * given @name and/or @service. - * - * Returns: (transfer full): a newly created instance of plugin info - * or %NULL if no matching value was found. - * - * Since: 1.4 - */ -NMVpnPluginInfo * -nm_vpn_plugin_info_new_search_file(const char *name, const char *service) -{ - NMVpnPluginInfo *info; - GSList * infos; - - if (!name && !service) - g_return_val_if_reached(NULL); - - infos = nm_vpn_plugin_info_list_load(); - info = nm_g_object_ref(_list_find_by_service(infos, name, service)); - g_slist_free_full(infos, g_object_unref); - return info; -} - -/*****************************************************************************/ - -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: (element-type NMVpnPluginInfo): 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 service type. */ - 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: (element-type NMVpnPluginInfo): 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) -{ - 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: (element-type NMVpnPluginInfo): list of plugins - * @name: name to search - * - * Returns: (transfer none): 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: (element-type NMVpnPluginInfo): list of plugins - * @filename: filename to search - * - * Returns: (transfer none): 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; -} - -static NMVpnPluginInfo * -_list_find_by_service(GSList *list, const char *name, const char *service) -{ - for (; list; list = list->next) { - NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE(list->data); - - if (name && !nm_streq(name, priv->name)) - continue; - if (service && !nm_streq(priv->service, service) - && (nm_utils_strv_find_first(priv->aliases, -1, service) < 0)) - continue; - - return list->data; - } - return NULL; -} - -/** - * nm_vpn_plugin_info_list_find_by_service: - * @list: (element-type NMVpnPluginInfo): list of plugins - * @service: service to search. This can be the main service-type - * or one of the provided aliases. - * - * Returns: (transfer none): 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) -{ - if (!service) - g_return_val_if_reached(NULL); - return _list_find_by_service(list, NULL, service); -} - -/* known_names are well known short names for the service-type. They all implicitly - * have a prefix "org.freedesktop.NetworkManager." + known_name. */ -static const char *known_names[] = { - "openvpn", - "vpnc", - "pptp", - "openconnect", - "openswan", - "libreswan", - "strongswan", - "ssh", - "l2tp", - "iodine", - "fortisslvpn", -}; - -/** - * nm_vpn_plugin_info_list_find_service_type: - * @list: (element-type NMVpnPluginInfo): a possibly empty #GSList of #NMVpnPluginInfo instances - * @name: a name to lookup the service-type. - * - * A VPN plugin provides one or several service-types, like org.freedesktop.NetworkManager.libreswan - * Certain plugins provide more then one service type, via aliases (org.freedesktop.NetworkManager.openswan). - * This function looks up a service-type (or an alias) based on a name. - * - * Preferably, the name can be a full service-type/alias of an installed - * plugin. Otherwise, it can be the name of a VPN plugin (in which case, the - * primary, non-aliased service-type is returned). Otherwise, it can be - * one of several well known short-names (which is a hard-coded list of - * types in libnm). On success, this returns a full qualified service-type - * (or an alias). It doesn't say, that such an plugin is actually available, - * but it could be retrieved via nm_vpn_plugin_info_list_find_by_service(). - * - * Returns: (transfer full): the resolved service-type or %NULL on failure. - * - * Since: 1.4 - */ -char * -nm_vpn_plugin_info_list_find_service_type(GSList *list, const char *name) -{ - NMVpnPluginInfo *info; - char * n; - - if (!name) - g_return_val_if_reached(NULL); - if (!*name) - return NULL; - - /* First, try to interpret @name as a full service-type (or alias). */ - info = _list_find_by_service(list, NULL, name); - if (info) - return g_strdup(name); - - /* try to interpret @name as plugin name, in which case we return - * the main service-type (not an alias). */ - info = _list_find_by_service(list, name, NULL); - if (info) - return g_strdup(NM_VPN_PLUGIN_INFO_GET_PRIVATE(info)->service); - - /* check the hard-coded list of short-names. They all have the same - * well-known prefix org.freedesktop.NetworkManager and the name. */ - if (nm_utils_strv_find_first((char **) known_names, G_N_ELEMENTS(known_names), name) >= 0) - return g_strdup_printf("%s.%s", NM_DBUS_INTERFACE, name); - - /* try, if there exists a plugin with @name under org.freedesktop.NetworkManager. - * Allow this to be a valid abbreviation. */ - n = g_strdup_printf("%s.%s", NM_DBUS_INTERFACE, name); - if (_list_find_by_service(list, NULL, n)) - return n; - g_free(n); - - /* currently, VPN plugins have no way to define a short-name for their - * alias name, unless the alias name is prefixed by org.freedesktop.NetworkManager. */ - - return NULL; -} - -static const char * -_service_type_get_default_abbreviation(const char *service_type) -{ - if (!g_str_has_prefix(service_type, NM_DBUS_INTERFACE)) - return NULL; - service_type += NM_STRLEN(NM_DBUS_INTERFACE); - if (service_type[0] != '.') - return NULL; - service_type++; - if (!service_type[0]) - return NULL; - return service_type; -} - -/** - * nm_vpn_plugin_info_list_get_service_types: - * @list: (element-type NMVpnPluginInfo): a possibly empty #GSList of #NMVpnPluginInfo - * @only_existing: only include results that are actually in @list. - * Otherwise, the result is extended with a hard-code list or - * well-known plugins - * @with_abbreviations: if %FALSE, only full service types are returned. - * Otherwise, this also includes abbreviated names that can be used - * with nm_vpn_plugin_info_list_find_service_type(). - * - * Returns: (transfer full): a %NULL terminated strv list of strings. - * The list itself and the values must be freed with g_strfreev(). - * - * Since: 1.4 - */ -char ** -nm_vpn_plugin_info_list_get_service_types(GSList * list, - gboolean only_existing, - gboolean with_abbreviations) -{ - GSList * iter; - GPtrArray * l; - guint i, j; - const char *n; - - l = g_ptr_array_sized_new(20); - - for (iter = list; iter; iter = iter->next) { - NMVpnPluginInfoPrivate *priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE(iter->data); - - g_ptr_array_add(l, g_strdup(priv->service)); - if (priv->aliases) { - for (i = 0; priv->aliases[i]; i++) - g_ptr_array_add(l, g_strdup(priv->aliases[i])); - } - - if (with_abbreviations) { - g_ptr_array_add(l, g_strdup(priv->name)); - n = _service_type_get_default_abbreviation(priv->service); - if (n) - g_ptr_array_add(l, g_strdup(n)); - for (i = 0; priv->aliases && priv->aliases[i]; i++) { - n = _service_type_get_default_abbreviation(priv->aliases[i]); - if (n) - g_ptr_array_add(l, g_strdup(n)); - } - } - } - - if (!only_existing) { - for (i = 0; i < G_N_ELEMENTS(known_names); i++) { - g_ptr_array_add(l, g_strdup_printf("%s.%s", NM_DBUS_INTERFACE, known_names[i])); - if (with_abbreviations) - g_ptr_array_add(l, g_strdup(known_names[i])); - } - } - - if (l->len <= 0) { - g_ptr_array_free(l, TRUE); - return g_new0(char *, 1); - } - - /* sort the result and remove duplicates. */ - g_ptr_array_sort(l, nm_strcmp_p); - for (i = 1, j = 1; i < l->len; i++) { - if (nm_streq(l->pdata[j - 1], l->pdata[i])) - g_free(l->pdata[i]); - else - l->pdata[j++] = l->pdata[i]; - } - - if (j == l->len) - g_ptr_array_add(l, NULL); - else - l->pdata[j] = NULL; - return (char **) g_ptr_array_free(l, FALSE); -} - -/*****************************************************************************/ - -/** - * 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.4 - */ -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_auth_dialog: - * @self: plugin info instance - * - * Returns: the absolute path to the auth-dialog helper or %NULL. - * - * Since: 1.4 - **/ -const char * -nm_vpn_plugin_info_get_auth_dialog(NMVpnPluginInfo *self) -{ - NMVpnPluginInfoPrivate *priv; - - g_return_val_if_fail(NM_IS_VPN_PLUGIN_INFO(self), NULL); - - priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE(self); - - if (G_UNLIKELY(priv->auth_dialog == NULL)) { - const char *s; - - s = g_hash_table_lookup( - priv->keys, - _nm_utils_strstrdictkey_static(NM_VPN_PLUGIN_INFO_KF_GROUP_GNOME, "auth-dialog")); - if (!s || !s[0]) - priv->auth_dialog = g_strdup(""); - else if (g_path_is_absolute(s)) - priv->auth_dialog = g_strdup(s); - else { - /* for relative paths, we take the basename and assume it's in LIBEXECDIR. */ - gs_free char *prog_basename = g_path_get_basename(s); - - priv->auth_dialog = g_build_filename(LIBEXECDIR, prog_basename, NULL); - } - } - - return priv->auth_dialog[0] ? priv->auth_dialog : NULL; -} - -/** - * nm_vpn_plugin_info_supports_hints: - * @self: plugin info instance - * - * Returns: %TRUE if the supports hints for secret requests, otherwise %FALSE - * - * Since: 1.4 - */ -gboolean -nm_vpn_plugin_info_supports_hints(NMVpnPluginInfo *self) -{ - const char *s; - - g_return_val_if_fail(NM_IS_VPN_PLUGIN_INFO(self), FALSE); - - s = nm_vpn_plugin_info_lookup_property(self, - NM_VPN_PLUGIN_INFO_KF_GROUP_GNOME, - "supports-hints"); - return _nm_utils_ascii_str_to_bool(s, FALSE); -} - -/** - * 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_supports_multiple: - * @self: plugin info instance - * - * Returns: %TRUE if the service supports multiple instances with different bus names, otherwise %FALSE - * - * Since: 1.2 - */ -gboolean -nm_vpn_plugin_info_supports_multiple(NMVpnPluginInfo *self) -{ - const char *s; - - g_return_val_if_fail(NM_IS_VPN_PLUGIN_INFO(self), FALSE); - - s = nm_vpn_plugin_info_lookup_property(self, - NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, - "supports-multiple-connections"); - return _nm_utils_ascii_str_to_bool(s, FALSE); -} - -/** - * nm_vpn_plugin_info_get_aliases: - * @self: plugin info instance - * - * Returns: (array zero-terminated=1) (element-type utf8) (transfer none): - * the aliases from the name-file. - * - * Since: 1.4 - */ -const char *const * -nm_vpn_plugin_info_get_aliases(NMVpnPluginInfo *self) -{ - NMVpnPluginInfoPrivate *priv; - - g_return_val_if_fail(NM_IS_VPN_PLUGIN_INFO(self), NULL); - - priv = NM_VPN_PLUGIN_INFO_GET_PRIVATE(self); - if (priv->aliases) - return (const char *const *) priv->aliases; - - /* For convenience, we always want to return non-NULL, even for empty - * aliases. Hack around that, by making a NULL terminated array using - * the NULL of priv->aliases. */ - return (const char *const *) &priv->aliases; -} - -/** - * 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_get_editor_plugin: - * @self: plugin info instance - * - * Returns: (transfer none): 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: (transfer none): 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, - nm_vpn_plugin_info_get_service(self), - getuid(), - NULL, - NULL, - error); - if (priv->editor_plugin) - nm_vpn_editor_plugin_set_plugin_info(priv->editor_plugin, self); - return priv->editor_plugin; -} - -/*****************************************************************************/ - -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 -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 -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->aliases = g_key_file_get_string_list(priv->keyfile, - NM_VPN_PLUGIN_INFO_KF_GROUP_CONNECTION, - "aliases", - NULL, - NULL); - if (priv->aliases && !priv->aliases[0]) - nm_clear_g_free(&priv->aliases); - - 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 for all our - * values. */ - 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); - } - } - - nm_clear_pointer(&priv->keyfile, g_key_file_unref); - - return TRUE; -} - -/** - * 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 -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) -{ - 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->auth_dialog); - g_strfreev(priv->aliases); - g_free(priv->filename); - g_hash_table_unref(priv->keys); - - nm_clear_pointer(&priv->keyfile, g_key_file_unref); - - 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); - - object_class->set_property = set_property; - object_class->get_property = get_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - /** - * 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: - * - * Initialize 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; -} |