Blame src/connection-editor/page-vpn.c

Packit Service 639700
// SPDX-License-Identifier: GPL-2.0+
Packit fabffb
/* NetworkManager Connection editor -- Connection editor for NetworkManager
Packit fabffb
 *
Packit fabffb
 * Dan Williams <dcbw@redhat.com>
Packit fabffb
 *
Packit fabffb
 * Copyright 2008 - 2014 Red Hat, Inc.
Packit fabffb
 */
Packit fabffb
Packit fabffb
#include "nm-default.h"
Packit fabffb
Packit fabffb
#include "page-vpn.h"
Packit fabffb
Packit fabffb
#include <string.h>
Packit fabffb
Packit fabffb
#include "connection-helpers.h"
Packit fabffb
#include "nm-connection-editor.h"
Packit fabffb
#include "vpn-helpers.h"
Packit fabffb
#include "nm-utils/nm-vpn-editor-plugin-call.h"
Packit fabffb
Packit fabffb
G_DEFINE_TYPE (CEPageVpn, ce_page_vpn, CE_TYPE_PAGE)
Packit fabffb
Packit fabffb
#define CE_PAGE_VPN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), CE_TYPE_PAGE_VPN, CEPageVpnPrivate))
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	NMSettingVpn *setting;
Packit fabffb
Packit fabffb
	char *service_type;
Packit fabffb
Packit fabffb
	NMVpnEditorPlugin *plugin;
Packit fabffb
	NMVpnEditor *editor;
Packit fabffb
} CEPageVpnPrivate;
Packit fabffb
Packit fabffb
static void
Packit fabffb
vpn_plugin_changed_cb (NMVpnEditorPlugin *plugin, CEPageVpn *self)
Packit fabffb
{
Packit fabffb
	ce_page_changed (CE_PAGE (self));
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
finish_setup (CEPageVpn *self, gpointer user_data)
Packit fabffb
{
Packit fabffb
	CEPage *parent = CE_PAGE (self);
Packit fabffb
	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (self);
Packit fabffb
	GError *local = NULL;
Packit fabffb
Packit fabffb
	g_return_if_fail (NM_IS_VPN_EDITOR_PLUGIN (priv->plugin));
Packit fabffb
Packit fabffb
	priv->editor = nm_vpn_editor_plugin_get_editor (priv->plugin, CE_PAGE (self)->connection, &local);
Packit fabffb
	if (!priv->editor) {
Packit fabffb
		g_warning (_("Could not load editor VPN plugin for ā€œ%sā€ (%s)."),
Packit fabffb
		           priv->service_type, local ? local->message : _("unknown failure"));
Packit fabffb
		g_clear_error (&local);
Packit fabffb
		return;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	g_signal_connect (priv->editor, "changed", G_CALLBACK (vpn_plugin_changed_cb), self);
Packit fabffb
Packit fabffb
	parent->page = GTK_WIDGET (nm_vpn_editor_get_widget (priv->editor));
Packit fabffb
	if (!parent->page) {
Packit fabffb
		g_warning ("Could not load VPN user interface for service '%s'.", priv->service_type);
Packit fabffb
		return;
Packit fabffb
	}
Packit fabffb
	g_object_ref_sink (parent->page);
Packit fabffb
	gtk_widget_show_all (parent->page);
Packit fabffb
}
Packit fabffb
Packit fabffb
CEPage *
Packit fabffb
ce_page_vpn_new (NMConnectionEditor *editor,
Packit fabffb
                 NMConnection *connection,
Packit fabffb
                 GtkWindow *parent_window,
Packit fabffb
                 NMClient *client,
Packit fabffb
                 const char **out_secrets_setting_name,
Packit fabffb
                 GError **error)
Packit fabffb
{
Packit fabffb
	CEPageVpn *self;
Packit fabffb
	CEPageVpnPrivate *priv;
Packit fabffb
	const char *service_type;
Packit fabffb
Packit fabffb
	self = CE_PAGE_VPN (ce_page_new (CE_TYPE_PAGE_VPN,
Packit fabffb
	                                 editor,
Packit fabffb
	                                 connection,
Packit fabffb
	                                 parent_window,
Packit fabffb
	                                 client,
Packit fabffb
	                                 NULL,
Packit fabffb
	                                 NULL,
Packit fabffb
	                                 _("VPN")));
Packit fabffb
	if (!self) {
Packit fabffb
		g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not load VPN user interface."));
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	priv = CE_PAGE_VPN_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	priv->setting = nm_connection_get_setting_vpn (connection);
Packit fabffb
	g_assert (priv->setting);
Packit fabffb
Packit fabffb
	service_type = nm_setting_vpn_get_service_type (priv->setting);
Packit fabffb
	g_assert (service_type);
Packit fabffb
	priv->service_type = g_strdup (service_type);
Packit fabffb
Packit fabffb
	priv->plugin = vpn_get_plugin_by_service (service_type);
Packit fabffb
	if (!priv->plugin) {
Packit fabffb
		g_set_error (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Could not find VPN plugin for ā€œ%sā€."), service_type);
Packit fabffb
		g_object_unref (self);
Packit fabffb
		return NULL;
Packit fabffb
	}
Packit fabffb
	priv->plugin = g_object_ref (priv->plugin);
Packit fabffb
Packit fabffb
	g_signal_connect (self, CE_PAGE_INITIALIZED, G_CALLBACK (finish_setup), NULL);
Packit fabffb
Packit fabffb
	*out_secrets_setting_name = NM_SETTING_VPN_SETTING_NAME;
Packit fabffb
Packit fabffb
	return CE_PAGE (self);
Packit fabffb
}
Packit fabffb
Packit fabffb
gboolean
Packit fabffb
ce_page_vpn_can_export (CEPageVpn *page)
Packit fabffb
{
Packit fabffb
	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (page);
Packit fabffb
Packit fabffb
	return (nm_vpn_editor_plugin_get_capabilities (priv->plugin) & NM_VPN_EDITOR_PLUGIN_CAPABILITY_EXPORT) != 0;
Packit fabffb
}
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
ce_page_validate_v (CEPage *page, NMConnection *connection, GError **error)
Packit fabffb
{
Packit fabffb
	CEPageVpn *self = CE_PAGE_VPN (page);
Packit fabffb
	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (self);
Packit fabffb
Packit fabffb
	return nm_vpn_editor_update_connection (priv->editor, connection, error);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ce_page_vpn_init (CEPageVpn *self)
Packit fabffb
{
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
dispose (GObject *object)
Packit fabffb
{
Packit fabffb
	CEPageVpnPrivate *priv = CE_PAGE_VPN_GET_PRIVATE (object);
Packit fabffb
Packit fabffb
	if (priv->editor) {
Packit fabffb
		g_signal_handlers_disconnect_by_func (priv->editor, G_CALLBACK (vpn_plugin_changed_cb), object);
Packit fabffb
		g_clear_object (&priv->editor);
Packit fabffb
	}
Packit fabffb
	g_clear_pointer (&priv->service_type, g_free);
Packit fabffb
Packit fabffb
	g_clear_object (&priv->plugin);
Packit fabffb
Packit fabffb
	G_OBJECT_CLASS (ce_page_vpn_parent_class)->dispose (object);
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
ce_page_vpn_class_init (CEPageVpnClass *vpn_class)
Packit fabffb
{
Packit fabffb
	GObjectClass *object_class = G_OBJECT_CLASS (vpn_class);
Packit fabffb
	CEPageClass *parent_class = CE_PAGE_CLASS (vpn_class);
Packit fabffb
Packit fabffb
	g_type_class_add_private (object_class, sizeof (CEPageVpnPrivate));
Packit fabffb
Packit fabffb
	/* virtual methods */
Packit fabffb
	object_class->dispose = dispose;
Packit fabffb
Packit fabffb
	parent_class->ce_page_validate_v = ce_page_validate_v;
Packit fabffb
}
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	NMClient *client;
Packit fabffb
	PageNewConnectionResultFunc result_func;
Packit fabffb
	gpointer user_data;
Packit fabffb
} NewVpnInfo;
Packit fabffb
Packit fabffb
typedef void (*VpnImportSuccessCallback) (NMConnection *connection, gpointer user_data);
Packit fabffb
Packit fabffb
typedef struct {
Packit fabffb
	VpnImportSuccessCallback callback;
Packit fabffb
	gpointer user_data;
Packit fabffb
} ActionInfo;
Packit fabffb
Packit fabffb
static void
Packit fabffb
complete_vpn_connection (NMConnection *connection, NMClient *client)
Packit fabffb
{
Packit fabffb
	ce_page_complete_connection (connection,
Packit fabffb
	                             _("VPN connection %d"),
Packit fabffb
	                             NM_SETTING_VPN_SETTING_NAME,
Packit fabffb
	                             FALSE,
Packit fabffb
	                             client);
Packit fabffb
}
Packit fabffb
Packit fabffb
#define NEW_VPN_CONNECTION_PRIMARY_LABEL _("Choose a VPN Connection Type")
Packit fabffb
#define NEW_VPN_CONNECTION_SECONDARY_LABEL _("Select the type of VPN you wish to use for the new connection. If the type of VPN connection you wish to create does not appear in the list, you may not have the correct VPN plugin installed.")
Packit fabffb
Packit fabffb
static gboolean
Packit fabffb
vpn_type_filter_func (FUNC_TAG_NEW_CONNECTION_TYPE_FILTER_IMPL,
Packit fabffb
                      GType type,
Packit fabffb
                      gpointer user_data)
Packit fabffb
{
Packit fabffb
	return type == NM_TYPE_SETTING_VPN;
Packit fabffb
}
Packit fabffb
Packit fabffb
static void
Packit fabffb
vpn_type_result_func (FUNC_TAG_NEW_CONNECTION_RESULT_IMPL,
Packit fabffb
                      NMConnection *connection,
Packit fabffb
                      gpointer user_data)
Packit fabffb
{
Packit fabffb
	NewVpnInfo *info = user_data;
Packit fabffb
Packit fabffb
	info->result_func (FUNC_TAG_PAGE_NEW_CONNECTION_RESULT_CALL, connection, connection == NULL, NULL, info->user_data);
Packit fabffb
	g_slice_free (NewVpnInfo, info);
Packit fabffb
}
Packit fabffb
Packit fabffb
void
Packit fabffb
vpn_connection_new (FUNC_TAG_PAGE_NEW_CONNECTION_IMPL,
Packit fabffb
                    GtkWindow *parent,
Packit fabffb
                    const char *detail,
Packit fabffb
                    gpointer detail_data,
Packit fabffb
                    NMConnection *connection,
Packit fabffb
                    NMClient *client,
Packit fabffb
                    PageNewConnectionResultFunc result_func,
Packit fabffb
                    gpointer user_data)
Packit fabffb
{
Packit fabffb
	NMSetting *s_vpn;
Packit fabffb
	const char *service_type;
Packit fabffb
	gs_free char *service_type_free = NULL;
Packit fabffb
	gs_free char *add_detail_key_free = NULL;
Packit fabffb
	gs_free char *add_detail_val_free = NULL;
Packit fabffb
	const CEPageVpnDetailData *vpn_data = detail_data;
Packit fabffb
	gssize split_idx, l;
Packit fabffb
	const char *add_detail_key = NULL;
Packit fabffb
	const char *add_detail_val = NULL;
Packit fabffb
	gs_unref_object NMConnection *connection_tmp = NULL;
Packit fabffb
Packit fabffb
	if (!detail && !connection) {
Packit fabffb
		NewVpnInfo *info;
Packit fabffb
Packit fabffb
		/* This will happen if nm-c-e is launched from the command line
Packit fabffb
		 * with "--create --type vpn". Dump the user back into the
Packit fabffb
		 * new connection dialog to let them pick a subtype now.
Packit fabffb
		 */
Packit fabffb
		info = g_slice_new (NewVpnInfo);
Packit fabffb
		info->result_func = result_func;
Packit fabffb
		info->user_data = user_data;
Packit fabffb
		new_connection_dialog_full (parent, client,
Packit fabffb
		                            NEW_VPN_CONNECTION_PRIMARY_LABEL,
Packit fabffb
		                            NEW_VPN_CONNECTION_SECONDARY_LABEL,
Packit fabffb
		                            vpn_type_filter_func,
Packit fabffb
		                            vpn_type_result_func, info);
Packit fabffb
		return;
Packit fabffb
	}
Packit fabffb
Packit fabffb
	connection = _ensure_connection_other (connection, &connection_tmp);
Packit fabffb
	if (detail) {
Packit fabffb
		service_type = detail;
Packit fabffb
		add_detail_key = vpn_data ? vpn_data->add_detail_key : NULL;
Packit fabffb
		add_detail_val = vpn_data ? vpn_data->add_detail_val : NULL;
Packit fabffb
Packit fabffb
		service_type_free = nm_vpn_plugin_info_list_find_service_type (vpn_get_plugin_infos (), detail);
Packit fabffb
		if (service_type_free)
Packit fabffb
			service_type = service_type_free;
Packit fabffb
		else if (!vpn_data) {
Packit fabffb
			/* when called without @vpn_data, it means that @detail may contain "<SERVICE_TYPE>:<ADD_DETAIL>".
Packit fabffb
			 * Try to parse them by spliting @detail at the colons and try to interpret the first part as
Packit fabffb
			 * @service_type and the remainder as add-detail. */
Packit fabffb
			l = strlen (detail);
Packit fabffb
			for (split_idx = 1; split_idx < l - 1; split_idx++) {
Packit fabffb
				if (detail[split_idx] == ':') {
Packit fabffb
					gs_free char *detail_main = g_strndup (detail, split_idx);
Packit fabffb
					NMVpnEditorPlugin *plugin;
Packit fabffb
Packit fabffb
					service_type_free = nm_vpn_plugin_info_list_find_service_type (vpn_get_plugin_infos (), detail_main);
Packit fabffb
					if (!service_type_free)
Packit fabffb
						continue;
Packit fabffb
					plugin = vpn_get_plugin_by_service (service_type_free);
Packit fabffb
					if (!plugin) {
Packit fabffb
						g_clear_pointer (&service_type_free, g_free);
Packit fabffb
						continue;
Packit fabffb
					}
Packit fabffb
Packit fabffb
					/* we found a @service_type. Try to use the remainder as add-detail. */
Packit fabffb
					service_type = service_type_free;
Packit fabffb
					if (nm_vpn_editor_plugin_get_service_add_detail (plugin, service_type, &detail[split_idx + 1],
Packit fabffb
					                                                 NULL, NULL,
Packit fabffb
					                                                 &add_detail_key_free, &add_detail_val_free, NULL)
Packit fabffb
					    && add_detail_key_free && add_detail_key_free[0]
Packit fabffb
					    && add_detail_val_free && add_detail_val_free[0]) {
Packit fabffb
						add_detail_key = add_detail_key_free;
Packit fabffb
						add_detail_val = add_detail_val_free;
Packit fabffb
					}
Packit fabffb
					break;
Packit fabffb
				}
Packit fabffb
			}
Packit fabffb
		}
Packit fabffb
		if (!service_type)
Packit fabffb
			service_type = detail;
Packit fabffb
Packit fabffb
		s_vpn = nm_setting_vpn_new ();
Packit fabffb
		g_object_set (s_vpn, NM_SETTING_VPN_SERVICE_TYPE, service_type, NULL);
Packit fabffb
Packit fabffb
		if (add_detail_key)
Packit fabffb
			nm_setting_vpn_add_data_item ((NMSettingVpn *) s_vpn, add_detail_key, add_detail_val);
Packit fabffb
Packit fabffb
		nm_connection_add_setting (connection, s_vpn);
Packit fabffb
	}
Packit fabffb
Packit fabffb
	complete_vpn_connection (connection, client);
Packit fabffb
Packit fabffb
	(*result_func) (FUNC_TAG_PAGE_NEW_CONNECTION_RESULT_CALL, connection, FALSE, NULL, user_data);
Packit fabffb
}