=== modified file 'INSTALL' --- INSTALL 2008-10-05 17:38:31 +0000 +++ INSTALL 2008-10-28 18:00:20 +0000 @@ -127,6 +127,6 @@ You may want to tighten or loosen the timeouts in the server configuration files; see mandos.conf(5) and mandos-clients.conf(5). - Is IPsec is not used, it is suggested that a more cryptographically + If IPsec is not used, it is suggested that a more cryptographically secure checker program is used and configured, since without IPsec ping packets can be faked. === modified file 'Makefile' --- Makefile 2008-10-18 10:58:29 +0000 +++ Makefile 2008-10-28 18:00:20 +0000 @@ -70,7 +70,8 @@ /usr/share/xml/docbook/stylesheet/nwalsh/xhtml/docbook.xsl \ $<; $(HTMLPOST) $@ # Fix citerefentry links -HTMLPOST=$(SED) --in-place --expression='s/\(\)\([^<]*\)\(<\/span>(\)\([^)]*\)\()<\/span><\/a>\)/\1\3.\5\2\3\4\5\6/g' +HTMLPOST=$(SED) --in-place \ + --expression='s/\(\)\([^<]*\)\(<\/span>(\)\([^)]*\)\()<\/span><\/a>\)/\1\3.\5\2\3\4\5\6/g' PLUGINS=plugins.d/password-prompt plugins.d/mandos-client \ plugins.d/usplash plugins.d/splashy plugins.d/askpass-fifo @@ -148,17 +149,27 @@ # Update all these files with version number $(version) common.ent: Makefile - $(SED) --in-place --expression='s/^\($$/\1$(version)"/' $@ + $(SED) --in-place \ + --expression='s/^\($$/\1$(version)"/' \ + $@ mandos: Makefile - $(SED) --in-place --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' $@ + $(SED) --in-place \ + --expression='s/^\(version = "\)[^"]*"$$/\1$(version)"/' \ + $@ mandos-keygen: Makefile - $(SED) --in-place --expression='s/^\(VERSION="\)[^"]*"$$/\1$(version)"/' $@ + $(SED) --in-place \ + --expression='s/^\(VERSION="\)[^"]*"$$/\1$(version)"/' \ + $@ mandos.lsm: Makefile - $(SED) --in-place --expression='s/^\(Version:\).*/\1\t$(version)/' $@ - $(SED) --in-place --expression='s/^\(Entered-date:\).*/\1\t$(shell date --rfc-3339=date --reference=Makefile)/' $@ + $(SED) --in-place \ + --expression='s/^\(Version:\).*/\1\t$(version)/' \ + $@ + $(SED) --in-place \ + --expression='s/^\(Entered-date:\).*/\1\t$(shell date --rfc-3339=date --reference=Makefile)/' \ + $@ plugins.d/mandos-client: plugins.d/mandos-client.o $(LINK.o) $(GNUTLS_LIBS) $(AVAHI_LIBS) $(GPGME_LIBS) \ @@ -206,7 +217,7 @@ install: install-server install-client-nokey -install-html: $(htmldocs) +install-html: html install --directory $(htmldir) install --mode=u=rw,go=r --target-directory=$(htmldir) \ $(htmldocs) === modified file 'README' --- README 2008-10-12 07:27:43 +0000 +++ README 2008-10-28 18:00:20 +0000 @@ -161,7 +161,7 @@ * Copyright Copyright © 2008 Teddy Hogeborn - 2008 Björn Påhlsson + Copyright © 2008 Björn Påhlsson ** License: === modified file 'TODO' --- TODO 2008-11-12 05:46:07 +0000 +++ TODO 2008-11-12 05:46:49 +0000 @@ -3,6 +3,7 @@ * mandos-client ** TODO [#B] Temporarily lower kernel log level for less printouts during sucessfull boot. + klogctl(6, NULL, 0); klogctl(7, NULL, 0); ** TODO [#C] IPv4 support * mandos (server) @@ -13,6 +14,23 @@ ** TODO [#B] Run-time communication with server :bugs: Probably using D-Bus See also [[*Mandos-tools]] +*** Client class + Remove unneeded Get* methods? +*** Main server + + Clients + out_signature="ao" + Does this have to be "GetClients" so as not to collide with the + interface name? + + SetLogLevel + syslogger.setLevel(logging.WARNING) + + Quit + + GetClientsProperties "aa{sv}": + dbus.Array(dbus.Dictionary({dbus.String("name"): + dbus.String("foo", variant_level=1), + dbus.String("created"): + dbus.Array(dbus.Int16(2008), ..., + variant_level=1)})) + + [[http://log.ometer.com/2007-05.html][Best D-Bus practices]] ** TODO Implement --foreground :bugs: [[info:standards:Option%20Table][Table of Long Options]] ** TODO Implement --socket @@ -20,6 +38,8 @@ ** TODO Date+time on console log messages :bugs: Is this the default? ** TODO delete hook when clients fall out by timeout + This will not be strictly necessary when the D-Bus interface is + implemented. * Mandos-tools/utilities All of this probably using D-Bus === modified file 'initramfs-tools-hook' --- initramfs-tools-hook 2008-09-19 00:54:24 +0000 +++ initramfs-tools-hook 2008-11-01 02:26:00 +0000 @@ -89,7 +89,7 @@ continue fi case "$base" in - *~|.*|\#*\#|*.dpkg-old|*.dpkg-new|*.dpkg-divert) : ;; + *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert) : ;; "*") :;; *) copy_exec "$file" "${PLUGINDIR}";; esac @@ -99,7 +99,7 @@ for file in /etc/mandos/plugins.d/*; do base="`basename \"$file\"`" case "$base" in - *~|.*|\#*\#|*.dpkg-old|*.dpkg-new|*.dpkg-divert) : ;; + *~|.*|\#*\#|*.dpkg-old|*.dpkg-bak|*.dpkg-new|*.dpkg-divert) : ;; "*") :;; *) copy_exec "$file" "${PLUGINDIR}";; esac === modified file 'mandos' --- mandos 2008-10-17 18:56:25 +0000 +++ mandos 2008-11-11 16:07:18 +0000 @@ -11,7 +11,8 @@ # and some lines in "main". # # Everything else is -# Copyright © 2008 Teddy Hogeborn & Björn Påhlsson +# Copyright © 2008 Teddy Hogeborn +# Copyright © 2008 Björn Påhlsson # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -30,7 +31,7 @@ # Contact the authors at . # -from __future__ import division +from __future__ import division, with_statement, absolute_import import SocketServer import socket @@ -55,8 +56,10 @@ import logging import logging.handlers import pwd +from contextlib import closing import dbus +import dbus.service import gobject import avahi from dbus.mainloop.glib import DBusGMainLoop @@ -66,11 +69,11 @@ version = "1.0.2" logger = logging.Logger('mandos') -syslogger = logging.handlers.SysLogHandler\ - (facility = logging.handlers.SysLogHandler.LOG_DAEMON, - address = "/dev/log") -syslogger.setFormatter(logging.Formatter\ - ('Mandos: %(levelname)s: %(message)s')) +syslogger = (logging.handlers.SysLogHandler + (facility = logging.handlers.SysLogHandler.LOG_DAEMON, + address = "/dev/log")) +syslogger.setFormatter(logging.Formatter + ('Mandos: %(levelname)s: %(message)s')) logger.addHandler(syslogger) console = logging.StreamHandler() @@ -109,16 +112,13 @@ a sensible number of times """ def __init__(self, interface = avahi.IF_UNSPEC, name = None, - servicetype = None, port = None, TXT = None, domain = "", - host = "", max_renames = 32768): + servicetype = None, port = None, TXT = None, + domain = "", host = "", max_renames = 32768): self.interface = interface self.name = name self.type = servicetype self.port = port - if TXT is None: - self.TXT = [] - else: - self.TXT = TXT + self.TXT = TXT if TXT is not None else [] self.domain = domain self.host = host self.rename_count = 0 @@ -133,9 +133,9 @@ self.name = server.GetAlternativeServiceName(self.name) logger.info(u"Changing Zeroconf service name to %r ...", str(self.name)) - syslogger.setFormatter(logging.Formatter\ + syslogger.setFormatter(logging.Formatter ('Mandos (%s): %%(levelname)s:' - ' %%(message)s' % self.name)) + ' %%(message)s' % self.name)) self.remove() self.add() self.rename_count += 1 @@ -147,10 +147,10 @@ """Derived from the Avahi example code""" global group if group is None: - group = dbus.Interface\ - (bus.get_object(avahi.DBUS_NAME, + group = dbus.Interface(bus.get_object + (avahi.DBUS_NAME, server.EntryGroupNew()), - avahi.DBUS_INTERFACE_ENTRY_GROUP) + avahi.DBUS_INTERFACE_ENTRY_GROUP) group.connect_to_signal('StateChanged', entry_group_state_changed) logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...", @@ -170,7 +170,7 @@ # End of Avahi example code -class Client(object): +class Client(dbus.service.Object): """A representation of a client host served by this server. Attributes: name: string; from the config file, used in log messages @@ -178,8 +178,9 @@ uniquely identify the client secret: bytestring; sent verbatim (over TLS) to client host: string; available for use by the checker command - created: datetime.datetime(); object creation, not client host - last_checked_ok: datetime.datetime() or None if not yet checked OK + created: datetime.datetime(); (UTC) object creation + started: datetime.datetime(); (UTC) last started + last_checked_ok: datetime.datetime(); (UTC) or None timeout: datetime.timedelta(); How long from last_checked_ok until this client is invalid interval: datetime.timedelta(); How often to start a new checker @@ -201,18 +202,20 @@ _interval_milliseconds: - '' - """ def _set_timeout(self, timeout): - "Setter function for 'timeout' attribute" + "Setter function for the 'timeout' attribute" self._timeout = timeout self._timeout_milliseconds = ((self.timeout.days * 24 * 60 * 60 * 1000) + (self.timeout.seconds * 1000) + (self.timeout.microseconds // 1000)) - timeout = property(lambda self: self._timeout, - _set_timeout) + # Emit D-Bus signal + self.TimeoutChanged(self._timeout_milliseconds) + timeout = property(lambda self: self._timeout, _set_timeout) del _set_timeout + def _set_interval(self, interval): - "Setter function for 'interval' attribute" + "Setter function for the 'interval' attribute" self._interval = interval self._interval_milliseconds = ((self.interval.days * 24 * 60 * 60 * 1000) @@ -220,13 +223,18 @@ * 1000) + (self.interval.microseconds // 1000)) - interval = property(lambda self: self._interval, - _set_interval) + # Emit D-Bus signal + self.IntervalChanged(self._interval_milliseconds) + interval = property(lambda self: self._interval, _set_interval) del _set_interval + def __init__(self, name = None, stop_hook=None, config=None): """Note: the 'checker' key in 'config' sets the 'checker_command' attribute and *not* the 'checker' attribute.""" + dbus.service.Object.__init__(self, bus, + "/Mandos/clients/%s" + % name.replace(".", "_")) if config is None: config = {} self.name = name @@ -234,21 +242,22 @@ # Uppercase and remove spaces from fingerprint for later # comparison purposes with return value from the fingerprint() # function - self.fingerprint = config["fingerprint"].upper()\ - .replace(u" ", u"") + self.fingerprint = (config["fingerprint"].upper() + .replace(u" ", u"")) logger.debug(u" Fingerprint: %s", self.fingerprint) if "secret" in config: self.secret = config["secret"].decode(u"base64") elif "secfile" in config: - secfile = open(os.path.expanduser(os.path.expandvars - (config["secfile"]))) - self.secret = secfile.read() - secfile.close() + with closing(open(os.path.expanduser + (os.path.expandvars + (config["secfile"])))) as secfile: + self.secret = secfile.read() else: raise TypeError(u"No secret or secfile for client %s" % self.name) self.host = config.get("host", "") - self.created = datetime.datetime.now() + self.created = datetime.datetime.utcnow() + self.started = None self.last_checked_ok = None self.timeout = string_to_delta(config["timeout"]) self.interval = string_to_delta(config["interval"]) @@ -258,27 +267,28 @@ self.stop_initiator_tag = None self.checker_callback_tag = None self.check_command = config["checker"] + def start(self): """Start this client's checker and timeout hooks""" + self.started = datetime.datetime.utcnow() # Schedule a new checker to be started an 'interval' from now, # and every interval from then on. - self.checker_initiator_tag = gobject.timeout_add\ - (self._interval_milliseconds, - self.start_checker) + self.checker_initiator_tag = (gobject.timeout_add + (self._interval_milliseconds, + self.start_checker)) # Also start a new checker *right now*. self.start_checker() # Schedule a stop() when 'timeout' has passed - self.stop_initiator_tag = gobject.timeout_add\ - (self._timeout_milliseconds, - self.stop) + self.stop_initiator_tag = (gobject.timeout_add + (self._timeout_milliseconds, + self.stop)) + # Emit D-Bus signal + self.StateChanged(True) + def stop(self): - """Stop this client. - The possibility that a client might be restarted is left open, - but not currently used.""" - # If this client doesn't have a secret, it is already stopped. - if hasattr(self, "secret") and self.secret: + """Stop this client.""" + if getattr(self, "started", None) is not None: logger.info(u"Stopping client %s", self.name) - self.secret = None else: return False if getattr(self, "stop_initiator_tag", False): @@ -290,31 +300,49 @@ self.stop_checker() if self.stop_hook: self.stop_hook(self) + self.started = None + # Emit D-Bus signal + self.StateChanged(False) # Do not run this again if called by a gobject.timeout_add return False + def __del__(self): self.stop_hook = None self.stop() + def checker_callback(self, pid, condition): """The checker has completed, so take appropriate actions.""" - now = datetime.datetime.now() self.checker_callback_tag = None self.checker = None - if os.WIFEXITED(condition) \ - and (os.WEXITSTATUS(condition) == 0): + if (os.WIFEXITED(condition) + and (os.WEXITSTATUS(condition) == 0)): logger.info(u"Checker for %(name)s succeeded", vars(self)) - self.last_checked_ok = now - gobject.source_remove(self.stop_initiator_tag) - self.stop_initiator_tag = gobject.timeout_add\ - (self._timeout_milliseconds, - self.stop) + # Emit D-Bus signal + self.CheckerCompleted(True) + self.bump_timeout() elif not os.WIFEXITED(condition): logger.warning(u"Checker for %(name)s crashed?", vars(self)) + # Emit D-Bus signal + self.CheckerCompleted(False) else: logger.info(u"Checker for %(name)s failed", vars(self)) + # Emit D-Bus signal + self.CheckerCompleted(False) + + def bump_timeout(self): + """Bump up the timeout for this client. + This should only be called when the client has been seen, + alive and well. + """ + self.last_checked_ok = datetime.datetime.utcnow() + gobject.source_remove(self.stop_initiator_tag) + self.stop_initiator_tag = (gobject.timeout_add + (self._timeout_milliseconds, + self.stop)) + def start_checker(self): """Start a new checker subprocess if one is not running. If a checker already exists, leave it running and do @@ -352,14 +380,17 @@ self.checker = subprocess.Popen(command, close_fds=True, shell=True, cwd="/") - self.checker_callback_tag = gobject.child_watch_add\ - (self.checker.pid, - self.checker_callback) + self.checker_callback_tag = (gobject.child_watch_add + (self.checker.pid, + self.checker_callback)) + # Emit D-Bus signal + self.CheckerStarted(command) except OSError, error: logger.error(u"Failed to start subprocess: %s", error) # Re-run this periodically if run by gobject.timeout_add return True + def stop_checker(self): """Force the checker process, if any, to stop.""" if self.checker_callback_tag: @@ -377,26 +408,183 @@ if error.errno != errno.ESRCH: # No such process raise self.checker = None + def still_valid(self): """Has the timeout not yet passed for this client?""" - now = datetime.datetime.now() + if not self.started: + return False + now = datetime.datetime.utcnow() if self.last_checked_ok is None: return now < (self.created + self.timeout) else: return now < (self.last_checked_ok + self.timeout) + + ## D-Bus methods & signals + _interface = u"org.mandos_system.Mandos.Client" + + def _datetime_to_dbus_struct(dt): + return dbus.Struct(dt.year, dt.month, dt.day, dt.hour, + dt.minute, dt.second, dt.microsecond, + signature="nyyyyyu") + + # BumpTimeout - method + BumpTimeout = dbus.service.method(_interface)(bump_timeout) + BumpTimeout.__name__ = "BumpTimeout" + + # IntervalChanged - signal + @dbus.service.signal(_interface, signature="t") + def IntervalChanged(self, t): + "D-Bus signal" + pass + + # CheckerCompleted - signal + @dbus.service.signal(_interface, signature="b") + def CheckerCompleted(self, success): + "D-Bus signal" + pass + + # CheckerIsRunning - method + @dbus.service.method(_interface, out_signature="b") + def CheckerIsRunning(self): + "D-Bus getter method" + return self.checker is not None + + # CheckerStarted - signal + @dbus.service.signal(_interface, signature="s") + def CheckerStarted(self, command): + "D-Bus signal" + pass + + # GetChecker - method + @dbus.service.method(_interface, out_signature="s") + def GetChecker(self): + "D-Bus getter method" + return self.checker_command + + # GetCreated - method + @dbus.service.method(_interface, out_signature="(nyyyyyu)") + def GetCreated(self): + "D-Bus getter method" + return datetime_to_dbus_struct(self.created) + + # GetFingerprint - method + @dbus.service.method(_interface, out_signature="s") + def GetFingerprint(self): + "D-Bus getter method" + return self.fingerprint + + # GetHost - method + @dbus.service.method(_interface, out_signature="s") + def GetHost(self): + "D-Bus getter method" + return self.host + + # GetInterval - method + @dbus.service.method(_interface, out_signature="t") + def GetInterval(self): + "D-Bus getter method" + return self._interval_milliseconds + + # GetName - method + @dbus.service.method(_interface, out_signature="s") + def GetName(self): + "D-Bus getter method" + return self.name + + # GetStarted - method + @dbus.service.method(_interface, out_signature="(nyyyyyu)") + def GetStarted(self): + "D-Bus getter method" + if self.started is not None: + return datetime_to_dbus_struct(self.started) + else: + return dbus.Struct(0, 0, 0, 0, 0, 0, 0, + signature="nyyyyyu") + + # GetTimeout - method + @dbus.service.method(_interface, out_signature="t") + def GetTimeout(self): + "D-Bus getter method" + return self._timeout_milliseconds + + # SetChecker - method + @dbus.service.method(_interface, in_signature="s") + def SetChecker(self, checker): + "D-Bus setter method" + self.checker_command = checker + + # SetHost - method + @dbus.service.method(_interface, in_signature="s") + def SetHost(self, host): + "D-Bus setter method" + self.host = host + + # SetInterval - method + @dbus.service.method(_interface, in_signature="t") + def SetInterval(self, milliseconds): + self.interval = datetime.timdeelta(0, 0, 0, milliseconds) + + # SetTimeout - method + @dbus.service.method(_interface, in_signature="t") + def SetTimeout(self, milliseconds): + self.timeout = datetime.timedelta(0, 0, 0, milliseconds) + + # SetSecret - method + @dbus.service.method(_interface, in_signature="ay", + byte_arrays=True) + def SetSecret(self, secret): + "D-Bus setter method" + self.secret = str(secret) + + # Start - method + Start = dbus.service.method(_interface)(start) + Start.__name__ = "Start" + + # StartChecker - method + StartChecker = dbus.service.method(_interface)(start_checker) + StartChecker.__name__ = "StartChecker" + + # StateChanged - signal + @dbus.service.signal(_interface, signature="b") + def StateChanged(self, started): + "D-Bus signal" + pass + + # StillValid - method + StillValid = (dbus.service.method(_interface, out_signature="b") + (still_valid)) + StillValid.__name__ = "StillValid" + + # Stop - method + Stop = dbus.service.method(_interface)(stop) + Stop.__name__ = "Stop" + + # StopChecker - method + StopChecker = dbus.service.method(_interface)(stop_checker) + StopChecker.__name__ = "StopChecker" + + # TimeoutChanged - signal + @dbus.service.signal(_interface, signature="t") + def TimeoutChanged(self, t): + "D-Bus signal" + pass + + del _datetime_to_dbus_struct + del _interface def peer_certificate(session): "Return the peer's OpenPGP certificate as a bytestring" # If not an OpenPGP certificate... - if gnutls.library.functions.gnutls_certificate_type_get\ - (session._c_object) \ - != gnutls.library.constants.GNUTLS_CRT_OPENPGP: + if (gnutls.library.functions + .gnutls_certificate_type_get(session._c_object) + != gnutls.library.constants.GNUTLS_CRT_OPENPGP): # ...do the normal thing return session.peer_certificate list_size = ctypes.c_uint() - cert_list = gnutls.library.functions.gnutls_certificate_get_peers\ - (session._c_object, ctypes.byref(list_size)) + cert_list = (gnutls.library.functions + .gnutls_certificate_get_peers + (session._c_object, ctypes.byref(list_size))) if list_size.value == 0: return None cert = cert_list[0] @@ -406,22 +594,24 @@ def fingerprint(openpgp): "Convert an OpenPGP bytestring to a hexdigit fingerprint string" # New GnuTLS "datum" with the OpenPGP public key - datum = gnutls.library.types.gnutls_datum_t\ - (ctypes.cast(ctypes.c_char_p(openpgp), - ctypes.POINTER(ctypes.c_ubyte)), - ctypes.c_uint(len(openpgp))) + datum = (gnutls.library.types + .gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp), + ctypes.POINTER + (ctypes.c_ubyte)), + ctypes.c_uint(len(openpgp)))) # New empty GnuTLS certificate crt = gnutls.library.types.gnutls_openpgp_crt_t() - gnutls.library.functions.gnutls_openpgp_crt_init\ - (ctypes.byref(crt)) + (gnutls.library.functions + .gnutls_openpgp_crt_init(ctypes.byref(crt))) # Import the OpenPGP public key into the certificate - gnutls.library.functions.gnutls_openpgp_crt_import\ - (crt, ctypes.byref(datum), - gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW) + (gnutls.library.functions + .gnutls_openpgp_crt_import(crt, ctypes.byref(datum), + gnutls.library.constants + .GNUTLS_OPENPGP_FMT_RAW)) # Verify the self signature in the key crtverify = ctypes.c_uint() - gnutls.library.functions.gnutls_openpgp_crt_verify_self\ - (crt, 0, ctypes.byref(crtverify)) + (gnutls.library.functions + .gnutls_openpgp_crt_verify_self(crt, 0, ctypes.byref(crtverify))) if crtverify.value != 0: gnutls.library.functions.gnutls_openpgp_crt_deinit(crt) raise gnutls.errors.CertificateSecurityError("Verify failed") @@ -429,8 +619,9 @@ buf = ctypes.create_string_buffer(20) buf_len = ctypes.c_size_t() # Get the fingerprint from the certificate into the buffer - gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint\ - (crt, ctypes.byref(buf), ctypes.byref(buf_len)) + (gnutls.library.functions + .gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf), + ctypes.byref(buf_len))) # Deinit the certificate gnutls.library.functions.gnutls_openpgp_crt_deinit(crt) # Convert the buffer to a Python bytestring @@ -447,9 +638,11 @@ def handle(self): logger.info(u"TCP connection from: %s", - unicode(self.client_address)) - session = gnutls.connection.ClientSession\ - (self.request, gnutls.connection.X509Credentials()) + unicode(self.client_address)) + session = (gnutls.connection + .ClientSession(self.request, + gnutls.connection + .X509Credentials())) line = self.request.makefile().readline() logger.debug(u"Protocol version: %r", line) @@ -468,12 +661,11 @@ #priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC", # "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP", # "+DHE-DSS")) - priority = "NORMAL" # Fallback default, since this - # MUST be set. - if self.server.settings["priority"]: - priority = self.server.settings["priority"] - gnutls.library.functions.gnutls_priority_set_direct\ - (session._c_object, priority, None) + # Use a fallback default, since this MUST be set. + priority = self.server.settings.get("priority", "NORMAL") + (gnutls.library.functions + .gnutls_priority_set_direct(session._c_object, + priority, None)) try: session.handshake() @@ -489,12 +681,11 @@ session.bye() return logger.debug(u"Fingerprint: %s", fpr) - client = None for c in self.server.clients: if c.fingerprint == fpr: client = c break - if not client: + else: logger.warning(u"Client not found for fingerprint: %s", fpr) session.bye() @@ -507,6 +698,8 @@ vars(client)) session.bye() return + ## This won't work here, since we're in a fork. + # client.bump_timeout() sent_size = 0 while sent_size < len(client.secret): sent = session.send(client.secret[sent_size:]) @@ -517,7 +710,8 @@ session.bye() -class IPv6_TCPServer(SocketServer.ForkingTCPServer, object): +class IPv6_TCPServer(SocketServer.ForkingMixIn, + SocketServer.TCPServer, object): """IPv6 TCP server. Accepts 'None' as address and/or port. Attributes: settings: Server settings @@ -642,8 +836,9 @@ """Call the C function if_nametoindex(), or equivalent""" global if_nametoindex try: - if_nametoindex = ctypes.cdll.LoadLibrary\ - (ctypes.util.find_library("c")).if_nametoindex + if_nametoindex = (ctypes.cdll.LoadLibrary + (ctypes.util.find_library("c")) + .if_nametoindex) except (OSError, AttributeError): if "struct" not in sys.modules: import struct @@ -652,10 +847,9 @@ def if_nametoindex(interface): "Get an interface index the hard way, i.e. using fcntl()" SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h - s = socket.socket() - ifreq = fcntl.ioctl(s, SIOCGIFINDEX, - struct.pack("16s16x", interface)) - s.close() + with closing(socket.socket()) as s: + ifreq = fcntl.ioctl(s, SIOCGIFINDEX, + struct.pack("16s16x", interface)) interface_index = struct.unpack("I", ifreq[16:20])[0] return interface_index return if_nametoindex(interface) @@ -729,8 +923,8 @@ # Convert the SafeConfigParser object to a dict server_settings = server_config.defaults() # Use getboolean on the boolean config option - server_settings["debug"] = server_config.getboolean\ - ("DEFAULT", "debug") + server_settings["debug"] = (server_config.getboolean + ("DEFAULT", "debug")) del server_config # Override the settings from the config file with command line @@ -750,7 +944,7 @@ console.setLevel(logging.WARNING) if server_settings["servicename"] != "Mandos": - syslogger.setFormatter(logging.Formatter\ + syslogger.setFormatter(logging.Formatter ('Mandos (%s): %%(levelname)s:' ' %%(message)s' % server_settings["servicename"])) @@ -804,8 +998,8 @@ service = AvahiService(name = server_settings["servicename"], servicetype = "_mandos._tcp", ) if server_settings["interface"]: - service.interface = if_nametoindex\ - (server_settings["interface"]) + service.interface = (if_nametoindex + (server_settings["interface"])) global main_loop global bus @@ -818,6 +1012,7 @@ avahi.DBUS_PATH_SERVER), avahi.DBUS_INTERFACE_SERVER) # End of Avahi example code + bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus) def remove_from_clients(client): clients.remove(client) @@ -905,8 +1100,8 @@ gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN, lambda *args, **kwargs: - tcp_server.handle_request\ - (*args[2:], **kwargs) or True) + (tcp_server.handle_request + (*args[2:], **kwargs) or True)) logger.debug(u"Starting main loop") main_loop.run() === modified file 'mandos-keygen' --- mandos-keygen 2008-11-12 05:46:07 +0000 +++ mandos-keygen 2008-11-12 05:46:49 +0000 @@ -2,7 +2,8 @@ # # Mandos key generator - create a new OpenPGP key for a Mandos client # -# Copyright © 2008 Teddy Hogeborn & Björn Påhlsson +# Copyright © 2008 Teddy Hogeborn +# Copyright © 2008 Björn Påhlsson # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by === modified file 'plugin-runner.c' --- plugin-runner.c 2008-09-30 07:23:39 +0000 +++ plugin-runner.c 2008-11-11 16:07:18 +0000 @@ -2,7 +2,8 @@ /* * Mandos plugin runner - Run Mandos plugins * - * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson + * Copyright © 2008 Teddy Hogeborn + * Copyright © 2008 Björn Påhlsson * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -700,6 +701,7 @@ const char const *bad_suffixes[] = { "~", "#", ".dpkg-new", ".dpkg-old", + ".dpkg-bak", ".dpkg-divert", NULL }; for(const char **pre = bad_prefixes; *pre != NULL; pre++){ size_t pre_len = strlen(*pre); === modified file 'plugins.d/askpass-fifo.c' --- plugins.d/askpass-fifo.c 2008-09-26 19:47:21 +0000 +++ plugins.d/askpass-fifo.c 2008-11-11 16:07:18 +0000 @@ -1,3 +1,28 @@ +/* -*- coding: utf-8 -*- */ +/* + * Passprompt - Read a password from a FIFO and output it + * + * Copyright © 2008 Teddy Hogeborn + * Copyright © 2008 Björn Påhlsson + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty 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, see + * . + * + * Contact the authors at and + * . + */ + #define _GNU_SOURCE /* TEMP_FAILURE_RETRY() */ #include /* ssize_t */ #include /* mkfifo(), S_IRUSR, S_IWUSR */ === modified file 'plugins.d/mandos-client.c' --- plugins.d/mandos-client.c 2008-09-30 07:23:39 +0000 +++ plugins.d/mandos-client.c 2008-11-11 16:07:18 +0000 @@ -9,7 +9,8 @@ * "browse_callback", and parts of "main". * * Everything else is - * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson + * Copyright © 2008 Teddy Hogeborn + * Copyright © 2008 Björn Påhlsson * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as === modified file 'plugins.d/password-prompt.c' --- plugins.d/password-prompt.c 2008-09-30 07:23:39 +0000 +++ plugins.d/password-prompt.c 2008-11-11 16:07:18 +0000 @@ -1,8 +1,9 @@ /* -*- coding: utf-8 -*- */ /* * Passprompt - Read a password from the terminal and print it - * - * Copyright © 2008 Teddy Hogeborn & Björn Påhlsson + * + * Copyright © 2008 Teddy Hogeborn + * Copyright © 2008 Björn Påhlsson * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as === modified file 'plugins.d/splashy.c' --- plugins.d/splashy.c 2008-10-03 09:32:30 +0000 +++ plugins.d/splashy.c 2008-11-11 16:07:18 +0000 @@ -1,3 +1,28 @@ +/* -*- coding: utf-8 -*- */ +/* + * Passprompt - Read a password from splashy and output it + * + * Copyright © 2008 Teddy Hogeborn + * Copyright © 2008 Björn Påhlsson + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty 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, see + * . + * + * Contact the authors at and + * . + */ + #define _GNU_SOURCE /* asprintf() */ #include /* sig_atomic_t, struct sigaction, sigemptyset(), sigaddset(), SIGINT, === modified file 'plugins.d/usplash.c' --- plugins.d/usplash.c 2008-10-03 09:32:30 +0000 +++ plugins.d/usplash.c 2008-11-11 16:07:18 +0000 @@ -1,3 +1,28 @@ +/* -*- coding: utf-8 -*- */ +/* + * Passprompt - Read a password from usplash and output it + * + * Copyright © 2008 Teddy Hogeborn + * Copyright © 2008 Björn Påhlsson + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty 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, see + * . + * + * Contact the authors at and + * . + */ + #define _GNU_SOURCE /* asprintf() */ #include /* sig_atomic_t, struct sigaction, sigemptyset(), sigaddset(), SIGINT,