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

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