diff --git a/AUTHORS b/AUTHORS index 5ab1470..d236e58 100644 --- a/AUTHORS +++ b/AUTHORS @@ -1 +1,3 @@ Gustavo Sverzut Barbieri +Matthias Wauer +Leif Middelschulte diff --git a/ChangeLog b/ChangeLog index e69de29..f51649d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -0,0 +1,4 @@ +Since 1.1: +* Added basic support for ieee802.1x wireless networks configuration + The user running econnman needs to be able to write its own configfile at + /var/lib/connman/econnman.config diff --git a/Makefile.am b/Makefile.am index a65ebf2..83cf1ac 100644 --- a/Makefile.am +++ b/Makefile.am @@ -17,6 +17,12 @@ econnman-bin: $(top_srcdir)/econnman-bin.in $(top_builddir)/Makefile $(top_srcdir)/econnman-bin.in > $(top_builddir)/econnman-bin chmod +x $(top_builddir)/econnman-bin +configdir = $(localstatedir@)/lib/connman +dist_config_DATA = \ + data/config/econnman.config + +EXTRA_DIST += $(config_DATA) + desktopdir = $(datadir)/applications desktop_DATA = \ data/desktop/econnman-agent.desktop \ diff --git a/README b/README index 89a0ec5..ece4fb7 100644 --- a/README +++ b/README @@ -36,6 +36,7 @@ Build:: Install:: make install + chown root:users /var/lib/connman/econnman.config If you wish to install at alternative locations, then make sure to configure your PYTHONPATH to be able to access this location! diff --git a/data/config/econnman.config b/data/config/econnman.config new file mode 100644 index 0000000..e69de29 diff --git a/econnman-bin.in b/econnman-bin.in index 55d2256..3292638 100755 --- a/econnman-bin.in +++ b/econnman-bin.in @@ -14,6 +14,12 @@ import logging import argparse import os.path +''' For python2 backwards compatibility ''' +try: + import configparser +except ImportError: + import ConfigParser as configparser + try: import efl.evas as evas import efl.ecore as ecore @@ -58,6 +64,9 @@ log = logging.getLogger() manager = None +CONF_FILE = "/var/lib/connman/econnman.config" +configs = None + EXPAND_BOTH = (evas.EVAS_HINT_EXPAND, evas.EVAS_HINT_EXPAND) EXPAND_HORIZ = (evas.EVAS_HINT_EXPAND, 0.0) @@ -242,6 +251,52 @@ class ObjectView(object): en.callback_activated_add(callback) return lb, en +####################################################################### +# Config Files Helper: + +def config_del(name): + secname = 'service_' + name + if configs == None: + log.error("Config file was not parsed!") + return + if not configs.has_section(secname): + configs.remove_section(secname) + config_write(name) + +def config_set(name, key, value): + secname = 'service_' + name + if configs == None: + log.error("Config file was not parsed!") + return + if not configs.has_section(secname): + configs.add_section(secname) + configs.set(secname, 'Type', 'wifi') + configs.set(secname, 'Name', name) + if value != None: + configs.set(secname, key, value) + elif configs.has_option(secname, key): + configs.remove_option(sec, key) + config_write(name) + +def config_get(name): + if configs == None: + log.error("Config file was not parsed!") + return None + for sec in configs.sections(): + if configs.has_option(sec, 'Name') and configs.get(sec, 'Name') == name: + return sec + else: + return None + +def config_exists(name): + if config_get(name): + return True + else: + return False + +def config_write(name): + with open(CONF_FILE, 'w', encoding='utf8') as configfile: + configs.write(configfile) ######################################################################## # Views: @@ -803,13 +858,16 @@ class ServiceView(ObjectView): "proxy_frame", "ethernet_frame", "vpn_frame", + "ieee8021x_frame", ) def create_view(self, properties): self.type = str(properties.get("Type")) + self.security_mode = properties.get("Security") self.immutable = bool(properties.get("Immutable")) self.readwrite_list_properties = {} self.readwrite_list_widget = {} + self.name = str(properties.get("Name")) self.connect = self.add_button(self.box, "Connect", self._connect) self.disconnect = self.add_button(self.box, "Disconnect", @@ -890,6 +948,37 @@ class ServiceView(ObjectView): fr, bx = self.add_readonly_section("VPN", self.vpn_fields) self.vpn_frame = fr + # section 2 Phase Authentication + + if (self.type == "wifi") and ("ieee8021x" in self.security_mode): + fr, bx = self.add_frame_and_box(self.box, "ieee8021x") + self.ieee8021x_frame = fr + cfg_sec = config_get(self.name) + + lb = self.add_label(bx, "EAP:") + options = ("PEAP", "TLS", "TTLS", "None") + self.eap_method, self.eap_method_items = self.add_segment_control( + bx, options, self._on_eap_method) + if cfg_sec: + conf_val = configs.get(cfg_sec, 'EAP') + if conf_val == "peap": + self.eap_method_items["PEAP"].selected = True + elif conf_val == "tls": + self.eap_method_items["TLS"].selected = True + elif conf_val == "ttls": + self.eap_method_items["TTLS"].selected = True + + options = ("TLS", "MSCHAPv2", "None") + lb = self.add_label(bx, "Phase2:") + self.phase2, self.phase2_items = self.add_segment_control( + bx, options, self._on_phase2) + if cfg_sec: + conf_val = configs.get(cfg_sec, 'Phase2') + if conf_val == "tls": + self.phase2_items["TLS"].selected = True + elif conf_val == "MSCHAPV2": + self.phase2_items["MSCHAPv2"].selected = True + def add_readonly_section(self, title, fields): fr, bx = self.add_frame_and_box(self.box, title) for name, attr in fields: @@ -1108,7 +1197,10 @@ class ServiceView(ObjectView): log.error("Could not remove %s", exc) self.forget.disabled = False - self.bus_obj.Remove(reply_handler=on_reply, error_handler=on_error) + if self.security_mode == "ieee8021x": + config_del(self.name) + else: + self.bus_obj.Remove(reply_handler=on_reply, error_handler=on_error) self.forget.disabled = True def _on_user_auto_connect(self, obj): @@ -1232,6 +1324,31 @@ class ServiceView(ObjectView): pass #revert to configured values... + def _on_eap_method(self, obj, item): + eap_val = None + if item.text == "PEAP": + eap_val = "peap" + elif item.text == "TLS": + eap_val = "tls" + elif item.text == "TTLS": + eap_val = "ttls" + elif item.text == "None": + eap_val = None + + config_set(self.name, "EAP", eap_val) + return + + def _on_phase2(self, obj, item): + phase2_val = None + if item.text == "MSCHAPv2": + phase2_val = "MSCHAPV2" + elif item.text == "TLS": + phase2_val = "tls" + elif item.text == "None": + eap_val = None + + config_set(self.name, 'Phase2', phase2_val) + return ######################################################################## # Main Actions: @@ -1254,6 +1371,7 @@ def connect_service(path, properties): if type in ("system", "gps", "gadget"): log.error("cannot connect to service with type: %s", type) return + sec = properties.get("Security") name = properties.get("Name") if name: @@ -1261,6 +1379,12 @@ def connect_service(path, properties): log.debug("connect to %s (%s): %s", name, path, dbus_dict_to_str(properties)) + ''' Connman only supports 2 phase auth via config files ''' + if ("ieee8021x" in sec) and not config_exists(name): + popup_error(win, "This Network needs Configuration", "This network uses 802.1x authentication. Please configure the options in the section at the bottom.") + show_service(path, properties) + return + def on_reply(): log.info("Connected to %s (%s)", name, path) @@ -1486,6 +1610,10 @@ if __name__ == "__main__": level -= 10 * args.verbose log.setLevel(level) + configs = configparser.RawConfigParser() + configs.optionxform = str + configs.read(CONF_FILE) + elm.init() elm.policy_set(ELM_POLICY_QUIT, ELM_POLICY_QUIT_LAST_WINDOW_CLOSED)