From 7d67dbbb889a754c71a878fa69fcf2aa18fcdbb7 Mon Sep 17 00:00:00 2001 From: Marek Marczykowski Date: Fri, 19 Oct 2018 08:02:11 +0200 Subject: [PATCH] anaconda: do not start network during install, set default hostname and write minimal network configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Frédéric Pierret --- pyanaconda/network.py | 14 +- pyanaconda/ui/gui/spokes/network.py | 1750 ----------------------------------- 2 files changed, 8 insertions(+), 1756 deletions(-) delete mode 100644 pyanaconda/ui/gui/spokes/network.py diff --git a/pyanaconda/network.py b/pyanaconda/network.py index b92fb8acf..5d3dcd604 100644 --- a/pyanaconda/network.py +++ b/pyanaconda/network.py @@ -54,7 +54,7 @@ networkConfFile = "%s/network" % (sysconfigDir) hostnameFile = "/etc/hostname" ipv6ConfFile = "/etc/sysctl.d/anaconda.conf" ifcfgLogFile = "/tmp/ifcfg.log" -DEFAULT_HOSTNAME = "localhost.localdomain" +DEFAULT_HOSTNAME = "dom0" ifcfglog = None @@ -1191,24 +1191,26 @@ def write_sysconfig_network(rootpath, overwrite=False): with open(cfgfile, "w") as f: f.write("# Created by anaconda\n") + f.write("NETWORKING=no\n") return True def write_network_config(storage, ksdata, instClass, rootpath): # overwrite previous settings for LiveCD or liveimg installations overwrite = flags.livecdInstall or ksdata.method.method == "liveimg" - write_hostname(rootpath, ksdata, overwrite=overwrite) + write_hostname(rootpath, ksdata, overwrite=flags.livecdInstall) if ksdata.network.hostname != DEFAULT_HOSTNAME: set_hostname(ksdata.network.hostname) - write_sysconfig_network(rootpath, overwrite=overwrite) + write_sysconfig_network(rootpath, overwrite=flags.livecdInstall) disableIPV6(rootpath) copyIfcfgFiles(rootpath) copyDhclientConfFiles(rootpath) copyFileToPath("/etc/resolv.conf", rootpath, overwrite=overwrite) - instClass.setNetworkOnbootDefault(ksdata) - autostartFCoEDevices(rootpath, storage, ksdata) -def update_hostname_data(ksdata, hostname): +def update_hostname_data(ksdata, hostname=None): + if not hostname: + # Default to 'dom0' in Qubes + hostname = 'dom0' log.debug("updating host name %s", hostname) hostname_found = False for nd in ksdata.network.network: diff --git a/pyanaconda/ui/gui/spokes/network.py b/pyanaconda/ui/gui/spokes/network.py deleted file mode 100644 index a15a07ccb..000000000 --- a/pyanaconda/ui/gui/spokes/network.py +++ /dev/null @@ -1,1750 +0,0 @@ -# Network configuration spoke classes -# -# Copyright (C) 2011 Red Hat, Inc. -# -# This copyrighted material is made available to anyone wishing to use, -# modify, copy, or redistribute it subject to the terms and conditions of -# the GNU General Public License v.2, or (at your option) any later version. -# This program is distributed in the hope that it will be useful, but WITHOUT -# ANY WARRANTY expressed or implied, including the implied warranties of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General -# Public License for more details. You should have received a copy of the -# GNU General Public License along with this program; if not, write to the -# Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA -# 02110-1301, USA. Any Red Hat trademarks that are incorporated in the -# source code or documentation are not subject to the GNU General Public -# License and may only be used or replicated with the express permission of -# Red Hat, Inc. -# - -import gi -gi.require_version("Gtk", "3.0") -gi.require_version("GLib", "2.0") -gi.require_version("GObject", "2.0") -gi.require_version("Pango", "1.0") -gi.require_version("Gio", "2.0") -gi.require_version("NM", "1.0") - -from gi.repository import Gtk -from gi.repository import GLib, GObject, Pango, Gio, NM - -from pyanaconda.flags import can_touch_runtime_system -from pyanaconda.i18n import _, N_, C_, CN_ -from pyanaconda.flags import flags as anaconda_flags -from pyanaconda.ui.communication import hubQ -from pyanaconda.ui.gui import GUIObject -from pyanaconda.ui.gui.spokes import NormalSpoke, StandaloneSpoke -from pyanaconda.ui.categories.system import SystemCategory -from pyanaconda.ui.gui.hubs.summary import SummaryHub -from pyanaconda.ui.gui.utils import gtk_call_once, escape_markup, really_hide, really_show -from pyanaconda.ui.common import FirstbootSpokeMixIn -from pyanaconda.iutil import startProgram -from pyanaconda.constants import ANACONDA_ENVIRON - -from pyanaconda import network -from pyanaconda import nm - -import dbus -import dbus.service -# Used for ascii_letters and hexdigits constants -import string # pylint: disable=deprecated-module -from uuid import uuid4 - -from dbus.mainloop.glib import DBusGMainLoop -DBusGMainLoop(set_as_default=True) - -import logging -log = logging.getLogger("anaconda") - -NM._80211ApFlags = getattr(NM, "80211ApFlags") -NM._80211ApSecurityFlags = getattr(NM, "80211ApSecurityFlags") -NM._80211Mode = getattr(NM, "80211Mode") - -NM_SERVICE = "org.freedesktop.NetworkManager" -NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION = 0x1 -SECRET_AGENT_IFACE = 'org.freedesktop.NetworkManager.SecretAgent' -AGENT_MANAGER_IFACE = 'org.freedesktop.NetworkManager.AgentManager' -AGENT_MANAGER_PATH = "/org/freedesktop/NetworkManager/AgentManager" - -IPV4_CONFIG = "IPv4" -IPV6_CONFIG = "IPv6" - -DEVICES_COLUMN_TITLE = 2 -DEVICES_COLUMN_OBJECT = 3 - -nmclient = NM.Client.new() - -def localized_string_of_device_state(device, state): - s = _("Status unknown (missing)") - - if state == NM.DeviceState.UNKNOWN: - s = _("Status unknown") - elif state == NM.DeviceState.UNMANAGED: - s = _("Unmanaged") - elif state == NM.DeviceState.UNAVAILABLE: - if not device: - s = _("Unavailable") - elif device.get_firmware_missing(): - s = _("Firmware missing") - else: - s = _("Unavailable") - elif state == NM.DeviceState.DISCONNECTED: - if (device and device.get_device_type() == NM.DeviceType.ETHERNET - and not device.get_carrier()): - s = _("Cable unplugged") - else: - s = _("Disconnected") - elif state in (NM.DeviceState.PREPARE, - NM.DeviceState.CONFIG, - NM.DeviceState.IP_CONFIG, - NM.DeviceState.IP_CHECK): - s = _("Connecting") - elif state == NM.DeviceState.NEED_AUTH: - s = _("Authentication required") - elif state == NM.DeviceState.ACTIVATED: - s = _("Connected") - elif state == NM.DeviceState.DEACTIVATING: - s = _("Disconnecting") - elif state == NM.DeviceState.FAILED: - s = _("Connection failed") - - return s - -__all__ = ["NetworkSpoke", "NetworkStandaloneSpoke"] - -class CellRendererSignal(Gtk.CellRendererPixbuf): - - __gtype_name__ = "CellRendererSignal" - __gproperties__ = { - "signal": (GObject.TYPE_UINT, - "Signal", "Signal", - 0, GObject.G_MAXUINT, 0, - GObject.PARAM_READWRITE), - } - - def __init__(self): - Gtk.CellRendererPixbuf.__init__(self) - self.signal = 0 - - - def do_get_property(self, prop): - if prop.name == 'signal': - return self.signal - else: - raise AttributeError('unknown property %s' % prop.name) - - def do_set_property(self, prop, value): - if prop.name == 'signal': - self.signal = value - self._set_icon_name(value) - else: - raise AttributeError('unknown property %s' % prop.name) - - def _set_icon_name(self, value): - - if value == 0: - self.set_property("gicon", None) - - if value < 20: - icon_name = "network-wireless-signal-none-symbolic" - elif value < 40: - icon_name = "network-wireless-signal-weak-symbolic" - elif value < 50: - icon_name = "network-wireless-signal-ok-symbolic" - elif value < 80: - icon_name = "network-wireless-signal-good-symbolic" - else: - icon_name = "network-wireless-signal-excellent-symbolic" - - icon = Gio.ThemedIcon.new_with_default_fallbacks(icon_name) - self.set_property("gicon", icon) - - -NM_AP_SEC_UNKNOWN = 0 -NM_AP_SEC_NONE = 1 -NM_AP_SEC_WEP = 2 -NM_AP_SEC_WPA = 3 -NM_AP_SEC_WPA2 = 4 - -class CellRendererSecurity(Gtk.CellRendererPixbuf): - - __gtype_name__ = "CellRendererSecurity" - __gproperties__ = { - "security": (GObject.TYPE_UINT, - "Security", "Security", - 0, GObject.G_MAXUINT, 0, - GObject.PARAM_READWRITE), - } - - def __init__(self): - Gtk.CellRendererPixbuf.__init__(self) - self.security = NM_AP_SEC_UNKNOWN - self.icon_name = "" - - def do_get_property(self, prop): - if prop.name == 'security': - return self.security - else: - raise AttributeError('unknown property %s' % prop.name) - - def do_set_property(self, prop, value): - if prop.name == 'security': - self.security = value - self._set_icon_name(value) - else: - raise AttributeError('unknown property %s' % prop.name) - - def _set_icon_name(self, security): - self.icon_name = "" - if security not in (NM_AP_SEC_NONE, NM_AP_SEC_UNKNOWN): - self.icon_name = "network-wireless-encrypted-symbolic" - - self.set_property("icon-name", self.icon_name) - -class DeviceConfiguration(object): - - setting_types = { - '802-11-wireless': NM.DeviceType.WIFI, - '802-3-ethernet': NM.DeviceType.ETHERNET, - 'vlan': NM.DeviceType.VLAN, - 'bond': NM.DeviceType.BOND, - 'team': NM.DeviceType.TEAM, - 'bridge': NM.DeviceType.BRIDGE, - } - - def __init__(self, device=None, con=None): - self.device = device - self.con = con - - def get_device_type(self): - if self.device: - return self.device.get_device_type() - elif self.con: - return self.setting_types.get(self.con.get_connection_type(), None) - else: - return None - - def get_iface(self): - iface = None - if self.device: - iface = self.device.get_iface() - elif self.con: - iface = self.con.get_setting_connection().get_interface_name() - wired_setting = self.con.get_setting_wired() - if not iface and wired_setting: - mac = wired_setting.get_mac_address() - if mac: - iface = nm.nm_hwaddr_to_device_name(mac) - return iface - - def get_uuid(self): - return self.con and self.con.get_uuid() - -class NetworkControlBox(GObject.GObject): - - __gsignals__ = { - "nm-state-changed": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, []), - "device-state-changed": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, [str, int, int, int]), - "apply-hostname": (GObject.SIGNAL_RUN_LAST, GObject.TYPE_NONE, []), - } - - supported_device_types = [ - NM.DeviceType.ETHERNET, - NM.DeviceType.WIFI, - NM.DeviceType.TEAM, - NM.DeviceType.BOND, - NM.DeviceType.VLAN, - NM.DeviceType.BRIDGE, - ] - - wired_ui_device_types = [ - NM.DeviceType.ETHERNET, - NM.DeviceType.TEAM, - NM.DeviceType.BOND, - NM.DeviceType.VLAN, - NM.DeviceType.BRIDGE, - ] - - device_type_sort_value = { - NM.DeviceType.ETHERNET : "1", - NM.DeviceType.WIFI : "2", - } - - device_type_name = { - NM.DeviceType.UNKNOWN: N_("Unknown"), - NM.DeviceType.ETHERNET: N_("Ethernet"), - NM.DeviceType.WIFI: N_("Wireless"), - NM.DeviceType.BOND: N_("Bond"), - NM.DeviceType.VLAN: N_("VLAN"), - NM.DeviceType.TEAM: N_("Team"), - NM.DeviceType.BRIDGE: N_("Bridge"), - } - - def __init__(self, builder, client, spoke=None): - - GObject.GObject.__init__(self) - - self.builder = builder - self._running_nmce = None - self.spoke = spoke - self.client = client - - # button for creating of virtual bond and vlan devices - self.builder.get_object("add_toolbutton").set_sensitive(True) - self.builder.get_object("add_toolbutton").connect("clicked", - self.on_add_device_clicked) - self.builder.get_object("remove_toolbutton").set_sensitive(False) - self.builder.get_object("remove_toolbutton").connect("clicked", - self.on_remove_device_clicked) - - not_supported = ["start_hotspot_button", - "stop_hotspot_button", - "heading_hotspot_network_name", - "heading_hotspot_security_key", - "label_hotspot_network_name", - "label_hotspot_security_key", - "hbox54", - ] - - do_not_show_in_refresh = ["heading_wireless_network_name", - "combobox_wireless_network_name"] - do_not_show_in_refresh += ["%s_%s_%s" % (widget, ty, value) - for widget in ["heading", "label"] - for ty in ["wired", "wireless"] - for value in ["ipv4", "ipv6", "dns", "route"]] - do_not_show_in_refresh += ["%s_wired_%s" % (widget, value) - for widget in ["heading", "label"] - for value in ["slaves", "vlanid", "parent"]] - - for ident in not_supported + do_not_show_in_refresh: - self.builder.get_object(ident).set_no_show_all(True) - self.builder.get_object(ident).hide() - - self.builder.get_object("notebook_types").set_show_tabs(False) - - # to prevent UI update signals races - self._updating_device = False - - # devices list - # limited to wired and wireless - treeview = self.builder.get_object("treeview_devices") - self._add_device_columns(treeview) - self.dev_cfg_store = self.builder.get_object("liststore_devices") - self.dev_cfg_store.set_sort_column_id(2, Gtk.SortType.ASCENDING) - selection = treeview.get_selection() - selection.set_mode(Gtk.SelectionMode.BROWSE) - selection.connect("changed", self.on_device_selection_changed) - - # wireless APs list - combobox = self.builder.get_object("combobox_wireless_network_name") - self._add_ap_icons(combobox) - model = combobox.get_model() - model.set_sort_column_id(2, Gtk.SortType.ASCENDING) - combobox.connect("changed", self.on_wireless_ap_changed_cb) - self.selected_ap = None - - self.builder.get_object("device_wired_off_switch").connect("notify::active", - self.on_device_off_toggled) - self.builder.get_object("device_wireless_off_switch").connect("notify::active", - self.on_device_off_toggled) - self.builder.get_object("button_wired_options").connect("clicked", - self.on_edit_connection) - self.builder.get_object("button_wireless_options").connect("clicked", - self.on_edit_connection) - self.entry_hostname = self.builder.get_object("entry_hostname") - self.label_current_hostname = self.builder.get_object("label_current_hostname") - self.button_apply_hostname = self.builder.get_object("button_apply_hostname") - self.button_apply_hostname.connect("clicked", self.on_apply_hostname) - - @property - def vbox(self): - return self.builder.get_object("networkControlBox_vbox") - - - def _add_ap_icons(self, combobox): - cell = CellRendererSecurity() - cell.set_padding(4, 0) - combobox.pack_start(cell, False) - combobox.add_attribute(cell, "security", 5) - - cell = CellRendererSignal() - cell.set_padding(4, 0) - #cell.set_property("xalign", 1.0) - combobox.pack_start(cell, False) - combobox.add_attribute(cell, "signal", 3) - - def _add_device_columns(self, treeview): - rnd = Gtk.CellRendererPixbuf() - rnd.set_property("stock-size", Gtk.IconSize.DND) - # TODO Gtk3 icon-name? (also at other places) - col = Gtk.TreeViewColumn("Icon", rnd, **{"icon-name":0}) - treeview.append_column(col) - - rnd = Gtk.CellRendererText() - rnd.set_property("wrap-mode", Pango.WrapMode.WORD) - col = Gtk.TreeViewColumn("Text", rnd, markup=2) - col.set_sort_column_id(2) - col.set_expand(True) - treeview.append_column(col) - - def add_connection_to_list(self, con): - uuid = con.get_uuid() - if self.dev_cfg(uuid=uuid): - log.debug("network: GUI, not adding connection %s, already in list", uuid) - return False - con_setting = con.get_setting_connection() - if con_setting and con_setting.get_read_only(): - log.debug("network: GUI, not adding read-only connection %s", uuid) - return False - dev_cfg = DeviceConfiguration(con=con) - if network.is_libvirt_device(dev_cfg.get_iface() or ""): - log.debug("network: GUI, not adding %s", dev_cfg.get_iface()) - return False - if network.is_ibft_configured_device(dev_cfg.get_iface() or ""): - log.debug("network: GUI, not adding %s configured from iBFT", dev_cfg.get_iface()) - return False - if dev_cfg.get_device_type() not in self.supported_device_types: - log.debug("network: GUI, not adding connection %s of unsupported type", uuid) - return False - if dev_cfg.get_device_type() == NM.DeviceType.ETHERNET: - if con_setting and con_setting.get_master(): - log.debug("network: GUI, not adding slave connection %s", uuid) - return False - # Wireless settings are handled in scope of its device's dev_cfg - if dev_cfg.get_device_type() == NM.DeviceType.WIFI: - log.debug("network: GUI, not adding wireless connection %s", uuid) - return False - existing_dev_cfg = self.dev_cfg(iface=dev_cfg.get_iface()) - if existing_dev_cfg: - if existing_dev_cfg.con: - log.debug("network: GUI, not adding connection %s, already have %s for device %s", - uuid, existing_dev_cfg.get_uuid(), existing_dev_cfg.device.get_iface()) - return False - else: - log.debug("network: GUI, attaching connection %s to device %s", - uuid, existing_dev_cfg.device.get_iface()) - existing_dev_cfg.con = con - else: - log.debug("network: GUI, adding connection %s", uuid) - self.add_dev_cfg(dev_cfg) - return True - - def initialize(self): - self.client.connect("device-added", self.on_device_added) - self.client.connect("device-removed", self.on_device_removed) - self.client.connect("connection-added", self.on_connection_added) - self.client.connect("notify::%s" % NM.CLIENT_WIRELESS_ENABLED, - self.on_wireless_enabled) - self.client.connect("notify::%s" % NM.CLIENT_STATE, - self.on_nm_state_changed) - - for device in self.client.get_devices(): - self.add_device_to_list(device) - - for con in self.client.get_connections(): - self.add_connection_to_list(con) - - # select the first device - treeview = self.builder.get_object("treeview_devices") - selection = treeview.get_selection() - itr = self.dev_cfg_store.get_iter_first() - if itr: - selection.select_iter(itr) - - def refresh(self): - self.refresh_ui() - - # Signal handlers. - def on_nm_state_changed(self, *args): - self.emit("nm-state-changed") - - def on_device_selection_changed(self, *args): - self.refresh_ui() - - def on_device_state_changed(self, device, new_state, *args): - self.emit("device-state-changed", device.get_iface(), new_state, *args) - if new_state == NM.DeviceState.SECONDARIES: - return - self._refresh_carrier_info() - dev_cfg = self.selected_dev_cfg() - if dev_cfg and dev_cfg.device == device: - self.refresh_ui(state=new_state) - - def on_device_config_changed(self, device, *args): - dev_cfg = self.selected_dev_cfg() - if dev_cfg and dev_cfg.device == device: - self.refresh_ui() - - def on_wireless_ap_changed_cb(self, combobox, *args): - if self._updating_device: - return - itr = combobox.get_active_iter() - if not itr: - return - - dev_cfg = self.selected_dev_cfg() - if not dev_cfg: - return - - device = dev_cfg.device - - ap, ssid_target = combobox.get_model().get(itr, 0, 1) - self.selected_ap = ap - - log.info("network: selected access point: %s", ssid_target) - - cons = ap.filter_connections(device.filter_connections(self.client.get_connections())) - if cons: - con = cons[0] - self.client.activate_connection_async(con, device, ap.get_path(), None) - else: - if self._ap_is_enterprise(ap): - # Create a connection for the ap and [Configure] it later with nm-c-e - con = NM.SimpleConnection.new() - s_con = NM.SettingConnection.new() - s_con.set_property('uuid', str(uuid4())) - s_con.set_property('id', ssid_target) - s_con.set_property('type', '802-11-wireless') - s_wireless = NM.SettingWireless.new() - s_wireless.set_property('ssid', ap.get_ssid()) - s_wireless.set_property('mode', 'infrastructure') - log.debug("network: adding connection for WPA-Enterprise AP %s", ssid_target) - con.add_setting(s_con) - con.add_setting(s_wireless) - persistent = True - self.client.add_connection_async(con, persistent, None) - self.builder.get_object("button_wireless_options").set_sensitive(True) - else: - self.client.add_and_activate_connection_async(None, device, ap.get_path(), None) - - def on_connection_added(self, client, connection): - self.add_connection_to_list(connection) - - def on_device_added(self, client, device, *args): - # We need to wait for valid state before adding the device to our list - if device.get_state() == NM.DeviceState.UNKNOWN: - device.connect("state-changed", self.on_added_device_state_changed) - else: - self.add_device_to_list(device) - - def on_added_device_state_changed(self, device, new_state, *args): - # We need to wait for valid state before adding the device to our list - if new_state != NM.DeviceState.UNKNOWN: - device.disconnect_by_func(self.on_added_device_state_changed) - self.add_device_to_list(device) - - def on_device_removed(self, client, device, *args): - self.remove_device(device) - - def _find_first_ap_setting(self, device, ap): - for con in device.filter_connections(self.client.get_connections()): - wireless_setting = con.get_setting_wireless() - if not wireless_setting or not wireless_setting.get_ssid(): - # setting is None or non-broadcast AP, we ignore these - return - if wireless_setting.get_ssid().get_data() == ap.get_ssid().get_data(): - return con - - def on_edit_connection(self, *args): - dev_cfg = self.selected_dev_cfg() - if not dev_cfg: - return - - device = dev_cfg.device - con = dev_cfg.con - activate = None - ssid = "" - - if dev_cfg.get_device_type() == NM.DeviceType.WIFI: - if not self.selected_ap: - return - ssid = self.selected_ap.get_ssid().get_data() - con = self._find_first_ap_setting(device, self.selected_ap) - if not con: - log.debug("network: on_edit_connection: connection for ap %s not found", self.selected_ap) - return - # 871132 auto activate wireless connection after editing if it is not - # already activated (assume entering secrets) - condition = lambda: self.selected_ap != device.get_active_access_point() - activate = (con, device, condition) - else: - if not con: - log.debug("network: on_edit_connection: connection for device %s not found", device.get_iface()) - if dev_cfg.get_device_type() == NM.DeviceType.ETHERNET: - # Create default connection for the device and run nm-c-e on it - default_con = self._default_eth_con(device.get_iface(), autoconnect=False) - persistent = False - log.info("network: creating new connection for %s device", dev_cfg.get_iface()) - self.client.add_connection_async(default_con, persistent, None, - self._default_connection_added_cb, activate) - return - - if device and device.get_state() == NM.DeviceState.ACTIVATED: - # Reactivate the connection after configuring it (if it changed) - settings = con.to_dbus(NM.ConnectionSerializationFlags.ALL) - settings_changed = lambda: settings != con.to_dbus(NM.ConnectionSerializationFlags.ALL) - activate = (con, device, settings_changed) - - log.info("network: configuring connection %s device %s ssid %s", - con.get_uuid(), dev_cfg.get_iface(), ssid) - self._run_nmce(con.get_uuid(), activate) - - def _default_connection_added_cb(self, client, result, activate): - con = client.add_connection_finish(result) - uuid = con.get_setting_connection().get_uuid() - log.info("network: configuring new connection %s", uuid) - self._run_nmce(uuid, activate) - - def _run_nmce(self, uuid, activate): - self.kill_nmce(msg="Configure button clicked") - proc = startProgram(["nm-connection-editor", "--keep-above", "--edit", "%s" % uuid], reset_lang=False) - self._running_nmce = proc - - GLib.child_watch_add(proc.pid, self.on_nmce_exited, activate) - - def _default_eth_con(self, iface, autoconnect): - con = NM.SimpleConnection.new() - s_con = NM.SettingConnection.new() - s_con.set_property('uuid', str(uuid4())) - s_con.set_property('id', iface) - s_con.set_property('interface-name', iface) - s_con.set_property('autoconnect', autoconnect) - s_con.set_property('type', '802-3-ethernet') - s_wired = NM.SettingWired.new() - con.add_setting(s_con) - con.add_setting(s_wired) - return con - - def kill_nmce(self, msg=""): - if not self._running_nmce: - return False - - log.debug("network: killing running nm-c-e %s: %s", self._running_nmce.pid, msg) - self._running_nmce.kill() - self._running_nmce = None - return True - - def on_nmce_exited(self, pid, condition, activate=None): - # waitpid() has been called, make sure we don't do anything else with the proc - self._running_nmce = None - log.debug("nm-c-e exited with status %s", condition) - - # nm-c-e was closed normally, not killed by anaconda - if condition == 0: - if activate: - # The default of None confuses pylint - con, device, activate_condition = activate # pylint: disable=unpacking-non-sequence - if activate_condition(): - gtk_call_once(self._activate_connection_cb, con, device) - network.logIfcfgFiles("nm-c-e run") - - def _activate_connection_cb(self, con, device): - self.client.activate_connection_async(con, device, None, None) - if self.spoke: - self.spoke.networking_changed = True - - def on_wireless_enabled(self, *args): - switch = self.builder.get_object("device_wireless_off_switch") - self._updating_device = True - switch.set_active(self.client.wireless_get_enabled()) - self._updating_device = False - - def on_device_off_toggled(self, switch, *args): - if self._updating_device: - return - - active = switch.get_active() - dev_cfg = self.selected_dev_cfg() - if not dev_cfg: - return - device = dev_cfg.device - con = dev_cfg.con - - log.info("network: device %s switched %s", dev_cfg.get_iface(), "on" if active else "off") - - if dev_cfg.get_device_type() == NM.DeviceType.WIFI: - self.client.wireless_set_enabled(active) - else: - if active: - if not con: - log.debug("network: on_device_off_toggled: no connection for %s", - dev_cfg.get_iface()) - return - - self.client.activate_connection_async(con, device, None, None) - else: - if not device: - log.debug("network: on_device_off_toggled: no device for %s", dev_cfg.get_iface()) - return - device.disconnect(None) - - if self.spoke: - self.spoke.networking_changed = True - - def on_add_device_clicked(self, *args): - dialog = self.builder.get_object("add_device_dialog") - with self.spoke.main_window.enlightbox(dialog): - rc = dialog.run() - dialog.hide() - if rc == 1: - ai = self.builder.get_object("combobox_add_device").get_active_iter() - model = self.builder.get_object("liststore_add_device") - dev_type = model[ai][1] - self.add_device(dev_type) - - def on_remove_device_clicked(self, *args): - selection = self.builder.get_object("treeview_devices").get_selection() - model, itr = selection.get_selected() - if not itr: - return None - dev_cfg = model[itr][DEVICES_COLUMN_OBJECT] - model.remove(itr) - if dev_cfg.con: - dev_cfg.con.delete() - - def on_apply_hostname(self, *args): - self.emit("apply-hostname") - - def add_device(self, ty): - log.info("network: adding device of type %s", ty) - self.kill_nmce(msg="Add device button clicked") - proc = startProgram(["nm-connection-editor", "--keep-above", "--create", "--type=%s" % ty], reset_lang=False) - self._running_nmce = proc - - GLib.child_watch_add(proc.pid, self.on_nmce_exited) - - def selected_dev_cfg(self): - selection = self.builder.get_object("treeview_devices").get_selection() - model, itr = selection.get_selected() - if not itr: - return None - return model[itr][DEVICES_COLUMN_OBJECT] - - def add_dev_cfg(self, dev_cfg): - log.debug("network: GUI, device configuration added: connection %s device %s", - dev_cfg.get_uuid(), dev_cfg.get_iface()) - self.dev_cfg_store.append([ - self._dev_icon_name(dev_cfg), - self.device_type_sort_value.get(dev_cfg.get_device_type(), "100"), - self._dev_title(dev_cfg), - dev_cfg - ]) - - def add_device_to_list(self, device): - if device.get_device_type() not in self.supported_device_types: - return - if network.is_libvirt_device(device.get_iface()): - log.debug("network: not adding %s", device.get_iface()) - return - # ignore fcoe vlan devices - # (can be chopped off to IFNAMSIZ kernel limit) - if device.get_iface().endswith(('-fcoe', '-fco', '-fc', '-f', '-')): - return - if network.is_ibft_configured_device(device.get_iface() or ""): - log.debug("network: not adding connection for device %s configured from iBFT", device.get_iface()) - return False - - # Ignore devices with active read-only connections (created by NM for iBFT VLAN) - ac = device.get_active_connection() - if ac: - rc = ac.get_connection() - # Getting of NMRemoteConnection can fail (None), isn't it a bug in NM? - if rc: - con_setting = rc.get_setting_connection() - if con_setting and con_setting.get_read_only(): - log.debug("network: not adding read-only connection " - "(assuming iBFT) for device %s", device.get_iface()) - return - else: - log.debug("network: can't get remote connection of active connection " - "of device %s", device.get_iface()) - - # Find the connection for the device (assuming existence of single ifcfg actually) - con = None - # Wifi connections are stored in wifi tab combobox - if device.get_device_type() != NM.DeviceType.WIFI: - cons = device.get_available_connections() - for c in cons: - if c.get_setting_connection() and not c.get_setting_connection().get_slave_type(): - con = c - if len(cons) != 1: - log.warning("network: %s has unexpected number of connections: %s", - device.get_iface(), [c.get_uuid() for c in cons]) - - if con and self.dev_cfg(uuid=con.get_uuid()): - # If we already have a connection for the device - # it is a virtual device appearing - self.dev_cfg(uuid=con.get_uuid()).device = device - # it might be too late for the callbacks below so refresh now - self.refresh_ui() - else: - self.add_dev_cfg(DeviceConfiguration(device=device, con=con)) - - device.connect("notify::ip4-config", self.on_ip_obj_changed, IPV4_CONFIG) - device.connect("notify::ip6-config", self.on_ip_obj_changed, IPV6_CONFIG) - device.connect("state-changed", self.on_device_state_changed) - - def on_ip_obj_changed(self, device, *args): - """Callback when ipX-config objects will be changed. - - Register callback on properties (IP address, gateway...) of these ipX-config - objects when they are created. - """ - log.debug("network: %s object changed", args[1]) - self.on_device_config_changed(device) - if args[1] == IPV4_CONFIG: - config = device.props.ip4_config - else: - config = device.props.ip6_config - - if config: - # register callback when inner NMIP[4,6]Config object changed - config.connect("notify::addresses", self.on_config_changed, device) - config.connect("notify::gateway", self.on_config_changed, device) - config.connect("notify::nameservers", self.on_config_changed, device) - - def on_config_changed(self, config, *args): - """Callback on property change of ipX-config objects. - - Call method which show changed properties (IP, gateway...) to an user. - """ - self.on_device_config_changed(args[1]) - - def _dev_icon_name(self, dev_cfg): - icon_name = "" - if dev_cfg.get_device_type() in self.wired_ui_device_types: - if dev_cfg.device: - if dev_cfg.device.get_state() == NM.DeviceState.UNAVAILABLE: - icon_name = "network-wired-disconnected" - else: - icon_name = "network-wired" - else: - icon_name = "network-wired-disconnected" - elif dev_cfg.get_device_type() == NM.DeviceType.WIFI: - icon_name = "network-wireless" - - return icon_name - - def _dev_title(self, dev_cfg): - unplugged = '' - - if dev_cfg.device: - if (dev_cfg.device.get_state() == NM.DeviceState.UNAVAILABLE - and dev_cfg.device.get_device_type() == NM.DeviceType.ETHERNET - and not dev_cfg.device.get_carrier()): - # TRANSLATORS: ethernet cable is unplugged - unplugged = ', %s' % escape_markup(_("unplugged")) - # pylint: disable=unescaped-markup - title = '%s (%s%s)' % \ - (escape_markup(_(self.device_type_name.get(dev_cfg.get_device_type(), ""))), - escape_markup(dev_cfg.get_iface()), - unplugged) - - if dev_cfg.device: - title += '\n%s %s' % \ - (escape_markup(dev_cfg.device.get_vendor() or ""), - escape_markup(dev_cfg.device.get_product() or "")) - return title - - def dev_cfg(self, uuid=None, device=None, iface=None): - for row in self.dev_cfg_store: - dev_cfg = row[DEVICES_COLUMN_OBJECT] - if uuid: - if dev_cfg.get_uuid() != uuid: - continue - if device: - if not dev_cfg.device \ - or dev_cfg.device.get_udi() != device.get_udi(): - continue - if iface: - if not dev_cfg.device \ - or dev_cfg.device.get_iface() != iface: - continue - return dev_cfg - return None - - def remove_device(self, device): - # This should not concern wifi and ethernet devices, - # just virtual devices e.g. vpn probably - log.debug("network: GUI, device removed: %s", device.get_iface()) - if self.spoke: - self.spoke.networking_changed = True - dev_cfg = self.dev_cfg(device=device) - if dev_cfg: - dev_cfg.device = None - - def refresh_ui(self, state=None): - - dev_cfg = self.selected_dev_cfg() - if not dev_cfg: - # the list is empty (no supported devices) - notebook = self.builder.get_object("notebook_types") - notebook.set_current_page(5) - return - - self._refresh_device_type_page(dev_cfg.get_device_type()) - self._refresh_header_ui(dev_cfg, state) - self._refresh_slaves(dev_cfg) - self._refresh_parent_vlanid(dev_cfg) - self._refresh_speed_hwaddr(dev_cfg, state) - self._refresh_ap(dev_cfg, state) - self._refresh_device_cfg(dev_cfg) - - def _refresh_device_cfg(self, dev_cfg): - - if dev_cfg.get_device_type() in self.wired_ui_device_types: - dt = "wired" - elif dev_cfg.get_device_type() == NM.DeviceType.WIFI: - dt = "wireless" - - if dev_cfg.device: - ipv4cfg = dev_cfg.device.get_ip4_config() - ipv6cfg = dev_cfg.device.get_ip6_config() - else: - ipv4cfg = ipv6cfg = None - - if ipv4cfg: - addr_str = ",".join("%s/%d" % (a.get_address(), a.get_prefix()) - for a in ipv4cfg.get_addresses()) - gateway_str = ipv4cfg.get_gateway() - dnss_str = ",".join(ipv4cfg.get_nameservers()) - else: - addr_str = dnss_str = gateway_str = None - self._set_device_info_value(dt, "ipv4", addr_str) - self._set_device_info_value(dt, "dns", dnss_str) - self._set_device_info_value(dt, "route", gateway_str) - - addr6_str = "" - if ipv6cfg: - addr6_str = ",".join("%s/%d" % (a.get_address(), a.get_prefix()) - for a in ipv6cfg.get_addresses() - # Do not display link-local addresses - if not a.get_address().startswith("fe80:")) - self._set_device_info_value(dt, "ipv6", addr6_str.strip() or None) - - if ipv4cfg and addr6_str: - self.builder.get_object("heading_%s_ipv4" % dt).set_label(_("IPv4 Address")) - self.builder.get_object("heading_%s_ipv6" % dt).set_label(_("IPv6 Address")) - elif ipv4cfg: - self.builder.get_object("heading_%s_ipv4" % dt).set_label(_("IP Address")) - elif addr6_str: - self.builder.get_object("heading_%s_ipv6" % dt).set_label(_("IP Address")) - - return False - - def _refresh_ap(self, dev_cfg, state=None): - if dev_cfg.get_device_type() != NM.DeviceType.WIFI: - return - - if state is None: - state = dev_cfg.device.get_state() - if state == NM.DeviceState.UNAVAILABLE: - ap_str = None - else: - active_ap = dev_cfg.device.get_active_access_point() - if active_ap: - ap_str = self._ap_security_string(active_ap) - else: - ap_str = "" - - self._set_device_info_value("wireless", "security", ap_str) - - if state == NM.DeviceState.UNAVAILABLE: - self.builder.get_object("heading_wireless_network_name").hide() - self.builder.get_object("combobox_wireless_network_name").hide() - else: - self.builder.get_object("heading_wireless_network_name").show() - self.builder.get_object("combobox_wireless_network_name").show() - - store = self.builder.get_object("liststore_wireless_network") - self._updating_device = True - store.clear() - aps = self._get_strongest_unique_aps(dev_cfg.device.get_access_points()) - for ap in aps: - self._add_ap(ap, active_ap == ap) - # TODO: add access point other... - if active_ap: - combobox = self.builder.get_object("combobox_wireless_network_name") - for i in combobox.get_model(): - if i[0] == active_ap: - combobox.set_active_iter(i.iter) - self.selected_ap = active_ap - break - self._updating_device = False - - def _refresh_slaves(self, dev_cfg): - if dev_cfg.get_device_type() in [NM.DeviceType.BOND, - NM.DeviceType.TEAM, - NM.DeviceType.BRIDGE]: - slaves = "" - if dev_cfg.device: - slaves = ",".join(s.get_iface() for s in dev_cfg.device.get_slaves()) - self._set_device_info_value("wired", "slaves", slaves) - - def _refresh_parent_vlanid(self, dev_cfg): - if dev_cfg.get_device_type() == NM.DeviceType.VLAN: - if dev_cfg.device: - vlanid = dev_cfg.device.get_vlan_id() - else: - vlanid = dev_cfg.con.get_setting_vlan().get_id() - parent = dev_cfg.con.get_setting_vlan().get_parent() - self._set_device_info_value("wired", "vlanid", str(vlanid)) - self._set_device_info_value("wired", "parent", parent) - - def _refresh_speed_hwaddr(self, dev_cfg, state=None): - dev_type = dev_cfg.get_device_type() - if dev_type in self.wired_ui_device_types: - dt = "wired" - elif dev_type == NM.DeviceType.WIFI: - dt = "wireless" - - # Speed - speed = None - if dev_cfg.device: - if dev_type == NM.DeviceType.ETHERNET: - speed = dev_cfg.device.get_speed() - elif dev_type == NM.DeviceType.WIFI: - speed = dev_cfg.device.get_bitrate() / 1000 - if state is None: - state = dev_cfg.device.get_state() - - if not dev_cfg.device or state == NM.DeviceState.UNAVAILABLE: - speed_str = None - elif speed: - speed_str = _("%d Mb/s") % speed - else: - speed_str = "" - self._set_device_info_value(dt, "speed", speed_str) - # Hardware address - hwaddr = dev_cfg.device and dev_cfg.device.get_hw_address() - self._set_device_info_value(dt, "mac", hwaddr) - - def _refresh_device_type_page(self, dev_type): - notebook = self.builder.get_object("notebook_types") - if dev_type == NM.DeviceType.ETHERNET: - notebook.set_current_page(0) - self.builder.get_object("heading_wired_slaves").hide() - self.builder.get_object("label_wired_slaves").hide() - self.builder.get_object("heading_wired_vlanid").hide() - self.builder.get_object("label_wired_vlanid").hide() - self.builder.get_object("heading_wired_parent").hide() - self.builder.get_object("label_wired_parent").hide() - self.builder.get_object("remove_toolbutton").set_sensitive(False) - elif dev_type in [NM.DeviceType.BOND, - NM.DeviceType.TEAM, - NM.DeviceType.BRIDGE]: - notebook.set_current_page(0) - self.builder.get_object("heading_wired_slaves").show() - self.builder.get_object("label_wired_slaves").show() - self.builder.get_object("heading_wired_vlanid").hide() - self.builder.get_object("label_wired_vlanid").hide() - self.builder.get_object("heading_wired_parent").hide() - self.builder.get_object("label_wired_parent").hide() - self.builder.get_object("remove_toolbutton").set_sensitive(True) - elif dev_type == NM.DeviceType.VLAN: - notebook.set_current_page(0) - self.builder.get_object("heading_wired_slaves").hide() - self.builder.get_object("label_wired_slaves").hide() - self.builder.get_object("heading_wired_vlanid").show() - self.builder.get_object("label_wired_vlanid").show() - self.builder.get_object("heading_wired_parent").show() - self.builder.get_object("label_wired_parent").show() - self.builder.get_object("remove_toolbutton").set_sensitive(True) - elif dev_type == NM.DeviceType.WIFI: - notebook.set_current_page(1) - self.builder.get_object("button_wireless_options").set_sensitive(self.selected_ap is not None) - - def _refresh_carrier_info(self): - for i in self.dev_cfg_store: - i[DEVICES_COLUMN_TITLE] = self._dev_title(i[DEVICES_COLUMN_OBJECT]) - - def _refresh_header_ui(self, dev_cfg, state=None): - if dev_cfg.get_device_type() in self.wired_ui_device_types: - dev_type_str = "wired" - elif dev_cfg.get_device_type() == NM.DeviceType.WIFI: - dev_type_str = "wireless" - - if dev_type_str == "wired": - # update icon according to device status - img = self.builder.get_object("image_wired_device") - img.set_from_icon_name(self._dev_icon_name(dev_cfg), Gtk.IconSize.DIALOG) - - # TODO: is this necessary? Isn't it static from glade? - device_type_label = _(self.device_type_name.get(dev_cfg.get_device_type(), "")) - self.builder.get_object("label_%s_device" % dev_type_str).set_label( - "%s (%s)" % (device_type_label, dev_cfg.get_iface())) - - if state is None: - if not dev_cfg.device: - state = NM.DeviceState.DISCONNECTED - else: - state = dev_cfg.device.get_state() - - self.builder.get_object("label_%s_status" % dev_type_str).set_label( - localized_string_of_device_state(dev_cfg.device, state)) - - switch = self.builder.get_object("device_%s_off_switch" % dev_type_str) - if dev_type_str == "wired": - switch.set_visible(state not in (NM.DeviceState.UNAVAILABLE, - NM.DeviceState.UNMANAGED)) - self._updating_device = True - switch.set_active(state not in (NM.DeviceState.UNMANAGED, - NM.DeviceState.UNAVAILABLE, - NM.DeviceState.DISCONNECTED, - NM.DeviceState.DEACTIVATING, - NM.DeviceState.FAILED)) - self._updating_device = False - elif dev_type_str == "wireless": - self.on_wireless_enabled() - - def _set_device_info_value(self, dev_type_str, info, value_str): - heading = self.builder.get_object("heading_%s_%s" % (dev_type_str, info)) - value_label = self.builder.get_object("label_%s_%s" % (dev_type_str, info)) - if value_str is None: - really_hide(heading) - really_hide(value_label) - else: - really_show(heading) - really_show(value_label) - value_label.set_label(value_str) - - def _add_ap(self, ap, active=False): - ssid = ap.get_ssid() - if not ssid: - # get_ssid can return None if AP does not broadcast. - return - ssid = ssid.get_data() - if not ssid: - return - - mode = ap.get_mode() - if not mode: - return - - security = self._ap_security(ap) - - store = self.builder.get_object("liststore_wireless_network") - - # Decode the SSID (a byte sequence) into something resembling a string - ssid_str = NM.utils_ssid_to_utf8(ssid) - - # the third column is for sorting - itr = store.append([ap, - ssid_str, - ssid_str, - ap.get_strength(), - mode, - security]) - if active: - self.builder.get_object("combobox_wireless_network_name").set_active_iter(itr) - - def _get_strongest_unique_aps(self, access_points): - strongest_aps = {} - for ap in access_points: - if not ap.get_ssid(): - # non-broadcasting AP. We don't do anything with these - continue - ssid = ap.get_ssid().get_data() - if ssid in strongest_aps: - if ap.get_strength() > strongest_aps[ssid].get_strength(): - strongest_aps[ssid] = ap - else: - strongest_aps[ssid] = ap - - return strongest_aps.values() - - def _ap_security(self, ap): - ty = NM_AP_SEC_UNKNOWN - - flags = ap.get_flags() - wpa_flags = ap.get_wpa_flags() - rsn_flags = ap.get_rsn_flags() - - if (not (flags & NM._80211ApFlags.PRIVACY) and - wpa_flags == NM._80211ApSecurityFlags.NONE and - rsn_flags == NM._80211ApSecurityFlags.NONE): - ty = NM_AP_SEC_NONE - elif (flags & NM._80211ApFlags.PRIVACY and - wpa_flags == NM._80211ApSecurityFlags.NONE and - rsn_flags == NM._80211ApSecurityFlags.NONE): - ty = NM_AP_SEC_WEP - elif (not (flags & NM._80211ApFlags.PRIVACY) and - wpa_flags != NM._80211ApSecurityFlags.NONE and - rsn_flags != NM._80211ApSecurityFlags.NONE): - ty = NM_AP_SEC_WPA - else: - ty = NM_AP_SEC_WPA2 - - return ty - - def _ap_security_string(self, ap): - - flags = ap.get_flags() - wpa_flags = ap.get_wpa_flags() - rsn_flags = ap.get_rsn_flags() - - sec_str = "" - - if ((flags & NM._80211ApFlags.PRIVACY) and - wpa_flags == NM._80211ApSecurityFlags.NONE and - rsn_flags == NM._80211ApSecurityFlags.NONE): - sec_str += "%s, " % _("WEP") - - if wpa_flags != NM._80211ApSecurityFlags.NONE: - sec_str += "%s, " % _("WPA") - - if rsn_flags != NM._80211ApSecurityFlags.NONE: - sec_str += "%s, " % _("WPA2") - - if ((wpa_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X) or - (rsn_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X)): - sec_str += "%s, " % _("Enterprise") - - if sec_str: - sec_str = sec_str[:-2] - else: - sec_str = _("None") - - return sec_str - - def _ap_is_enterprise(self, ap): - wpa_flags = ap.get_wpa_flags() - rsn_flags = ap.get_rsn_flags() - return ((wpa_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X) or - (rsn_flags & NM._80211ApSecurityFlags.KEY_MGMT_802_1X)) - - @property - def dev_cfgs(self): - return [row[DEVICES_COLUMN_OBJECT] for - row in self.dev_cfg_store] - - @property - def hostname(self): - return self.entry_hostname.get_text() - - @hostname.setter - def hostname(self, value): - if not value: - return - self.entry_hostname.set_text(value) - - @property - def current_hostname(self): - return self.label_current_hostname.get_text() - - @current_hostname.setter - def current_hostname(self, value): - if not value: - return - self.label_current_hostname.set_text(value) - - def disconnect_client_callbacks(self): - for cb in [self.on_device_added, self.on_device_removed, - self.on_connection_added, self.on_wireless_enabled, - self.on_nm_state_changed]: - _try_disconnect(self.client, cb) - - for device in self.client.get_devices(): - _try_disconnect(device, self.on_device_config_changed) - _try_disconnect(device, self.on_device_state_changed) - _try_disconnect(device, self.on_ip_obj_changed) - for config in self._get_ip_configs(device): - _try_disconnect(config, self.on_config_changed) - - def _get_ip_configs(self, device): - out = [] - try: - out.append(self.props.ip4_config) - except AttributeError: - pass - try: - out.append(self.props.ip6_config) - except AttributeError: - pass - - return out - -def _try_disconnect(obj, callback): - try: - obj.disconnect_by_func(callback) - except TypeError as e: - if not "nothing connected" in str(e): - log.debug("network: %s", e) - -class SecretAgentDialog(GUIObject): - builderObjects = ["secret_agent_dialog"] - mainWidgetName = "secret_agent_dialog" - uiFile = "spokes/network.glade" - - def __init__(self, *args, **kwargs): - self._content = kwargs.pop('content', {}) - GUIObject.__init__(self, *args, **kwargs) - self.builder.get_object("label_message").set_text(self._content['message']) - self._connect_button = self.builder.get_object("connect_button") - - def initialize(self): - self._entries = {} - grid = Gtk.Grid() - grid.set_row_spacing(6) - grid.set_column_spacing(6) - - for row, secret in enumerate(self._content['secrets']): - label = Gtk.Label(label=secret['label'], halign=Gtk.Align.START) - entry = Gtk.Entry(hexpand=True) - entry.set_text(secret['value']) - if secret['key']: - self._entries[secret['key']] = entry - else: - entry.set_sensitive(False) - if secret['password']: - entry.set_visibility(False) - self._validate(entry, secret) - entry.connect("changed", self._validate, secret) - entry.connect("activate", self._password_entered_cb) - label.set_use_underline(True) - label.set_mnemonic_widget(entry) - grid.attach(label, 0, row, 1, 1) - grid.attach(entry, 1, row, 1, 1) - - self.builder.get_object("password_box").add(grid) - - def run(self): - self.initialize() - self.window.show_all() - rc = self.window.run() - for secret in self._content['secrets']: - if secret['key']: - secret['value'] = self._entries[secret['key']].get_text() - self.window.destroy() - return rc - - @property - def valid(self): - return all(secret.get('valid', False) for secret in self._content['secrets']) - - def _validate(self, entry, secret): - secret['value'] = entry.get_text() - if secret['validate']: - secret['valid'] = secret['validate'](secret) - else: - secret['valid'] = len(secret['value']) > 0 - self._update_connect_button() - - def _password_entered_cb(self, entry): - if self._connect_button.get_sensitive() and self.valid: - self.window.response(1) - - def _update_connect_button(self): - self._connect_button.set_sensitive(self.valid) - -secret_agent = None - -class NotAuthorizedException(dbus.DBusException): - _dbus_error_name = SECRET_AGENT_IFACE + '.NotAuthorized' - -class SecretAgent(dbus.service.Object): - def __init__(self, spoke): - self._bus = dbus.SystemBus() - self.spoke = spoke - dbus.service.Object.__init__(self, self._bus, "/org/freedesktop/NetworkManager/SecretAgent") - - @dbus.service.method(SECRET_AGENT_IFACE, - in_signature='a{sa{sv}}osasb', - out_signature='a{sa{sv}}', - sender_keyword='sender') - def GetSecrets(self, connection_hash, connection_path, setting_name, hints, flags, sender=None): - if not sender: - raise NotAuthorizedException("Internal error: couldn't get sender") - uid = self._bus.get_unix_user(sender) - if uid != 0: - raise NotAuthorizedException("UID %d not authorized" % uid) - - log.debug("network: secrets requested path '%s' setting '%s' hints '%s' new %d", - connection_path, setting_name, str(hints), flags) - if not (flags & NM_SECRET_AGENT_GET_SECRETS_FLAG_ALLOW_INTERACTION): - return - - content = self._get_content(setting_name, connection_hash) - dialog = SecretAgentDialog(self.spoke.data, content=content) - with self.spoke.main_window.enlightbox(dialog.window): - rc = dialog.run() - - secrets = dbus.Dictionary() - if rc == 1: - for secret in content['secrets']: - if secret['key']: - secrets[secret['key']] = secret['value'] - - settings = dbus.Dictionary({setting_name: secrets}) - - return settings - - def _get_content(self, setting_name, connection_hash): - content = {} - connection_type = connection_hash['connection']['type'] - if connection_type == "802-11-wireless": - content['title'] = _("Authentication required by wireless network") - content['message'] = _("Passwords or encryption keys are required to access\n" - "the wireless network '%(network_id)s'.") \ - % {'network_id':str(connection_hash['connection']['id'])} - content['secrets'] = self._get_wireless_secrets(setting_name, connection_hash) - else: - log.info("Connection type %s not supported by secret agent", connection_type) - - return content - - def _get_wireless_secrets(self, setting_name, connection_hash): - key_mgmt = connection_hash['802-11-wireless-security']['key-mgmt'] - original_secrets = connection_hash[setting_name] - secrets = [] - if key_mgmt in ['wpa-none', 'wpa-psk']: - secrets.append({'label' : C_('GUI|Network|Secrets Dialog', '_Password:'), - 'key' : 'psk', - 'value' : original_secrets.get('psk', ''), - 'validate' : self._validate_wpapsk, - 'password' : True}) - # static WEP - elif key_mgmt == 'none': - key_idx = str(original_secrets.get('wep_tx_keyidx', '0')) - secrets.append({'label' : C_('GUI|Network|Secrets Dialog', '_Key:'), - 'key' : 'wep-key%s' % key_idx, - 'value' : original_secrets.get('wep-key%s' % key_idx, ''), - 'wep_key_type': original_secrets.get('wep-key-type', ''), - 'validate' : self._validate_staticwep, - 'password' : True}) - # WPA-Enterprise - elif key_mgmt == 'wpa-eap': - eap = original_secrets['eap'][0] - if eap in ('md5', 'leap', 'ttls', 'peap'): - secrets.append({'label' : _('User name: '), - 'key' : None, - 'value' : original_secrets.get('identity', ''), - 'validate' : None, - 'password' : False}) - secrets.append({'label' : _('Password: '), - 'key' : 'password', - 'value' : original_secrets.get('password', ''), - 'validate' : None, - 'password' : True}) - elif eap == 'tls': - secrets.append({'label' : _('Identity: '), - 'key' : None, - 'value' : original_secrets.get('identity', ''), - 'validate' : None, - 'password' : False}) - secrets.append({'label' : _('Private key password: '), - 'key' : 'private-key-password', - 'value' : original_secrets.get('private-key-password', ''), - 'validate' : None, - 'password' : True}) - else: - log.info("Unsupported wireless key management: %s", key_mgmt) - - return secrets - - def _validate_wpapsk(self, secret): - value = secret['value'] - if len(value) == 64: - # must be composed of hexadecimal digits only - return all(c in string.hexdigits for c in value) - else: - return 8 <= len(value) <= 63 - - def _validate_staticwep(self, secret): - value = secret['value'] - if secret['wep_key_type'] == NM.WepKeyType.KEY: - if len(value) in (10, 26): - return all(c in string.hexdigits for c in value) - elif len(value) in (5, 13): - return all(c in string.ascii_letters for c in value) - else: - return False - elif secret['wep_key_type'] == NM.WepKeyType.PASSPHRASE: - return 0 <= len(value) <= 64 - else: - return True - -def register_secret_agent(spoke): - - if not can_touch_runtime_system("register anaconda secret agent"): - return False - - global secret_agent - if not secret_agent: - # Ignore an error from pylint incorrectly analyzing types in dbus-python - secret_agent = SecretAgent(spoke) # pylint: disable=no-value-for-parameter - bus = dbus.SystemBus() - proxy = bus.get_object(NM_SERVICE, AGENT_MANAGER_PATH) - proxy.Register("anaconda", dbus_interface=AGENT_MANAGER_IFACE) - else: - secret_agent.spoke = spoke - - return True - - -class NetworkSpoke(FirstbootSpokeMixIn, NormalSpoke): - """ - .. inheritance-diagram:: NetworkSpoke - :parts: 3 - """ - builderObjects = ["networkWindow", "liststore_wireless_network", "liststore_devices", "add_device_dialog", "liststore_add_device"] - mainWidgetName = "networkWindow" - uiFile = "spokes/network.glade" - helpFile = "NetworkSpoke.xml" - - title = CN_("GUI|Spoke", "_NETWORK & HOST NAME") - icon = "network-transmit-receive-symbolic" - - category = SystemCategory - - def __init__(self, *args, **kwargs): - NormalSpoke.__init__(self, *args, **kwargs) - self.networking_changed = False - self.network_control_box = NetworkControlBox(self.builder, nmclient, spoke=self) - self.network_control_box.hostname = self.data.network.hostname - self.network_control_box.current_hostname = network.current_hostname() - self.network_control_box.connect("nm-state-changed", - self.on_nm_state_changed) - self.network_control_box.connect("device-state-changed", - self.on_device_state_changed) - self.network_control_box.connect("apply-hostname", - self.on_apply_hostname) - - def apply(self): - _update_network_data(self.data, self.network_control_box) - log.debug("network: apply ksdata %s", self.data.network) - - # if installation media or hdd aren't used and settings have changed - # try if source is available - if self.networking_changed: - if ANACONDA_ENVIRON in anaconda_flags.environs and self.payload.needsNetwork: - log.debug("network spoke (apply) refresh payload") - from pyanaconda.packaging import payloadMgr - payloadMgr.restartThread(self.storage, self.data, self.payload, self.instclass, - fallback=not anaconda_flags.automatedInstall) - else: - log.debug("network spoke (apply), payload refresh skipped (running outside of installation environment)") - self.networking_changed = False - else: - log.debug("network spoke (apply), no changes detected") - self.network_control_box.kill_nmce(msg="leaving network spoke") - - @property - def completed(self): - # TODO: check also if source requires updates when implemented - return (not can_touch_runtime_system("require network connection") - or nm.nm_activated_devices()) - - @property - def mandatory(self): - # the network spoke should be mandatory only if it is running - # during the installation and if the installation source requires network - return ANACONDA_ENVIRON in anaconda_flags.environs and self.payload.needsNetwork - - @property - def status(self): - """ A short string describing which devices are connected. """ - return network.status_message() - - def initialize(self): - register_secret_agent(self) - NormalSpoke.initialize(self) - self.network_control_box.initialize() - if not can_touch_runtime_system("hide hint to use network configuration in DE"): - self.builder.get_object("network_config_vbox").set_no_show_all(True) - self.builder.get_object("network_config_vbox").hide() - else: - self.builder.get_object("live_hint_label").set_no_show_all(True) - self.builder.get_object("live_hint_label").hide() - - if not self.data.network.seen: - _update_network_data(self.data, self.network_control_box) - - def refresh(self): - NormalSpoke.refresh(self) - self.network_control_box.refresh() - self.network_control_box.current_hostname = network.current_hostname() - - def on_nm_state_changed(self, *args): - gtk_call_once(self._update_status) - gtk_call_once(self._update_hostname) - - def on_device_state_changed(self, source, device, new_state, *args): - if new_state in (NM.DeviceState.ACTIVATED, - NM.DeviceState.DISCONNECTED, - NM.DeviceState.UNAVAILABLE): - gtk_call_once(self._update_status) - - def on_apply_hostname(self, *args): - hostname = self.network_control_box.hostname - (valid, error) = network.sanityCheckHostname(hostname) - if not valid: - self.clear_info() - msg = _("Host name is not valid: %s") % error - self.set_warning(msg) - self.network_control_box.entry_hostname.grab_focus() - else: - self.clear_info() - network.set_hostname(hostname) - self._update_hostname() - - def _update_status(self): - hubQ.send_message(self.__class__.__name__, self.status) - - def _update_hostname(self): - self.network_control_box.current_hostname = network.current_hostname() - - def on_back_clicked(self, button): - hostname = self.network_control_box.hostname - (valid, error) = network.sanityCheckHostname(hostname) - if not valid: - self.clear_info() - msg = _("Host name is not valid: %s") % error - self.set_warning(msg) - self.network_control_box.entry_hostname.grab_focus() - else: - self.clear_info() - NormalSpoke.on_back_clicked(self, button) - - def finished(self): - """Disconnect callbacks - - Called when leaving summary hub - """ - self.network_control_box.kill_nmce(msg="finished with network spoke") - self.network_control_box.disconnect_client_callbacks() - -class NetworkStandaloneSpoke(StandaloneSpoke): - """ - .. inheritance-diagram:: NetworkStandaloneSpoke - :parts: 3 - """ - builderObjects = ["networkStandaloneWindow", "networkControlBox_vbox", "liststore_wireless_network", "liststore_devices", "add_device_dialog", "liststore_add_device"] - mainWidgetName = "networkStandaloneWindow" - uiFile = "spokes/network.glade" - - preForHub = SummaryHub - priority = 10 - - def __init__(self, *args, **kwargs): - StandaloneSpoke.__init__(self, *args, **kwargs) - self.network_control_box = NetworkControlBox(self.builder, nmclient, spoke=self) - self.network_control_box.hostname = self.data.network.hostname - self.network_control_box.current_hostname = network.current_hostname() - parent = self.builder.get_object("AnacondaStandaloneWindow-action_area5") - parent.add(self.network_control_box.vbox) - - self.network_control_box.connect("nm-state-changed", - self.on_nm_state_changed) - self.network_control_box.connect("apply-hostname", - self.on_apply_hostname) - - self._initially_available = self.completed - log.debug("network standalone spoke (init): completed: %s", self._initially_available) - self._now_available = False - - def apply(self): - _update_network_data(self.data, self.network_control_box) - - log.debug("network: apply ksdata %s", self.data.network) - - self._now_available = self.completed - - log.debug("network standalone spoke (apply) payload: %s completed: %s", self.payload.baseRepo, self._now_available) - if (not self.payload.baseRepo and not self._initially_available - and self._now_available and self.payload.needsNetwork): - from pyanaconda.packaging import payloadMgr - payloadMgr.restartThread(self.storage, self.data, self.payload, self.instclass, - fallback=not anaconda_flags.automatedInstall) - - self.network_control_box.kill_nmce(msg="leaving standalone network spoke") - self.network_control_box.disconnect_client_callbacks() - - @property - def completed(self): - return (not can_touch_runtime_system("require network connection") - or nm.nm_activated_devices() - or self.data.method.method not in ("url", "nfs")) - - def initialize(self): - register_secret_agent(self) - StandaloneSpoke.initialize(self) - self.network_control_box.initialize() - - def refresh(self): - StandaloneSpoke.refresh(self) - self.network_control_box.refresh() - self.network_control_box.current_hostname = network.current_hostname() - - def _on_continue_clicked(self, window, user_data=None): - hostname = self.network_control_box.hostname - (valid, error) = network.sanityCheckHostname(hostname) - if not valid: - self.clear_info() - msg = _("Host name is not valid: %s") % error - self.set_warning(msg) - self.network_control_box.entry_hostname.grab_focus() - else: - self.clear_info() - StandaloneSpoke._on_continue_clicked(self, window, user_data) - - # Use case: slow dhcp has connected when on spoke - def on_nm_state_changed(self, *args): - gtk_call_once(self._update_hostname) - - def on_apply_hostname(self, *args): - hostname = self.network_control_box.hostname - (valid, error) = network.sanityCheckHostname(hostname) - if not valid: - self.clear_info() - msg = _("Host name is not valid: %s") % error - self.set_warning(msg) - self.network_control_box.entry_hostname.grab_focus() - else: - self.clear_info() - network.set_hostname(hostname) - self._update_hostname() - - def _update_hostname(self): - self.network_control_box.current_hostname = network.current_hostname() - -def _update_network_data(data, ncb): - data.network.network = [] - for i, dev_cfg in enumerate(ncb.dev_cfgs): - devname = dev_cfg.get_iface() - nd = network.ksdata_from_ifcfg(devname, dev_cfg.get_uuid()) - if not nd: - continue - if devname in nm.nm_activated_devices(): - nd.activate = True - else: - # First network command defaults to --activate so we must - # use --no-activate explicitly to prevent the default - if i == 0: - nd.activate = False - - data.network.network.append(nd) - hostname = ncb.hostname - network.update_hostname_data(data, hostname) - - -def test(): - win = Gtk.Window() - win.connect("delete-event", Gtk.main_quit) - - builder = Gtk.Builder() - import os - ui_file_path = os.environ.get('UIPATH')+'spokes/network.glade' - builder.add_from_file(ui_file_path) - - n = NetworkControlBox(builder, nmclient) - n.initialize() - n.refresh() - - n.vbox.reparent(win) - - win.show_all() - Gtk.main() - -if __name__ == "__main__": - test() -- 2.14.4