|
Packit Service |
639700 |
// SPDX-License-Identifier: GPL-2.0+
|
|
Packit |
fabffb |
/* NetworkManager Connection editor -- Connection editor for NetworkManager
|
|
Packit |
fabffb |
*
|
|
Packit |
fabffb |
* Rodrigo Moya <rodrigo@gnome-db.org>
|
|
Packit |
fabffb |
* Dan Williams <dcbw@redhat.com>
|
|
Packit |
fabffb |
* Tambet Ingo <tambet@gmail.com>
|
|
Packit |
fabffb |
*
|
|
Packit |
fabffb |
* Copyright 2007 - 2017 Red Hat, Inc.
|
|
Packit |
fabffb |
* Copyright 2007 - 2008 Novell, Inc.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#include "nm-default.h"
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#include <string.h>
|
|
Packit |
fabffb |
#include <sys/types.h>
|
|
Packit |
fabffb |
#include <unistd.h>
|
|
Packit |
fabffb |
#include <errno.h>
|
|
Packit |
fabffb |
#include <gdk/gdkx.h>
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#if WITH_SELINUX
|
|
Packit |
fabffb |
#include <selinux/selinux.h>
|
|
Packit |
fabffb |
#endif
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#include "nm-connection-editor.h"
|
|
Packit |
fabffb |
#include "nma-cert-chooser.h"
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#include "ce-page.h"
|
|
Packit |
fabffb |
#include "page-general.h"
|
|
Packit |
fabffb |
#include "page-ethernet.h"
|
|
Packit |
fabffb |
#include "page-8021x-security.h"
|
|
Packit |
fabffb |
#include "page-wifi.h"
|
|
Packit |
fabffb |
#include "page-wifi-security.h"
|
|
Packit |
fabffb |
#include "page-proxy.h"
|
|
Packit |
fabffb |
#include "page-ip4.h"
|
|
Packit |
fabffb |
#include "page-ip6.h"
|
|
Packit |
fabffb |
#include "page-ip-tunnel.h"
|
|
Packit |
fabffb |
#include "page-dsl.h"
|
|
Packit |
fabffb |
#include "page-mobile.h"
|
|
Packit |
fabffb |
#include "page-bluetooth.h"
|
|
Packit |
fabffb |
#include "page-ppp.h"
|
|
Packit |
fabffb |
#include "page-vpn.h"
|
|
Packit |
fabffb |
#include "page-infiniband.h"
|
|
Packit |
fabffb |
#include "page-bond.h"
|
|
Packit |
fabffb |
#include "page-team.h"
|
|
Packit |
fabffb |
#include "page-team-port.h"
|
|
Packit |
fabffb |
#include "page-bridge.h"
|
|
Packit |
fabffb |
#include "page-bridge-port.h"
|
|
Packit |
fabffb |
#include "page-vlan.h"
|
|
Packit |
fabffb |
#include "page-dcb.h"
|
|
Packit |
fabffb |
#include "page-macsec.h"
|
|
Packit Service |
639700 |
#include "page-wireguard.h"
|
|
Packit |
fabffb |
#include "ce-polkit-button.h"
|
|
Packit |
fabffb |
#include "vpn-helpers.h"
|
|
Packit |
fabffb |
#include "eap-method.h"
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
extern gboolean nm_ce_keep_above;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
G_DEFINE_TYPE (NMConnectionEditor, nm_connection_editor, G_TYPE_OBJECT)
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
enum {
|
|
Packit |
fabffb |
EDITOR_DONE,
|
|
Packit |
fabffb |
NEW_EDITOR,
|
|
Packit |
fabffb |
EDITOR_LAST_SIGNAL
|
|
Packit |
fabffb |
};
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static guint editor_signals[EDITOR_LAST_SIGNAL] = { 0 };
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static GHashTable *active_editors;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean nm_connection_editor_set_connection (NMConnectionEditor *editor,
|
|
Packit |
fabffb |
NMConnection *connection,
|
|
Packit |
fabffb |
GError **error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
struct GetSecretsInfo {
|
|
Packit |
fabffb |
NMConnectionEditor *self;
|
|
Packit |
fabffb |
CEPage *page;
|
|
Packit |
fabffb |
char *setting_name;
|
|
Packit |
fabffb |
gboolean canceled;
|
|
Packit |
fabffb |
};
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#define SECRETS_TAG "secrets-setting-name"
|
|
Packit |
fabffb |
#define ORDER_TAG "page-order"
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
nm_connection_editor_update_title (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
const char *id;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_return_if_fail (editor != NULL);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (editor->connection);
|
|
Packit |
fabffb |
g_assert (s_con);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
id = nm_setting_connection_get_id (s_con);
|
|
Packit |
fabffb |
if (id && strlen (id)) {
|
|
Packit |
fabffb |
char *title = g_strdup_printf (_("Editing %s"), id);
|
|
Packit |
fabffb |
gtk_window_set_title (GTK_WINDOW (editor->window), title);
|
|
Packit |
fabffb |
g_free (title);
|
|
Packit |
fabffb |
} else
|
|
Packit |
fabffb |
gtk_window_set_title (GTK_WINDOW (editor->window), _("Editing un-named connection"));
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
ui_to_setting (NMConnectionEditor *editor, GError **error)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
GtkWidget *widget;
|
|
Packit |
fabffb |
const char *name;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (editor->connection);
|
|
Packit |
fabffb |
g_assert (s_con);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
widget = GTK_WIDGET (gtk_builder_get_object (editor->builder, "connection_name"));
|
|
Packit |
fabffb |
name = gtk_entry_get_text (GTK_ENTRY (widget));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_object_set (G_OBJECT (s_con), NM_SETTING_CONNECTION_ID, name, NULL);
|
|
Packit |
fabffb |
nm_connection_editor_update_title (editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!name || !strlen (name)) {
|
|
Packit |
fabffb |
g_set_error_literal (error, NMA_ERROR, NMA_ERROR_GENERIC, _("Missing connection name"));
|
|
Packit |
fabffb |
return FALSE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return TRUE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
editor_is_initialized (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
return (g_slist_length (editor->initializing_pages) == 0);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
update_sensitivity (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
gboolean sensitive = FALSE;
|
|
Packit |
fabffb |
GtkWidget *widget;
|
|
Packit |
fabffb |
GSList *iter;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (editor->connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Can't modify read-only connections; can't modify anything before the
|
|
Packit |
fabffb |
* editor is initialized either.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
if ( editor_is_initialized (editor)
|
|
Packit |
fabffb |
&& editor->can_modify
|
|
Packit |
fabffb |
&& !nm_setting_connection_get_read_only (s_con)) {
|
|
Packit |
fabffb |
/* If the user cannot ever be authorized to change system connections,
|
|
Packit |
fabffb |
* we desensitize the entire dialog.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
sensitive = ce_polkit_button_get_authorized (CE_POLKIT_BUTTON (editor->ok_button));
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Cancel button is always sensitive */
|
|
Packit |
fabffb |
gtk_widget_set_sensitive (GTK_WIDGET (editor->cancel_button), TRUE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
widget = GTK_WIDGET (gtk_builder_get_object (editor->builder, "connection_name_label"));
|
|
Packit |
fabffb |
gtk_widget_set_sensitive (widget, sensitive);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
widget = GTK_WIDGET (gtk_builder_get_object (editor->builder, "connection_name"));
|
|
Packit |
fabffb |
gtk_widget_set_sensitive (widget, sensitive);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
for (iter = editor->pages; iter; iter = g_slist_next (iter)) {
|
|
Packit |
fabffb |
widget = ce_page_get_page (CE_PAGE (iter->data));
|
|
Packit |
fabffb |
gtk_widget_set_sensitive (widget, sensitive);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
#if WITH_SELINUX
|
|
Packit |
fabffb |
/* This is what the files in ~/.cert would get. */
|
|
Packit |
fabffb |
static const char certcon[] = "unconfined_u:object_r:home_cert_t:s0";
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
clear_name_if_present (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
gchar **filename = data;
|
|
Packit |
fabffb |
gs_free char *existing = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_tree_model_get (model, iter, 2, &existing, -1);
|
|
Packit |
fabffb |
if (g_strcmp0 (existing, *filename) == 0) {
|
|
Packit |
fabffb |
*filename = NULL;
|
|
Packit |
fabffb |
return TRUE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return FALSE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
update_relabel_list_filename (GtkListStore *store, char *filename)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GtkTreeIter iter;
|
|
Packit |
fabffb |
gboolean writable;
|
|
Packit |
fabffb |
char *tcon;
|
|
Packit |
fabffb |
/* Any kind of VPN would do. If OpenVPN can't access the files
|
|
Packit |
fabffb |
* no VPN likely can. NetworkManager policy currently allows
|
|
Packit |
fabffb |
* accessing home. It may make sense to tighten it some point. */
|
|
Packit |
fabffb |
static const char scon[] = "system_u:system_r:openvpn_t:s0";
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_tree_model_foreach (GTK_TREE_MODEL (store), clear_name_if_present, &filename);
|
|
Packit |
fabffb |
if (filename == NULL)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (getfilecon (filename, &tcon) == -1) {
|
|
Packit |
fabffb |
/* Don't warn here, just ignore it. Perhaps the file
|
|
Packit |
fabffb |
* is not on a SELinux-capable filesystem or something. */
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (g_strcmp0 (certcon, tcon) == 0)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
writable = (access (filename, W_OK) == 0);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (selinux_check_access (scon, tcon, "file", "open", NULL) == -1) {
|
|
Packit |
fabffb |
gtk_list_store_append (store, &iter);
|
|
Packit |
fabffb |
gtk_list_store_set (store, &iter,
|
|
Packit |
fabffb |
0, writable,
|
|
Packit |
fabffb |
1, writable,
|
|
Packit |
fabffb |
2, filename,
|
|
Packit |
fabffb |
-1);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
freecon (tcon);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
update_relabel_list (GtkWidget *widget, GtkListStore *store)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
gchar *filename = NULL;
|
|
Packit |
fabffb |
NMSetting8021xCKScheme scheme;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!gtk_widget_is_sensitive (widget))
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (NMA_IS_CERT_CHOOSER (widget)) {
|
|
Packit |
fabffb |
filename = nma_cert_chooser_get_cert (NMA_CERT_CHOOSER (widget), &scheme);
|
|
Packit |
fabffb |
if (filename && scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
|
|
Packit |
fabffb |
update_relabel_list_filename (store, filename);
|
|
Packit |
fabffb |
g_free (filename);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
filename = nma_cert_chooser_get_key (NMA_CERT_CHOOSER (widget), &scheme);
|
|
Packit |
fabffb |
if (filename && scheme == NM_SETTING_802_1X_CK_SCHEME_PATH) {
|
|
Packit |
fabffb |
update_relabel_list_filename (store, filename);
|
|
Packit |
fabffb |
g_free (filename);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
} else if (GTK_IS_CONTAINER (widget)) {
|
|
Packit |
fabffb |
gtk_container_foreach (GTK_CONTAINER (widget),
|
|
Packit |
fabffb |
(GtkCallback) update_relabel_list,
|
|
Packit |
fabffb |
store);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
recheck_relabel (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
gtk_list_store_clear (editor->relabel_list);
|
|
Packit |
fabffb |
update_relabel_list (editor->window, editor->relabel_list);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (gtk_tree_model_iter_n_children (GTK_TREE_MODEL (editor->relabel_list), NULL))
|
|
Packit |
fabffb |
gtk_widget_show (editor->relabel_info);
|
|
Packit |
fabffb |
else
|
|
Packit |
fabffb |
gtk_widget_hide (editor->relabel_info);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
relabel_toggled (GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor = user_data;
|
|
Packit |
fabffb |
GtkTreeIter iter;
|
|
Packit |
fabffb |
gboolean relabel;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (editor->relabel_list), &iter, path))
|
|
Packit |
fabffb |
g_return_if_reached ();
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_tree_model_get (GTK_TREE_MODEL (editor->relabel_list), &iter, 0, &relabel, -1);
|
|
Packit |
fabffb |
gtk_list_store_set (editor->relabel_list, &iter, 0, !relabel, -1);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
maybe_relabel (GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, gpointer data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
gboolean relabel;
|
|
Packit |
fabffb |
gchar *filename;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_tree_model_get (model, iter, 0, &relabel, 2, &filename, -1);
|
|
Packit |
fabffb |
if (relabel) {
|
|
Packit |
fabffb |
if (setfilecon (filename, certcon) == -1)
|
|
Packit |
fabffb |
g_warning ("setfilecon: %s\n", g_strerror (errno));
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_free (filename);
|
|
Packit |
fabffb |
return FALSE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
relabel_button_clicked_cb (GtkWidget *widget, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (gtk_dialog_run (GTK_DIALOG (editor->relabel_dialog)) == GTK_RESPONSE_APPLY) {
|
|
Packit |
fabffb |
gtk_tree_model_foreach (GTK_TREE_MODEL (editor->relabel_list), maybe_relabel, NULL);
|
|
Packit |
fabffb |
recheck_relabel (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
gtk_widget_hide (editor->relabel_dialog);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
#else /* !WITH_SELINUX */
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
recheck_relabel (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
relabel_toggled (GtkCellRendererToggle *cell_renderer, gchar *path, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_if_reached ();
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
relabel_button_clicked_cb (GtkWidget *widget, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_if_reached ();
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
#endif /* WITH_SELINUX */
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
connection_editor_validate (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
GSList *iter;
|
|
Packit |
fabffb |
gs_free char *validation_error = NULL;
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!editor_is_initialized (editor)) {
|
|
Packit |
fabffb |
validation_error = g_strdup (_("Editor initializing…"));
|
|
Packit |
fabffb |
goto done_silent;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (editor->connection);
|
|
Packit |
fabffb |
g_assert (s_con);
|
|
Packit |
fabffb |
if (nm_setting_connection_get_read_only (s_con)) {
|
|
Packit |
fabffb |
validation_error = g_strdup (_("Connection cannot be modified"));
|
|
Packit |
fabffb |
goto done;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!ui_to_setting (editor, &error)) {
|
|
Packit |
fabffb |
validation_error = g_strdup (error->message);
|
|
Packit |
fabffb |
g_clear_error (&error);
|
|
Packit |
fabffb |
goto done;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
recheck_relabel (editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
for (iter = editor->pages; iter; iter = g_slist_next (iter)) {
|
|
Packit |
fabffb |
if (!ce_page_validate (CE_PAGE (iter->data), editor->connection, &error)) {
|
|
Packit |
fabffb |
if (!validation_error) {
|
|
Packit |
fabffb |
validation_error = g_strdup_printf (_("Invalid setting %s: %s"),
|
|
Packit |
fabffb |
CE_PAGE (iter->data)->title,
|
|
Packit |
fabffb |
error->message);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
g_clear_error (&error);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
done:
|
|
Packit |
fabffb |
if (g_strcmp0 (validation_error, editor->last_validation_error) != 0) {
|
|
Packit |
fabffb |
if (editor->last_validation_error && !validation_error)
|
|
Packit |
fabffb |
g_message ("Connection validates and can be saved");
|
|
Packit |
fabffb |
else if (validation_error)
|
|
Packit |
fabffb |
g_message ("Cannot save connection due to error: %s", validation_error);
|
|
Packit |
fabffb |
g_free (editor->last_validation_error);
|
|
Packit |
fabffb |
editor->last_validation_error = g_strdup (validation_error);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
done_silent:
|
|
Packit |
fabffb |
ce_polkit_button_set_validation_error (CE_POLKIT_BUTTON (editor->ok_button), validation_error);
|
|
Packit |
fabffb |
gtk_widget_set_sensitive (editor->export_button, !validation_error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
update_sensitivity (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
ok_button_actionable_cb (GtkWidget *button,
|
|
Packit |
fabffb |
gboolean actionable,
|
|
Packit |
fabffb |
NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
connection_editor_validate (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
permissions_changed_cb (NMClient *client,
|
|
Packit |
fabffb |
NMClientPermission permission,
|
|
Packit |
fabffb |
NMClientPermissionResult result,
|
|
Packit |
fabffb |
NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
if (permission != NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (result == NM_CLIENT_PERMISSION_RESULT_YES || result == NM_CLIENT_PERMISSION_RESULT_AUTH)
|
|
Packit |
fabffb |
editor->can_modify = TRUE;
|
|
Packit |
fabffb |
else
|
|
Packit |
fabffb |
editor->can_modify = FALSE;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
connection_editor_validate (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
destroy_inter_page_item (gpointer data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
nm_connection_editor_init (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GtkWidget *dialog;
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
const char *objects[] = { "nm-connection-editor", "relabel_dialog", "relabel_list", NULL };
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->builder = gtk_builder_new ();
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!gtk_builder_add_objects_from_resource (editor->builder,
|
|
Packit |
fabffb |
"/org/gnome/nm_connection_editor/nm-connection-editor.ui",
|
|
Packit |
fabffb |
(char **) objects,
|
|
Packit |
fabffb |
&error)) {
|
|
Packit |
fabffb |
g_warning ("Couldn't load builder resource " "/org/gnome/nm_connection_editor/nm-connection-editor.ui: %s", error->message);
|
|
Packit |
fabffb |
g_error_free (error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
dialog = gtk_message_dialog_new (NULL, 0,
|
|
Packit |
fabffb |
GTK_MESSAGE_ERROR,
|
|
Packit |
fabffb |
GTK_BUTTONS_OK,
|
|
Packit |
fabffb |
"%s",
|
|
Packit |
fabffb |
_("The connection editor could not find some required resources (the .ui file was not found)."));
|
|
Packit |
fabffb |
gtk_dialog_run (GTK_DIALOG (dialog));
|
|
Packit |
fabffb |
gtk_widget_destroy (dialog);
|
|
Packit |
fabffb |
gtk_main_quit ();
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->window = GTK_WIDGET (gtk_builder_get_object (editor->builder, "nm-connection-editor"));
|
|
Packit |
fabffb |
if (nm_ce_keep_above)
|
|
Packit |
fabffb |
gtk_window_set_keep_above (GTK_WINDOW (editor->window), TRUE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->cancel_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "cancel_button"));
|
|
Packit |
fabffb |
editor->export_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "export_button"));
|
|
Packit |
fabffb |
editor->relabel_info = GTK_WIDGET (gtk_builder_get_object (editor->builder, "relabel_info"));
|
|
Packit |
fabffb |
editor->relabel_dialog = GTK_WIDGET (gtk_builder_get_object (editor->builder, "relabel_dialog"));
|
|
Packit |
fabffb |
editor->relabel_button = GTK_WIDGET (gtk_builder_get_object (editor->builder, "relabel_button"));
|
|
Packit |
fabffb |
editor->relabel_list = GTK_LIST_STORE (gtk_builder_get_object (editor->builder, "relabel_list"));
|
|
Packit |
fabffb |
gtk_builder_add_callback_symbol (editor->builder, "relabel_toggled", G_CALLBACK (relabel_toggled));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_builder_connect_signals (editor->builder, editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->inter_page_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, (GDestroyNotify) destroy_inter_page_item);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
get_secrets_info_free (GetSecretsInfo *info)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_free (info->setting_name);
|
|
Packit |
fabffb |
g_free (info);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
dispose (GObject *object)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor = NM_CONNECTION_EDITOR (object);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->disposed = TRUE;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (active_editors && editor->orig_connection)
|
|
Packit |
fabffb |
g_hash_table_remove (active_editors, editor->orig_connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_slist_free_full (editor->initializing_pages, g_object_unref);
|
|
Packit |
fabffb |
editor->initializing_pages = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_slist_free_full (editor->pages, g_object_unref);
|
|
Packit |
fabffb |
editor->pages = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Mark any in-progress secrets call as canceled; it will clean up after itself. */
|
|
Packit |
fabffb |
if (editor->secrets_call)
|
|
Packit |
fabffb |
editor->secrets_call->canceled = TRUE;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
while (editor->pending_secrets_calls) {
|
|
Packit |
fabffb |
get_secrets_info_free ((GetSecretsInfo *) editor->pending_secrets_calls->data);
|
|
Packit |
fabffb |
editor->pending_secrets_calls = g_slist_delete_link (editor->pending_secrets_calls, editor->pending_secrets_calls);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
nm_clear_g_source (&editor->validate_id);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_clear_object (&editor->connection);
|
|
Packit |
fabffb |
g_clear_object (&editor->orig_connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (editor->window) {
|
|
Packit |
fabffb |
gtk_widget_destroy (editor->window);
|
|
Packit |
fabffb |
editor->window = NULL;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
g_clear_object (&editor->parent_window);
|
|
Packit |
fabffb |
g_clear_object (&editor->builder);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
nm_clear_g_signal_handler (editor->client, &editor->permission_id);
|
|
Packit |
fabffb |
g_clear_object (&editor->client);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_clear_pointer (&editor->last_validation_error, g_free);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (editor->inter_page_hash) {
|
|
Packit |
fabffb |
g_hash_table_destroy (editor->inter_page_hash);
|
|
Packit |
fabffb |
editor->inter_page_hash = NULL;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_slist_free_full (editor->unsupported_properties, g_free);
|
|
Packit |
fabffb |
editor->unsupported_properties = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
G_OBJECT_CLASS (nm_connection_editor_parent_class)->dispose (object);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
nm_connection_editor_class_init (NMConnectionEditorClass *klass)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* virtual methods */
|
|
Packit |
fabffb |
object_class->dispose = dispose;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Signals */
|
|
Packit |
fabffb |
editor_signals[EDITOR_DONE] =
|
|
Packit |
fabffb |
g_signal_new (NM_CONNECTION_EDITOR_DONE,
|
|
Packit |
fabffb |
G_OBJECT_CLASS_TYPE (object_class),
|
|
Packit |
fabffb |
G_SIGNAL_RUN_FIRST,
|
|
Packit |
fabffb |
0, NULL, NULL, NULL,
|
|
Packit |
fabffb |
G_TYPE_NONE, 1, GTK_TYPE_RESPONSE_TYPE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor_signals[NEW_EDITOR] =
|
|
Packit |
fabffb |
g_signal_new (NM_CONNECTION_EDITOR_NEW_EDITOR,
|
|
Packit |
fabffb |
G_OBJECT_CLASS_TYPE (object_class),
|
|
Packit |
fabffb |
G_SIGNAL_RUN_FIRST,
|
|
Packit |
fabffb |
0, NULL, NULL, NULL,
|
|
Packit |
fabffb |
G_TYPE_NONE, 1, G_TYPE_POINTER);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
NMConnectionEditor *
|
|
Packit |
fabffb |
nm_connection_editor_new (GtkWindow *parent_window,
|
|
Packit |
fabffb |
NMConnection *connection,
|
|
Packit |
fabffb |
NMClient *client)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor;
|
|
Packit |
fabffb |
GtkWidget *hbox;
|
|
Packit |
fabffb |
gboolean is_new;
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
is_new = !nm_client_get_connection_by_uuid (client, nm_connection_get_uuid (connection));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor = g_object_new (NM_TYPE_CONNECTION_EDITOR, NULL);
|
|
Packit |
fabffb |
editor->parent_window = parent_window ? g_object_ref (parent_window) : NULL;
|
|
Packit |
fabffb |
editor->client = g_object_ref (client);
|
|
Packit |
fabffb |
editor->is_new_connection = is_new;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->can_modify = nm_client_get_permission_result (client, NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM);
|
|
Packit |
fabffb |
editor->permission_id = g_signal_connect (editor->client,
|
|
Packit |
fabffb |
"permission-changed",
|
|
Packit |
fabffb |
G_CALLBACK (permissions_changed_cb),
|
|
Packit |
fabffb |
editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->ok_button = ce_polkit_button_new (_("_Save"),
|
|
Packit |
fabffb |
_("Save any changes made to this connection."),
|
|
Packit |
fabffb |
_("Authenticate to save this connection for all users of this machine."),
|
|
Packit |
fabffb |
"emblem-ok-symbolic",
|
|
Packit |
fabffb |
client,
|
|
Packit |
fabffb |
NM_CLIENT_PERMISSION_SETTINGS_MODIFY_SYSTEM);
|
|
Packit |
fabffb |
gtk_button_set_use_underline (GTK_BUTTON (editor->ok_button), TRUE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_connect (editor->ok_button, "actionable",
|
|
Packit |
fabffb |
G_CALLBACK (ok_button_actionable_cb), editor);
|
|
Packit |
fabffb |
g_signal_connect (editor->ok_button, "authorized",
|
|
Packit |
fabffb |
G_CALLBACK (ok_button_actionable_cb), editor);
|
|
Packit |
fabffb |
hbox = GTK_WIDGET (gtk_builder_get_object (editor->builder, "action_area_hbox"));
|
|
Packit |
fabffb |
gtk_box_pack_end (GTK_BOX (hbox), editor->ok_button, TRUE, TRUE, 0);
|
|
Packit |
fabffb |
gtk_widget_show_all (editor->ok_button);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!nm_connection_editor_set_connection (editor, connection, &error)) {
|
|
Packit |
fabffb |
nm_connection_editor_error (parent_window,
|
|
Packit |
fabffb |
is_new ? _("Could not create connection") : _("Could not edit connection"),
|
|
Packit |
fabffb |
"%s",
|
|
Packit |
fabffb |
error ? error->message : _("Unknown error creating connection editor dialog."));
|
|
Packit |
fabffb |
g_clear_error (&error);
|
|
Packit |
fabffb |
g_object_unref (editor);
|
|
Packit |
fabffb |
return NULL;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!active_editors)
|
|
Packit |
fabffb |
active_editors = g_hash_table_new_full (NULL, NULL, g_object_unref, NULL);
|
|
Packit |
fabffb |
g_hash_table_insert (active_editors, g_object_ref (connection), editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return editor;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
NMConnectionEditor *
|
|
Packit |
fabffb |
nm_connection_editor_get (NMConnection *connection)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
return active_editors ? g_hash_table_lookup (active_editors, connection) : NULL;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Returns an editor for @slave's master, if any */
|
|
Packit |
fabffb |
NMConnectionEditor *
|
|
Packit |
fabffb |
nm_connection_editor_get_master (NMConnection *slave)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GHashTableIter iter;
|
|
Packit |
fabffb |
gpointer connection, editor;
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
const char *master;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!active_editors)
|
|
Packit |
fabffb |
return NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (slave);
|
|
Packit |
fabffb |
master = nm_setting_connection_get_master (s_con);
|
|
Packit |
fabffb |
if (!master)
|
|
Packit |
fabffb |
return NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_hash_table_iter_init (&iter, active_editors);
|
|
Packit |
fabffb |
while (g_hash_table_iter_next (&iter, &connection, &editor)) {
|
|
Packit |
fabffb |
if (!g_strcmp0 (master, nm_connection_get_uuid (connection)))
|
|
Packit |
fabffb |
return editor;
|
|
Packit |
fabffb |
if (!g_strcmp0 (master, nm_connection_get_interface_name (connection)))
|
|
Packit |
fabffb |
return editor;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return NULL;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
NMConnection *
|
|
Packit |
fabffb |
nm_connection_editor_get_connection (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_val_if_fail (NM_IS_CONNECTION_EDITOR (editor), NULL);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return editor->orig_connection;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
populate_connection_ui (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
GtkWidget *name;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
name = GTK_WIDGET (gtk_builder_get_object (editor->builder, "connection_name"));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (editor->connection);
|
|
Packit |
fabffb |
gtk_entry_set_text (GTK_ENTRY (name), s_con ? nm_setting_connection_get_id (s_con) : NULL);
|
|
Packit |
fabffb |
gtk_widget_set_tooltip_text (name, nm_connection_get_uuid (editor->connection));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_connect_swapped (name, "changed", G_CALLBACK (connection_editor_validate), editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
connection_editor_validate (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
page_changed (CEPage *page, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
GSList *iter;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Do page interdependent changes */
|
|
Packit |
fabffb |
for (iter = editor->pages; iter; iter = g_slist_next (iter))
|
|
Packit |
fabffb |
ce_page_inter_page_change (CE_PAGE (iter->data));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (editor_is_initialized (editor))
|
|
Packit |
fabffb |
nm_connection_editor_inter_page_clear_data (editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
connection_editor_validate (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
idle_validate (gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->validate_id = 0;
|
|
Packit |
fabffb |
connection_editor_validate (editor);
|
|
Packit |
fabffb |
return FALSE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
recheck_initialization (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GtkNotebook *notebook;
|
|
Packit |
fabffb |
GtkLabel *label;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!editor_is_initialized (editor) || editor->init_run)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->init_run = TRUE;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
populate_connection_ui (editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Show the second page (the connection-type-specific data) first */
|
|
Packit |
fabffb |
notebook = GTK_NOTEBOOK (gtk_builder_get_object (editor->builder, "notebook"));
|
|
Packit |
fabffb |
gtk_notebook_set_current_page (notebook, 1);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* When everything is initialized, re-present the window to ensure it's on top */
|
|
Packit |
fabffb |
nm_connection_editor_present (editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Validate the connection from an idle handler to ensure that stuff like
|
|
Packit |
fabffb |
* GtkFileChoosers have had a chance to asynchronously find their files.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
if (editor->validate_id)
|
|
Packit |
fabffb |
g_source_remove (editor->validate_id);
|
|
Packit |
fabffb |
editor->validate_id = g_idle_add (idle_validate, editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (editor->unsupported_properties) {
|
|
Packit |
fabffb |
GString *str;
|
|
Packit |
fabffb |
GSList *iter;
|
|
Packit |
fabffb |
gs_free char *tooltip = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
str = g_string_new ("Unsupported properties: ");
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
for (iter = editor->unsupported_properties; iter; iter = g_slist_next (iter)) {
|
|
Packit |
fabffb |
g_string_append (str, (char *) iter->data);
|
|
Packit |
fabffb |
if (iter->next)
|
|
Packit |
fabffb |
g_string_append (str, ", ");
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
tooltip = g_string_free (str, FALSE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
label = GTK_LABEL (gtk_builder_get_object (editor->builder, "message_label"));
|
|
Packit |
fabffb |
gtk_label_set_text (label,
|
|
Packit |
fabffb |
_("Warning: the connection contains some properties not supported by the editor. "
|
|
Packit |
fabffb |
"They will be cleared upon save."));
|
|
Packit |
fabffb |
gtk_widget_set_tooltip_text (GTK_WIDGET (label), tooltip);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
page_initialized (CEPage *page, GError *error, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *editor = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
GtkWidget *widget, *parent;
|
|
Packit |
fabffb |
GtkNotebook *notebook;
|
|
Packit |
fabffb |
GtkWidget *label;
|
|
Packit |
fabffb |
GList *children, *iter;
|
|
Packit |
fabffb |
gpointer order, child_order;
|
|
Packit |
fabffb |
int i;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (error) {
|
|
Packit |
fabffb |
gtk_widget_hide (editor->window);
|
|
Packit |
fabffb |
nm_connection_editor_error (editor->parent_window,
|
|
Packit |
fabffb |
_("Error initializing editor"),
|
|
Packit |
fabffb |
"%s", error->message);
|
|
Packit |
fabffb |
g_signal_emit (editor, editor_signals[EDITOR_DONE], 0, GTK_RESPONSE_NONE);
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Add the page to the UI */
|
|
Packit |
fabffb |
notebook = GTK_NOTEBOOK (gtk_builder_get_object (editor->builder, "notebook"));
|
|
Packit |
fabffb |
label = gtk_label_new (ce_page_get_title (page));
|
|
Packit |
fabffb |
widget = ce_page_get_page (page);
|
|
Packit |
fabffb |
parent = gtk_widget_get_parent (widget);
|
|
Packit |
fabffb |
if (parent)
|
|
Packit |
fabffb |
gtk_container_remove (GTK_CONTAINER (parent), widget);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
order = g_object_get_data (G_OBJECT (page), ORDER_TAG);
|
|
Packit |
fabffb |
g_object_set_data (G_OBJECT (widget), ORDER_TAG, order);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
children = gtk_container_get_children (GTK_CONTAINER (notebook));
|
|
Packit |
fabffb |
for (iter = children, i = 0; iter; iter = iter->next, i++) {
|
|
Packit |
fabffb |
child_order = g_object_get_data (G_OBJECT (iter->data), ORDER_TAG);
|
|
Packit |
fabffb |
if (child_order > order)
|
|
Packit |
fabffb |
break;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
g_list_free (children);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_notebook_insert_page (notebook, widget, label, i);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (CE_IS_PAGE_VPN (page) && ce_page_vpn_can_export (CE_PAGE_VPN (page)))
|
|
Packit |
fabffb |
gtk_widget_show (editor->export_button);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Move the page from the initializing list to the main page list */
|
|
Packit |
fabffb |
editor->initializing_pages = g_slist_remove (editor->initializing_pages, page);
|
|
Packit |
fabffb |
editor->pages = g_slist_append (editor->pages, page);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
recheck_initialization (editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
page_new_editor (CEPage *page, NMConnectionEditor *new_editor, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *self = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_emit (self, editor_signals[NEW_EDITOR], 0, new_editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void request_secrets (GetSecretsInfo *info);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
get_secrets_cb (GObject *object,
|
|
Packit |
fabffb |
GAsyncResult *result,
|
|
Packit |
fabffb |
gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMRemoteConnection *connection = NM_REMOTE_CONNECTION (object);
|
|
Packit |
fabffb |
GetSecretsInfo *info = user_data;
|
|
Packit |
fabffb |
NMConnectionEditor *self;
|
|
Packit |
fabffb |
GVariant *secrets;
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (info->canceled) {
|
|
Packit |
fabffb |
get_secrets_info_free (info);
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
secrets = nm_remote_connection_get_secrets_finish (connection, result, &error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
self = info->self;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Complete this secrets request; completion can actually dispose of the
|
|
Packit |
fabffb |
* dialog if there was an error.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
self->secrets_call = NULL;
|
|
Packit |
fabffb |
ce_page_complete_init (info->page, info->setting_name, secrets, error);
|
|
Packit |
fabffb |
get_secrets_info_free (info);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Kick off the next secrets request if there is one queued; if the dialog
|
|
Packit |
fabffb |
* was disposed of by the completion above we don't need to do anything.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
if (!self->disposed && self->pending_secrets_calls) {
|
|
Packit |
fabffb |
self->secrets_call = g_slist_nth_data (self->pending_secrets_calls, 0);
|
|
Packit |
fabffb |
self->pending_secrets_calls = g_slist_remove (self->pending_secrets_calls, self->secrets_call);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
request_secrets (self->secrets_call);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
request_secrets (GetSecretsInfo *info)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_if_fail (info != NULL);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
nm_remote_connection_get_secrets_async (NM_REMOTE_CONNECTION (info->self->orig_connection),
|
|
Packit |
fabffb |
info->setting_name, NULL, get_secrets_cb, info);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
get_secrets_for_page (NMConnectionEditor *self,
|
|
Packit |
fabffb |
CEPage *page,
|
|
Packit |
fabffb |
const char *setting_name)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GetSecretsInfo *info;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
info = g_malloc0 (sizeof (GetSecretsInfo));
|
|
Packit |
fabffb |
info->self = self;
|
|
Packit |
fabffb |
info->page = page;
|
|
Packit |
fabffb |
info->setting_name = g_strdup (setting_name);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* PolicyKit doesn't queue up authorization requests internally. Instead,
|
|
Packit |
fabffb |
* if there's a pending authorization request, subsequent requests for that
|
|
Packit |
fabffb |
* same authorization will return NotAuthorized+Challenge. That's pretty
|
|
Packit |
fabffb |
* inconvenient and it would be a lot nicer if PK just queued up subsequent
|
|
Packit |
fabffb |
* authorization requests and executed them when the first one was finished.
|
|
Packit |
fabffb |
* But it since it doesn't do that, we have to serialize the authorization
|
|
Packit |
fabffb |
* requests ourselves to get the right authorization result.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
/* NOTE: PolicyKit-gnome 0.95 now serializes auth requests as of this commit:
|
|
Packit |
fabffb |
* http://git.gnome.org/cgit/PolicyKit-gnome/commit/?id=f32cb7faa7197b9db55b569677732742c3c7fdc1
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* If there's already an in-progress call, queue up the new one */
|
|
Packit |
fabffb |
if (self->secrets_call)
|
|
Packit |
fabffb |
self->pending_secrets_calls = g_slist_append (self->pending_secrets_calls, info);
|
|
Packit |
fabffb |
else {
|
|
Packit |
fabffb |
/* Request secrets for this page */
|
|
Packit |
fabffb |
self->secrets_call = info;
|
|
Packit |
fabffb |
request_secrets (info);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
add_page (NMConnectionEditor *editor,
|
|
Packit |
fabffb |
CEPageNewFunc func,
|
|
Packit |
fabffb |
NMConnection *connection,
|
|
Packit |
fabffb |
GError **error)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
CEPage *page;
|
|
Packit |
fabffb |
const char *secrets_setting_name = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_return_val_if_fail (editor != NULL, FALSE);
|
|
Packit |
fabffb |
g_return_val_if_fail (func != NULL, FALSE);
|
|
Packit |
fabffb |
g_return_val_if_fail (connection != NULL, FALSE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
page = (*func) (editor, connection, GTK_WINDOW (editor->window), editor->client,
|
|
Packit |
fabffb |
&secrets_setting_name, error);
|
|
Packit |
fabffb |
if (page) {
|
|
Packit |
fabffb |
g_object_set_data_full (G_OBJECT (page),
|
|
Packit |
fabffb |
SECRETS_TAG,
|
|
Packit |
fabffb |
g_strdup (secrets_setting_name),
|
|
Packit |
fabffb |
g_free);
|
|
Packit |
fabffb |
g_object_set_data (G_OBJECT (page),
|
|
Packit |
fabffb |
ORDER_TAG,
|
|
Packit |
fabffb |
GINT_TO_POINTER (g_slist_length (editor->initializing_pages)));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->initializing_pages = g_slist_append (editor->initializing_pages, page);
|
|
Packit |
fabffb |
g_signal_connect (page, CE_PAGE_CHANGED, G_CALLBACK (page_changed), editor);
|
|
Packit |
fabffb |
g_signal_connect (page, CE_PAGE_INITIALIZED, G_CALLBACK (page_initialized), editor);
|
|
Packit |
fabffb |
g_signal_connect (page, CE_PAGE_NEW_EDITOR, G_CALLBACK (page_new_editor), editor);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
return !!page;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_add_unsupported_property (NMConnectionEditor *editor, const char *name)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
editor->unsupported_properties = g_slist_append (editor->unsupported_properties, g_strdup (name));
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_check_unsupported_properties (NMConnectionEditor *editor,
|
|
Packit |
fabffb |
NMSetting *setting,
|
|
Packit |
fabffb |
const char * const *known_props)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
gs_free GParamSpec **property_specs = NULL;
|
|
Packit |
fabffb |
GParamSpec *prop_spec;
|
|
Packit |
fabffb |
guint n_property_specs;
|
|
Packit |
fabffb |
guint i;
|
|
Packit |
fabffb |
char tmp[1024];
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!setting)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
property_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (setting),
|
|
Packit |
fabffb |
&n_property_specs);
|
|
Packit |
fabffb |
for (i = 0; i < n_property_specs; i++) {
|
|
Packit |
fabffb |
prop_spec = property_specs[i];
|
|
Packit |
fabffb |
if ( !g_strv_contains (known_props, prop_spec->name)
|
|
Packit |
fabffb |
&& !nm_streq0 (prop_spec->name, NM_SETTING_NAME)) {
|
|
Packit |
fabffb |
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_value_init (&value, prop_spec->value_type);
|
|
Packit |
fabffb |
g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
|
|
Packit |
fabffb |
if (!g_param_value_defaults (prop_spec, &value)) {
|
|
Packit |
fabffb |
nm_sprintf_buf (tmp, "%s.%s", nm_setting_get_name (setting), prop_spec->name);
|
|
Packit |
fabffb |
nm_connection_editor_add_unsupported_property (editor, tmp);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
nm_connection_editor_set_connection (NMConnectionEditor *editor,
|
|
Packit |
fabffb |
NMConnection *orig_connection,
|
|
Packit |
fabffb |
GError **error)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMSettingConnection *s_con;
|
|
Packit |
fabffb |
const char *connection_type;
|
|
Packit |
fabffb |
const char *slave_type;
|
|
Packit |
fabffb |
gboolean success = FALSE;
|
|
Packit |
fabffb |
GSList *iter, *copy;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_return_val_if_fail (NM_IS_CONNECTION_EDITOR (editor), FALSE);
|
|
Packit |
fabffb |
g_return_val_if_fail (NM_IS_CONNECTION (orig_connection), FALSE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* clean previous connection */
|
|
Packit |
fabffb |
if (editor->connection)
|
|
Packit |
fabffb |
g_object_unref (editor->connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->connection = nm_simple_connection_new_clone (orig_connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
editor->orig_connection = g_object_ref (orig_connection);
|
|
Packit |
fabffb |
nm_connection_editor_update_title (editor);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Handle CA cert ignore stuff */
|
|
Packit |
fabffb |
eap_method_ca_cert_ignore_load (editor->connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
s_con = nm_connection_get_setting_connection (editor->connection);
|
|
Packit |
fabffb |
g_assert (s_con);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
connection_type = nm_setting_connection_get_connection_type (s_con);
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_general_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!strcmp (connection_type, NM_SETTING_WIRED_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_ethernet_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_8021x_security_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_dcb_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_WIRELESS_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_wifi_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_wifi_security_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_VPN_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_vpn_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_IP_TUNNEL_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_ip_tunnel_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_PPPOE_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_dsl_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_ppp_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_GSM_SETTING_NAME) ||
|
|
Packit |
fabffb |
!strcmp (connection_type, NM_SETTING_CDMA_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_mobile_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_ppp_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_BLUETOOTH_SETTING_NAME)) {
|
|
Packit |
fabffb |
NMSettingBluetooth *s_bt = nm_connection_get_setting_bluetooth (editor->connection);
|
|
Packit |
fabffb |
const char *type = nm_setting_bluetooth_get_connection_type (s_bt);
|
|
Packit |
fabffb |
g_assert (type);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_bluetooth_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!g_strcmp0 (type, "dun")) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_mobile_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_ppp_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_INFINIBAND_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_infiniband_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_BOND_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_bond_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_TEAM_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_team_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_bridge_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_VLAN_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_vlan_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!strcmp (connection_type, NM_SETTING_MACSEC_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_macsec_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_8021x_security_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit Service |
639700 |
} else if (!strcmp (connection_type, NM_SETTING_WIREGUARD_SETTING_NAME)) {
|
|
Packit Service |
639700 |
if (!add_page (editor, ce_page_wireguard_new, editor->connection, error))
|
|
Packit Service |
639700 |
goto out;
|
|
Packit |
fabffb |
} else {
|
|
Packit |
fabffb |
g_warning ("Unhandled setting type '%s'", connection_type);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
slave_type = nm_setting_connection_get_slave_type (s_con);
|
|
Packit |
fabffb |
if (!g_strcmp0 (slave_type, NM_SETTING_TEAM_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_team_port_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
} else if (!g_strcmp0 (slave_type, NM_SETTING_BRIDGE_SETTING_NAME)) {
|
|
Packit |
fabffb |
if (!add_page (editor, ce_page_bridge_port_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if ( nm_connection_get_setting_proxy (editor->connection)
|
|
Packit |
fabffb |
&& !add_page (editor, ce_page_proxy_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if ( nm_connection_get_setting_ip4_config (editor->connection)
|
|
Packit |
fabffb |
&& !add_page (editor, ce_page_ip4_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
if ( nm_connection_get_setting_ip6_config (editor->connection)
|
|
Packit |
fabffb |
&& !add_page (editor, ce_page_ip6_new, editor->connection, error))
|
|
Packit |
fabffb |
goto out;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* After all pages are created, then kick off secrets requests that any
|
|
Packit |
fabffb |
* the pages may need to make; if they don't need any secrets, then let
|
|
Packit |
fabffb |
* them finish initialization. The list might get modified during the loop
|
|
Packit |
fabffb |
* which is why copy the list here.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
copy = g_slist_copy (editor->initializing_pages);
|
|
Packit |
fabffb |
for (iter = copy; iter; iter = g_slist_next (iter)) {
|
|
Packit |
fabffb |
CEPage *page = CE_PAGE (iter->data);
|
|
Packit |
fabffb |
const char *setting_name = g_object_get_data (G_OBJECT (page), SECRETS_TAG);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (!setting_name) {
|
|
Packit |
fabffb |
/* page doesn't need any secrets */
|
|
Packit |
fabffb |
ce_page_complete_init (page, NULL, NULL, NULL);
|
|
Packit |
fabffb |
} else if (!NM_IS_REMOTE_CONNECTION (editor->orig_connection)) {
|
|
Packit |
fabffb |
/* We want to get secrets using ->orig_connection, since that's the
|
|
Packit |
fabffb |
* remote connection which can actually respond to secrets requests.
|
|
Packit |
fabffb |
* ->connection is a plain NMConnection copy of ->orig_connection
|
|
Packit |
fabffb |
* which is what gets changed when users modify anything. But when
|
|
Packit |
fabffb |
* creating or importing, ->orig_connection will be an NMConnection
|
|
Packit |
fabffb |
* since the new connection hasn't been added to NetworkManager yet.
|
|
Packit |
fabffb |
* So basically, skip requesting secrets if the connection can't
|
|
Packit |
fabffb |
* handle a secrets request.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
ce_page_complete_init (page, setting_name, NULL, NULL);
|
|
Packit |
fabffb |
} else {
|
|
Packit |
fabffb |
/* Page wants secrets, get them */
|
|
Packit |
fabffb |
get_secrets_for_page (editor, page, setting_name);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
g_object_set_data (G_OBJECT (page), SECRETS_TAG, NULL);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
g_slist_free (copy);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* set the UI */
|
|
Packit |
fabffb |
recheck_initialization (editor);
|
|
Packit |
fabffb |
success = TRUE;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
out:
|
|
Packit |
fabffb |
return success;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_present (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_if_fail (NM_IS_CONNECTION_EDITOR (editor));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_window_present (GTK_WINDOW (editor->window));
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
cancel_button_clicked_cb (GtkWidget *widget, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *self = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* If the dialog is busy waiting for authorization or something,
|
|
Packit |
fabffb |
* don't destroy it until authorization returns.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
if (self->busy)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_emit (self, editor_signals[EDITOR_DONE], 0, GTK_RESPONSE_CANCEL);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
editor_closed_cb (GtkWidget *widget, GdkEvent *event, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
cancel_button_clicked_cb (widget, user_data);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static gboolean
|
|
Packit |
fabffb |
key_press_cb (GtkWidget *widget, GdkEventKey *event, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
if (event->keyval == GDK_KEY_Escape) {
|
|
Packit |
fabffb |
gtk_window_close (GTK_WINDOW (widget));
|
|
Packit |
fabffb |
return TRUE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return FALSE;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
added_connection_cb (GObject *client,
|
|
Packit |
fabffb |
GAsyncResult *result,
|
|
Packit |
fabffb |
gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *self = user_data;
|
|
Packit |
fabffb |
NMRemoteConnection *connection;
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
nm_connection_editor_set_busy (self, FALSE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
connection = nm_client_add_connection_finish (NM_CLIENT (client), result, &error);
|
|
Packit |
fabffb |
if (error) {
|
|
Packit |
fabffb |
nm_connection_editor_error (self->parent_window, _("Connection add failed"),
|
|
Packit |
fabffb |
"%s", error->message);
|
|
Packit |
fabffb |
/* Leave the editor open */
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
g_clear_object (&connection);
|
|
Packit |
fabffb |
g_clear_error (&error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_emit (self, editor_signals[EDITOR_DONE], 0, GTK_RESPONSE_OK);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
update_complete (NMConnectionEditor *self, GError *error)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
nm_connection_editor_set_busy (self, FALSE);
|
|
Packit |
fabffb |
g_signal_emit (self, editor_signals[EDITOR_DONE], 0, GTK_RESPONSE_OK);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
updated_connection_cb (GObject *connection,
|
|
Packit |
fabffb |
GAsyncResult *result,
|
|
Packit |
fabffb |
gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *self = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
nm_remote_connection_commit_changes_finish (NM_REMOTE_CONNECTION (connection),
|
|
Packit |
fabffb |
result, &error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Clear secrets so they don't lay around in memory; they'll get requested
|
|
Packit |
fabffb |
* again anyway next time the connection is edited.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
nm_connection_clear_secrets (NM_CONNECTION (connection));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
update_complete (self, error);
|
|
Packit |
fabffb |
g_clear_error (&error);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
ok_button_clicked_save_connection (NMConnectionEditor *self)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
/* Copy the modified connection to the original connection */
|
|
Packit |
fabffb |
nm_connection_replace_settings_from_connection (self->orig_connection,
|
|
Packit |
fabffb |
self->connection);
|
|
Packit |
fabffb |
nm_connection_editor_set_busy (self, TRUE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Save new CA cert ignore values to GSettings */
|
|
Packit |
fabffb |
eap_method_ca_cert_ignore_save (self->connection);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (self->is_new_connection) {
|
|
Packit |
fabffb |
nm_client_add_connection_async (self->client,
|
|
Packit |
fabffb |
self->orig_connection,
|
|
Packit |
fabffb |
TRUE,
|
|
Packit |
fabffb |
NULL,
|
|
Packit |
fabffb |
added_connection_cb,
|
|
Packit |
fabffb |
self);
|
|
Packit |
fabffb |
} else {
|
|
Packit |
fabffb |
nm_remote_connection_commit_changes_async (NM_REMOTE_CONNECTION (self->orig_connection),
|
|
Packit |
fabffb |
TRUE, NULL, updated_connection_cb, self);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
ok_button_clicked_cb (GtkWidget *widget, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *self = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
GSList *iter;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* If the dialog is busy waiting for authorization or something,
|
|
Packit |
fabffb |
* don't destroy it until authorization returns.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
if (self->busy)
|
|
Packit |
fabffb |
return;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Validate one last time to ensure all pages update the connection */
|
|
Packit |
fabffb |
connection_editor_validate (self);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* Perform page specific actions before the connection is saved */
|
|
Packit |
fabffb |
for (iter = self->pages; iter; iter = g_slist_next (iter))
|
|
Packit |
fabffb |
ce_page_last_update (CE_PAGE (iter->data), self->connection, NULL);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
ok_button_clicked_save_connection (self);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
vpn_export_get_secrets_cb (GObject *object,
|
|
Packit |
fabffb |
GAsyncResult *result,
|
|
Packit |
fabffb |
gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnection *tmp;
|
|
Packit |
fabffb |
GVariant *secrets;
|
|
Packit |
fabffb |
GError *error = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
secrets = nm_remote_connection_get_secrets_finish (NM_REMOTE_CONNECTION (object),
|
|
Packit |
fabffb |
result, &error);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
/* We don't really care about errors; if the user couldn't authenticate
|
|
Packit |
fabffb |
* then just let them export everything except secrets. Duplicate the
|
|
Packit |
fabffb |
* connection so that we don't let secrets sit around in the original
|
|
Packit |
fabffb |
* one.
|
|
Packit |
fabffb |
*/
|
|
Packit |
fabffb |
tmp = nm_simple_connection_new_clone (NM_CONNECTION (object));
|
|
Packit |
fabffb |
g_assert (tmp);
|
|
Packit |
fabffb |
if (secrets)
|
|
Packit |
fabffb |
nm_connection_update_secrets (tmp, NM_SETTING_VPN_SETTING_NAME, secrets, NULL);
|
|
Packit |
fabffb |
vpn_export (tmp);
|
|
Packit |
fabffb |
g_object_unref (tmp);
|
|
Packit |
fabffb |
if (secrets)
|
|
Packit |
fabffb |
g_variant_ref (secrets);
|
|
Packit |
fabffb |
g_clear_error (&error);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
export_button_clicked_cb (GtkWidget *widget, gpointer user_data)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
NMConnectionEditor *self = NM_CONNECTION_EDITOR (user_data);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (NM_IS_REMOTE_CONNECTION (self->orig_connection)) {
|
|
Packit |
fabffb |
/* Grab secrets if we can */
|
|
Packit |
fabffb |
nm_remote_connection_get_secrets_async (NM_REMOTE_CONNECTION (self->orig_connection),
|
|
Packit |
fabffb |
NM_SETTING_VPN_SETTING_NAME,
|
|
Packit |
fabffb |
NULL,
|
|
Packit |
fabffb |
vpn_export_get_secrets_cb,
|
|
Packit |
fabffb |
self);
|
|
Packit |
fabffb |
} else
|
|
Packit |
fabffb |
vpn_export (self->connection);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_run (NMConnectionEditor *self)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_if_fail (NM_IS_CONNECTION_EDITOR (self));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_connect (G_OBJECT (self->window), "delete-event",
|
|
Packit |
fabffb |
G_CALLBACK (editor_closed_cb), self);
|
|
Packit |
fabffb |
g_signal_connect (G_OBJECT (self->window), "key-press-event",
|
|
Packit |
fabffb |
G_CALLBACK (key_press_cb), self);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
g_signal_connect (G_OBJECT (self->ok_button), "clicked",
|
|
Packit |
fabffb |
G_CALLBACK (ok_button_clicked_cb), self);
|
|
Packit |
fabffb |
g_signal_connect (G_OBJECT (self->cancel_button), "clicked",
|
|
Packit |
fabffb |
G_CALLBACK (cancel_button_clicked_cb), self);
|
|
Packit |
fabffb |
g_signal_connect (G_OBJECT (self->export_button), "clicked",
|
|
Packit |
fabffb |
G_CALLBACK (export_button_clicked_cb), self);
|
|
Packit |
fabffb |
g_signal_connect (G_OBJECT (self->relabel_button), "clicked",
|
|
Packit |
fabffb |
G_CALLBACK (relabel_button_clicked_cb), self);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
nm_connection_editor_present (self);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
GtkWindow *
|
|
Packit |
fabffb |
nm_connection_editor_get_window (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_val_if_fail (NM_IS_CONNECTION_EDITOR (editor), NULL);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return GTK_WINDOW (editor->window);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gboolean
|
|
Packit |
fabffb |
nm_connection_editor_get_busy (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_val_if_fail (NM_IS_CONNECTION_EDITOR (editor), FALSE);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
return editor->busy;
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_set_busy (NMConnectionEditor *editor, gboolean busy)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_return_if_fail (NM_IS_CONNECTION_EDITOR (editor));
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
if (busy != editor->busy) {
|
|
Packit |
fabffb |
editor->busy = busy;
|
|
Packit |
fabffb |
gtk_widget_set_sensitive (editor->window, !busy);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
static void
|
|
Packit |
fabffb |
nm_connection_editor_dialog (GtkWindow *parent, GtkMessageType type, const char *heading,
|
|
Packit |
fabffb |
const char *message)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
GtkWidget *dialog;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
dialog = gtk_message_dialog_new (parent,
|
|
Packit |
fabffb |
GTK_DIALOG_DESTROY_WITH_PARENT,
|
|
Packit |
fabffb |
type,
|
|
Packit |
fabffb |
GTK_BUTTONS_CLOSE,
|
|
Packit |
fabffb |
"%s", heading);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", message);
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gtk_widget_show_all (dialog);
|
|
Packit |
fabffb |
gtk_window_present (GTK_WINDOW (dialog));
|
|
Packit |
fabffb |
gtk_dialog_run (GTK_DIALOG (dialog));
|
|
Packit |
fabffb |
gtk_widget_destroy (dialog);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_error (GtkWindow *parent, const char *heading, const char *format, ...)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
va_list args;
|
|
Packit |
fabffb |
gs_free char *message = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
va_start (args, format);
|
|
Packit |
fabffb |
message = g_strdup_vprintf (format, args);
|
|
Packit |
fabffb |
va_end (args);
|
|
Packit |
fabffb |
nm_connection_editor_dialog (parent, GTK_MESSAGE_ERROR, heading, message);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_warning (GtkWindow *parent, const char *heading, const char *format, ...)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
va_list args;
|
|
Packit |
fabffb |
gs_free char *message = NULL;
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
va_start (args, format);
|
|
Packit |
fabffb |
message = g_strdup_vprintf (format, args);
|
|
Packit |
fabffb |
va_end (args);
|
|
Packit |
fabffb |
nm_connection_editor_dialog (parent, GTK_MESSAGE_WARNING, heading, message);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_inter_page_set_value (NMConnectionEditor *editor, InterPageChangeType type, gpointer value)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_hash_table_insert (editor->inter_page_hash, GUINT_TO_POINTER (type), value);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
gboolean
|
|
Packit |
fabffb |
nm_connection_editor_inter_page_get_value (NMConnectionEditor *editor, InterPageChangeType type, gpointer *value)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
return g_hash_table_lookup_extended (editor->inter_page_hash, GUINT_TO_POINTER (type), NULL, value);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|
|
Packit |
fabffb |
void
|
|
Packit |
fabffb |
nm_connection_editor_inter_page_clear_data (NMConnectionEditor *editor)
|
|
Packit |
fabffb |
{
|
|
Packit |
fabffb |
g_hash_table_remove_all (editor->inter_page_hash);
|
|
Packit |
fabffb |
}
|
|
Packit |
fabffb |
|