// SPDX-License-Identifier: GPL-2.0+ /* NetworkManager Applet -- allow user control over networking * * Dan Williams * * Copyright 2008 - 2017 Red Hat, Inc. * Copyright 2008 Novell, Inc. */ #include "nm-default.h" #include "applet.h" #include "applet-device-ethernet.h" #include "ethernet-dialog.h" #define DEFAULT_ETHERNET_NAME _("Auto Ethernet") static gboolean ethernet_new_auto_connection (NMDevice *device, gpointer dclass_data, AppletNewAutoConnectionCallback callback, gpointer callback_data) { NMConnection *connection; NMSettingWired *s_wired = NULL; NMSettingConnection *s_con; char *uuid; connection = nm_simple_connection_new (); s_wired = NM_SETTING_WIRED (nm_setting_wired_new ()); nm_connection_add_setting (connection, NM_SETTING (s_wired)); s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); uuid = nm_utils_uuid_generate (); g_object_set (s_con, NM_SETTING_CONNECTION_ID, DEFAULT_ETHERNET_NAME, NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRED_SETTING_NAME, NM_SETTING_CONNECTION_AUTOCONNECT, TRUE, NM_SETTING_CONNECTION_UUID, uuid, NULL); g_free (uuid); nm_connection_add_setting (connection, NM_SETTING (s_con)); (*callback) (connection, TRUE, FALSE, callback_data); return TRUE; } static void ethernet_add_menu_item (NMDevice *device, gboolean multiple_devices, const GPtrArray *connections, NMConnection *active, GtkWidget *menu, NMApplet *applet) { char *text; GtkWidget *item; gboolean carrier = TRUE; if (multiple_devices) { const char *desc; desc = nm_device_get_description (device); if (connections->len > 1) text = g_strdup_printf (_("Ethernet Networks (%s)"), desc); else text = g_strdup_printf (_("Ethernet Network (%s)"), desc); } else { if (connections->len > 1) text = g_strdup (_("Ethernet Networks")); else text = g_strdup (_("Ethernet Network")); } item = applet_menu_item_create_device_item_helper (device, applet, text); g_free (text); /* Only dim the item if the device supports carrier detection AND * we know it doesn't have a link. */ if (nm_device_get_capabilities (device) & NM_DEVICE_CAP_CARRIER_DETECT) carrier = nm_device_ethernet_get_carrier (NM_DEVICE_ETHERNET (device)); gtk_widget_set_sensitive (item, FALSE); gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); if (connections->len) applet_add_connection_items (device, connections, carrier, active, NMA_ADD_ACTIVE, menu, applet); /* Notify user of unmanaged or unavailable device */ item = nma_menu_device_get_menu_item (device, applet, carrier ? NULL : _("disconnected")); if (item) { gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); gtk_widget_show (item); } if (!nma_menu_device_check_unusable (device)) { if ((!active && connections->len) || (active && connections->len > 1)) applet_menu_item_add_complex_separator_helper (menu, applet, _("Available")); if (connections->len) applet_add_connection_items (device, connections, carrier, active, NMA_ADD_INACTIVE, menu, applet); else applet_add_default_connection_item (device, DEFAULT_ETHERNET_NAME, carrier, menu, applet); } } static void ethernet_notify_connected (NMDevice *device, const char *msg, NMApplet *applet) { applet_do_notify_with_pref (applet, _("Connection Established"), msg ? msg : _("You are now connected to the ethernet network."), "nm-device-wired", PREF_DISABLE_CONNECTED_NOTIFICATIONS); } static void ethernet_get_icon (NMDevice *device, NMDeviceState state, NMConnection *connection, GdkPixbuf **out_pixbuf, const char **out_icon_name, char **tip, NMApplet *applet) { NMSettingConnection *s_con; const char *id; g_return_if_fail (out_icon_name && !*out_icon_name); g_return_if_fail (tip && !*tip); id = nm_device_get_iface (NM_DEVICE (device)); if (connection) { s_con = nm_connection_get_setting_connection (connection); id = nm_setting_connection_get_id (s_con); } switch (state) { case NM_DEVICE_STATE_PREPARE: *tip = g_strdup_printf (_("Preparing ethernet network connection “%s”…"), id); break; case NM_DEVICE_STATE_CONFIG: *tip = g_strdup_printf (_("Configuring ethernet network connection “%s”…"), id); break; case NM_DEVICE_STATE_NEED_AUTH: *tip = g_strdup_printf (_("User authentication required for ethernet network connection “%s”…"), id); break; case NM_DEVICE_STATE_IP_CONFIG: *tip = g_strdup_printf (_("Requesting an ethernet network address for “%s”…"), id); break; case NM_DEVICE_STATE_ACTIVATED: *out_icon_name = "nm-device-wired"; *tip = g_strdup_printf (_("Ethernet network connection “%s” active"), id); break; default: break; } } /* PPPoE */ typedef struct { SecretsRequest req; GtkWidget *dialog; GtkEntry *username_entry; GtkEntry *service_entry; GtkEntry *password_entry; GtkWidget *ok_button; } NMPppoeInfo; static void pppoe_verify (GtkEditable *editable, gpointer user_data) { NMPppoeInfo *info = (NMPppoeInfo *) user_data; const char *s; gboolean valid = TRUE; s = gtk_entry_get_text (info->username_entry); if (!s || strlen (s) < 1) valid = FALSE; if (valid) { s = gtk_entry_get_text (info->password_entry); if (!s || strlen (s) < 1) valid = FALSE; } gtk_widget_set_sensitive (info->ok_button, valid); } static void pppoe_update_setting (NMSettingPppoe *pppoe, NMPppoeInfo *info) { const char *s; s = gtk_entry_get_text (info->service_entry); if (s && strlen (s) < 1) s = NULL; g_object_set (pppoe, NM_SETTING_PPPOE_USERNAME, gtk_entry_get_text (info->username_entry), NM_SETTING_PPPOE_PASSWORD, gtk_entry_get_text (info->password_entry), NM_SETTING_PPPOE_SERVICE, s, NULL); } static void pppoe_update_ui (NMConnection *connection, NMPppoeInfo *info) { NMSettingPppoe *s_pppoe; const char *s; g_return_if_fail (NM_IS_CONNECTION (connection)); g_return_if_fail (info != NULL); s_pppoe = nm_connection_get_setting_pppoe (connection); g_return_if_fail (s_pppoe != NULL); s = nm_setting_pppoe_get_username (s_pppoe); if (s) gtk_entry_set_text (info->username_entry, s); s = nm_setting_pppoe_get_service (s_pppoe); if (s) gtk_entry_set_text (info->service_entry, s); s = nm_setting_pppoe_get_password (s_pppoe); if (s) gtk_entry_set_text (info->password_entry, s); } static void free_pppoe_info (SecretsRequest *req) { NMPppoeInfo *info = (NMPppoeInfo *) req; if (info->dialog) { gtk_widget_hide (info->dialog); gtk_widget_destroy (info->dialog); } } static void get_pppoe_secrets_cb (GtkDialog *dialog, gint response, gpointer user_data) { SecretsRequest *req = user_data; NMPppoeInfo *info = (NMPppoeInfo *) req; NMSettingPppoe *setting; GVariant *secrets = NULL; GError *error = NULL; if (response != GTK_RESPONSE_OK) { g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED, "%s.%d (%s): canceled", __FILE__, __LINE__, __func__); goto done; } setting = nm_connection_get_setting_pppoe (req->connection); pppoe_update_setting (setting, info); secrets = nm_connection_to_dbus (req->connection, NM_CONNECTION_SERIALIZE_ONLY_SECRETS); if (!secrets) { g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, "%s.%d (%s): failed to hash setting " NM_SETTING_PPPOE_SETTING_NAME, __FILE__, __LINE__, __func__); } done: applet_secrets_request_complete (req, secrets, error); applet_secrets_request_free (req); if (secrets) g_variant_unref (secrets); } static void show_password_toggled (GtkToggleButton *button, gpointer user_data) { NMPppoeInfo *info = (NMPppoeInfo *) user_data; if (gtk_toggle_button_get_active (button)) gtk_entry_set_visibility (GTK_ENTRY (info->password_entry), TRUE); else gtk_entry_set_visibility (GTK_ENTRY (info->password_entry), FALSE); } static gboolean pppoe_get_secrets (SecretsRequest *req, GError **error) { NMPppoeInfo *info = (NMPppoeInfo *) req; GtkWidget *w; GtkBuilder* builder; GError *tmp_error = NULL; builder = gtk_builder_new (); if (!gtk_builder_add_from_resource (builder, "/org/freedesktop/network-manager-applet/connection-editor/ce-page-dsl.ui", &tmp_error)) { g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, "%s.%d (%s): couldn't display secrets UI: %s", __FILE__, __LINE__, __func__, tmp_error->message); g_error_free (tmp_error); return FALSE; } applet_secrets_request_set_free_func (req, free_pppoe_info); info->username_entry = GTK_ENTRY (gtk_builder_get_object (builder, "dsl_username")); g_signal_connect (info->username_entry, "changed", G_CALLBACK (pppoe_verify), info); info->service_entry = GTK_ENTRY (gtk_builder_get_object (builder, "dsl_service")); info->password_entry = GTK_ENTRY (gtk_builder_get_object (builder, "dsl_password")); g_signal_connect (info->password_entry, "changed", G_CALLBACK (pppoe_verify), info); /* Create the dialog */ info->dialog = gtk_dialog_new (); gtk_window_set_title (GTK_WINDOW (info->dialog), _("DSL authentication")); gtk_window_set_modal (GTK_WINDOW (info->dialog), TRUE); gtk_dialog_add_button (GTK_DIALOG (info->dialog), _("_Cancel"), GTK_RESPONSE_REJECT); w = gtk_dialog_add_button (GTK_DIALOG (info->dialog), _("_OK"), GTK_RESPONSE_OK); info->ok_button = w; gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (info->dialog))), GTK_WIDGET (gtk_builder_get_object (builder, "DslPage")), TRUE, TRUE, 0); pppoe_update_ui (req->connection, info); w = GTK_WIDGET (gtk_builder_get_object (builder, "dsl_show_password")); g_signal_connect (w, "toggled", G_CALLBACK (show_password_toggled), info); g_signal_connect (info->dialog, "response", G_CALLBACK (get_pppoe_secrets_cb), info); gtk_window_set_position (GTK_WINDOW (info->dialog), GTK_WIN_POS_CENTER_ALWAYS); gtk_widget_realize (info->dialog); gtk_window_present (GTK_WINDOW (info->dialog)); return TRUE; } /* 802.1x */ typedef struct { SecretsRequest req; GtkWidget *dialog; } NM8021xInfo; static void free_8021x_info (SecretsRequest *req) { NM8021xInfo *info = (NM8021xInfo *) req; if (info->dialog) { gtk_widget_hide (info->dialog); gtk_widget_destroy (info->dialog); } } static void get_8021x_secrets_cb (GtkDialog *dialog, gint response, gpointer user_data) { SecretsRequest *req = user_data; NM8021xInfo *info = (NM8021xInfo *) req; NMConnection *connection = NULL; NMSetting *setting; GError *error = NULL; if (response != GTK_RESPONSE_OK) { g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_USER_CANCELED, "%s.%d (%s): canceled", __FILE__, __LINE__, __func__); goto done; } connection = nma_ethernet_dialog_get_connection (info->dialog); if (!connection) { g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, "%s.%d (%s): couldn't get connection from ethernet dialog.", __FILE__, __LINE__, __func__); goto done; } setting = nm_connection_get_setting (connection, NM_TYPE_SETTING_802_1X); if (setting) { nm_connection_add_setting (req->connection, g_object_ref (setting)); } else { g_set_error (&error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, "%s.%d (%s): requested setting '802-1x' didn't" " exist in the connection.", __FILE__, __LINE__, __func__); } done: applet_secrets_request_complete_setting (req, NM_SETTING_802_1X_SETTING_NAME, error); applet_secrets_request_free (req); g_clear_error (&error); } static gboolean nm_8021x_get_secrets (SecretsRequest *req, GError **error) { NM8021xInfo *info = (NM8021xInfo *) req; applet_secrets_request_set_free_func (req, free_8021x_info); info->dialog = nma_ethernet_dialog_new (g_object_ref (req->connection)); if (!info->dialog) { g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, "%s.%d (%s): couldn't display secrets UI", __FILE__, __LINE__, __func__); return FALSE; } g_signal_connect (info->dialog, "response", G_CALLBACK (get_8021x_secrets_cb), info); gtk_window_set_position (GTK_WINDOW (info->dialog), GTK_WIN_POS_CENTER_ALWAYS); gtk_widget_realize (info->dialog); gtk_window_present (GTK_WINDOW (info->dialog)); return TRUE; } static gboolean ethernet_get_secrets (SecretsRequest *req, GError **error) { NMSettingConnection *s_con; const char *ctype; s_con = nm_connection_get_setting_connection (req->connection); if (!s_con) { g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_INVALID_CONNECTION, "%s.%d (%s): Invalid connection", __FILE__, __LINE__, __func__); return FALSE; } ctype = nm_setting_connection_get_connection_type (s_con); if (!strcmp (ctype, NM_SETTING_WIRED_SETTING_NAME)) return nm_8021x_get_secrets (req, error); else if (!strcmp (ctype, NM_SETTING_PPPOE_SETTING_NAME)) return pppoe_get_secrets (req, error); else { g_set_error (error, NM_SECRET_AGENT_ERROR, NM_SECRET_AGENT_ERROR_FAILED, "%s.%d (%s): unhandled ethernet connection type '%s'", __FILE__, __LINE__, __func__, ctype); } return FALSE; } NMADeviceClass * applet_device_ethernet_get_class (NMApplet *applet) { NMADeviceClass *dclass; dclass = g_slice_new0 (NMADeviceClass); if (!dclass) return NULL; dclass->new_auto_connection = ethernet_new_auto_connection; dclass->add_menu_item = ethernet_add_menu_item; dclass->notify_connected = ethernet_notify_connected; dclass->get_icon = ethernet_get_icon; dclass->get_secrets = ethernet_get_secrets; dclass->secrets_request_size = MAX (sizeof (NM8021xInfo), sizeof (NMPppoeInfo)); return dclass; }