=== modified file 'DBUS-API' --- DBUS-API 2011-03-17 18:14:34 +0000 +++ DBUS-API 2011-09-18 14:28:47 +0000 @@ -86,15 +86,16 @@ | CheckerRunning (c) | b | Read/Write | N/A | | Created (d) | s | Read | N/A | | Enabled (e) | b | Read/Write | N/A | + | Expires (f) | s | Read | N/A | | Fingerprint | s | Read | fingerprint | | Host | s | Read/Write | host | | Interval (a) | t | Read/Write | interval | - | LastApprovalRequest (f) | s | Read | N/A | - | LastCheckedOK (g) | s | Read/Write | N/A | - | LastEnabled (h) | s | Read | N/A | + | LastApprovalRequest (g) | s | Read | N/A | + | LastCheckedOK (h) | s | Read/Write | N/A | + | LastEnabled (i) | s | Read | N/A | | Name | s | Read | (Section name) | | ObjectPath | o | Read | N/A | - | Secret (i) | ay | Write | secret (or secfile) | + | Secret (j) | ay | Write | secret (or secfile) | | Timeout (a) | t | Read/Write | timeout | a) Represented as milliseconds. @@ -109,20 +110,23 @@ e) Setting this property is equivalent to calling Enable() or Disable(). - f) The time of the last approval request, as an RFC 3339 string, or + f) The date and time this client will be disabled, as an RFC 3339 + string, or an empty string if this has not happened. + + g) The time of the last approval request, as an RFC 3339 string, or an empty string if this has not happened. - g) The last time a checker was successful, as an RFC 3339 string, + h) The last time a checker was successful, as an RFC 3339 string, or an empty string if this has not happened. Setting this property is equivalent to calling CheckedOK(), i.e. the current time is set, regardless of the string sent. Please always use an empty string when setting this property, to allow for possible future expansion. - h) The last time this client was enabled, as an RFC 3339 string, or + i) The last time this client was enabled, as an RFC 3339 string, or an empty string if this has not happened. - i) A raw byte array, not hexadecimal digits. + j) A raw byte array, not hexadecimal digits. ** Signals *** CheckerCompleted(n: Exitcode, x: Waitstatus, s: Command) === modified file 'README' --- README 2011-08-08 21:12:37 +0000 +++ README 2011-09-18 14:28:47 +0000 @@ -3,7 +3,7 @@ This information previously in this file has been moved to the intro(8mandos) manual page. Go to the above URL, or run this command: - make intro.8mandos && man -l intro.8mandos + man 8mandos intro In short, this is the Mandos system; it allows computers to have encrypted root file systems and at the same time be capable of remote === modified file 'TODO' --- TODO 2011-08-17 22:46:35 +0000 +++ TODO 2011-09-18 14:28:47 +0000 @@ -38,6 +38,7 @@ ** TODO [#B] Use openat() * mandos (server) +** TODO [#A] Make all attributes properties! ** TODO [#B] Log level :BUGS: ** TODO Persistent state :BUGS: /var/lib/mandos/* === modified file 'mandos' --- mandos 2011-07-27 17:58:27 +0000 +++ mandos 2011-09-18 14:28:47 +0000 @@ -297,7 +297,10 @@ secret: bytestring; sent verbatim (over TLS) to client timeout: datetime.timedelta(); How long from last_checked_ok until this client is disabled + extended_timeout: extra long timeout when password has been sent runtime_expansions: Allowed attributes for runtime expansion. + expire: datetime.datetime(); time (UTC) when a client will be + disabled, or None """ runtime_expansions = ("approval_delay", "approval_duration", @@ -315,6 +318,10 @@ def timeout_milliseconds(self): "Return the 'timeout' attribute in milliseconds" return self._timedelta_to_milliseconds(self.timeout) + + def extended_timeout_milliseconds(self): + "Return the 'extended_timeout' attribute in milliseconds" + return self._timedelta_to_milliseconds(self.extended_timeout) def interval_milliseconds(self): "Return the 'interval' attribute in milliseconds" @@ -354,11 +361,13 @@ self.last_enabled = None self.last_checked_ok = None self.timeout = string_to_delta(config["timeout"]) + self.extended_timeout = string_to_delta(config["extended_timeout"]) self.interval = string_to_delta(config["interval"]) self.disable_hook = disable_hook self.checker = None self.checker_initiator_tag = None self.disable_initiator_tag = None + self.expires = None self.checker_callback_tag = None self.checker_command = config["checker"] self.current_checker_command = None @@ -391,6 +400,7 @@ (self.interval_milliseconds(), self.start_checker)) # Schedule a disable() when 'timeout' has passed + self.expires = datetime.datetime.utcnow() + self.timeout self.disable_initiator_tag = (gobject.timeout_add (self.timeout_milliseconds(), self.disable)) @@ -409,6 +419,7 @@ if getattr(self, "disable_initiator_tag", False): gobject.source_remove(self.disable_initiator_tag) self.disable_initiator_tag = None + self.expires = None if getattr(self, "checker_initiator_tag", False): gobject.source_remove(self.checker_initiator_tag) self.checker_initiator_tag = None @@ -440,16 +451,19 @@ logger.warning("Checker for %(name)s crashed?", vars(self)) - def checked_ok(self): + def checked_ok(self, timeout=None): """Bump up the timeout for this client. This should only be called when the client has been seen, alive and well. """ + if timeout is None: + timeout = self.timeout self.last_checked_ok = datetime.datetime.utcnow() gobject.source_remove(self.disable_initiator_tag) + self.expires = datetime.datetime.utcnow() + timeout self.disable_initiator_tag = (gobject.timeout_add - (self.timeout_milliseconds(), + (self._timedelta_to_milliseconds(timeout), self.disable)) def need_approval(self): @@ -763,6 +777,16 @@ ("/clients/" + client_object_name)) DBusObjectWithProperties.__init__(self, self.bus, self.dbus_object_path) + def _set_expires(self, value): + old_value = getattr(self, "_expires", None) + self._expires = value + if hasattr(self, "dbus_object_path") and old_value != value: + dbus_time = (self._datetime_to_dbus(self._expires, + variant_level=1)) + self.PropertyChanged(dbus.String("Expires"), + dbus_time) + expires = property(lambda self: self._expires, _set_expires) + del _set_expires def _get_approvals_pending(self): return self._approvals_pending @@ -783,6 +807,8 @@ @staticmethod def _datetime_to_dbus(dt, variant_level=0): """Convert a UTC datetime.datetime() to a D-Bus type.""" + if dt is None: + return dbus.String("", variant_level = variant_level) return dbus.String(dt.isoformat(), variant_level=variant_level) @@ -986,10 +1012,12 @@ def ApprovedByDefault_dbus_property(self, value=None): if value is None: # get return dbus.Boolean(self.approved_by_default) + old_value = self.approved_by_default self.approved_by_default = bool(value) # Emit D-Bus signal - self.PropertyChanged(dbus.String("ApprovedByDefault"), - dbus.Boolean(value, variant_level=1)) + if old_value != self.approved_by_default: + self.PropertyChanged(dbus.String("ApprovedByDefault"), + dbus.Boolean(value, variant_level=1)) # ApprovalDelay - property @dbus_service_property(_interface, signature="t", @@ -997,10 +1025,12 @@ def ApprovalDelay_dbus_property(self, value=None): if value is None: # get return dbus.UInt64(self.approval_delay_milliseconds()) + old_value = self.approval_delay self.approval_delay = datetime.timedelta(0, 0, 0, value) # Emit D-Bus signal - self.PropertyChanged(dbus.String("ApprovalDelay"), - dbus.UInt64(value, variant_level=1)) + if old_value != self.approval_delay: + self.PropertyChanged(dbus.String("ApprovalDelay"), + dbus.UInt64(value, variant_level=1)) # ApprovalDuration - property @dbus_service_property(_interface, signature="t", @@ -1009,10 +1039,12 @@ if value is None: # get return dbus.UInt64(self._timedelta_to_milliseconds( self.approval_duration)) + old_value = self.approval_duration self.approval_duration = datetime.timedelta(0, 0, 0, value) # Emit D-Bus signal - self.PropertyChanged(dbus.String("ApprovalDuration"), - dbus.UInt64(value, variant_level=1)) + if old_value != self.approval_duration: + self.PropertyChanged(dbus.String("ApprovalDuration"), + dbus.UInt64(value, variant_level=1)) # Name - property @dbus_service_property(_interface, signature="s", access="read") @@ -1030,10 +1062,12 @@ def Host_dbus_property(self, value=None): if value is None: # get return dbus.String(self.host) + old_value = self.host self.host = value # Emit D-Bus signal - self.PropertyChanged(dbus.String("Host"), - dbus.String(value, variant_level=1)) + if old_value != self.host: + self.PropertyChanged(dbus.String("Host"), + dbus.String(value, variant_level=1)) # Created - property @dbus_service_property(_interface, signature="s", access="read") @@ -1043,9 +1077,7 @@ # LastEnabled - property @dbus_service_property(_interface, signature="s", access="read") def LastEnabled_dbus_property(self): - if self.last_enabled is None: - return dbus.String("") - return dbus.String(self._datetime_to_dbus(self.last_enabled)) + return self._datetime_to_dbus(self.last_enabled) # Enabled - property @dbus_service_property(_interface, signature="b", @@ -1065,19 +1097,17 @@ if value is not None: self.checked_ok() return - if self.last_checked_ok is None: - return dbus.String("") - return dbus.String(self._datetime_to_dbus(self - .last_checked_ok)) + return self._datetime_to_dbus(self.last_checked_ok) + + # Expires - property + @dbus_service_property(_interface, signature="s", access="read") + def Expires_dbus_property(self): + return self._datetime_to_dbus(self.expires) # LastApprovalRequest - property @dbus_service_property(_interface, signature="s", access="read") def LastApprovalRequest_dbus_property(self): - if self.last_approval_request is None: - return dbus.String("") - return dbus.String(self. - _datetime_to_dbus(self - .last_approval_request)) + return self._datetime_to_dbus(self.last_approval_request) # Timeout - property @dbus_service_property(_interface, signature="t", @@ -1085,15 +1115,18 @@ def Timeout_dbus_property(self, value=None): if value is None: # get return dbus.UInt64(self.timeout_milliseconds()) + old_value = self.timeout self.timeout = datetime.timedelta(0, 0, 0, value) # Emit D-Bus signal - self.PropertyChanged(dbus.String("Timeout"), - dbus.UInt64(value, variant_level=1)) + if old_value != self.timeout: + self.PropertyChanged(dbus.String("Timeout"), + dbus.UInt64(value, variant_level=1)) if getattr(self, "disable_initiator_tag", None) is None: return # Reschedule timeout gobject.source_remove(self.disable_initiator_tag) self.disable_initiator_tag = None + self.expires = None time_to_die = (self. _timedelta_to_milliseconds((self .last_checked_ok @@ -1104,19 +1137,36 @@ # The timeout has passed self.disable() else: + self.expires = (datetime.datetime.utcnow() + + datetime.timedelta(milliseconds = time_to_die)) self.disable_initiator_tag = (gobject.timeout_add (time_to_die, self.disable)) - + + # ExtendedTimeout - property + @dbus_service_property(_interface, signature="t", + access="readwrite") + def ExtendedTimeout_dbus_property(self, value=None): + if value is None: # get + return dbus.UInt64(self.extended_timeout_milliseconds()) + old_value = self.extended_timeout + self.extended_timeout = datetime.timedelta(0, 0, 0, value) + # Emit D-Bus signal + if old_value != self.extended_timeout: + self.PropertyChanged(dbus.String("ExtendedTimeout"), + dbus.UInt64(value, variant_level=1)) + # Interval - property @dbus_service_property(_interface, signature="t", access="readwrite") def Interval_dbus_property(self, value=None): if value is None: # get return dbus.UInt64(self.interval_milliseconds()) + old_value = self.interval self.interval = datetime.timedelta(0, 0, 0, value) # Emit D-Bus signal - self.PropertyChanged(dbus.String("Interval"), - dbus.UInt64(value, variant_level=1)) + if old_value != self.interval: + self.PropertyChanged(dbus.String("Interval"), + dbus.UInt64(value, variant_level=1)) if getattr(self, "checker_initiator_tag", None) is None: return # Reschedule checker run @@ -1131,11 +1181,13 @@ def Checker_dbus_property(self, value=None): if value is None: # get return dbus.String(self.checker_command) + old_value = self.checker_command self.checker_command = value # Emit D-Bus signal - self.PropertyChanged(dbus.String("Checker"), - dbus.String(self.checker_command, - variant_level=1)) + if old_value != self.checker_command: + self.PropertyChanged(dbus.String("Checker"), + dbus.String(self.checker_command, + variant_level=1)) # CheckerRunning - property @dbus_service_property(_interface, signature="b", @@ -1329,7 +1381,7 @@ logger.info("Sending secret to %s", client.name) # bump the timeout as if seen - client.checked_ok() + client.checked_ok(client.extended_timeout) if self.server.use_dbus: # Emit D-Bus signal client.GotSecret() @@ -1796,8 +1848,9 @@ % server_settings["servicename"])) # Parse config file with clients - client_defaults = { "timeout": "1h", - "interval": "5m", + client_defaults = { "timeout": "5m", + "extended_timeout": "15m", + "interval": "2m", "checker": "fping -q -- %%(host)s", "host": "", "approval_delay": "0s", === modified file 'mandos-clients.conf.xml' --- mandos-clients.conf.xml 2011-08-08 21:12:37 +0000 +++ mandos-clients.conf.xml 2011-09-18 14:28:47 +0000 @@ -229,7 +229,7 @@ will wait for a checker to complete until the below timeout occurs, at which time the client will be disabled, and any running checker - killed. The default interval is 5 minutes. + killed. The default interval is 2 minutes. The format of TIME is the same @@ -302,7 +302,7 @@ The timeout is how long the server will wait (for either a successful checker run or a client receiving its secret) until a client is disabled and not allowed to get the data - this server holds. By default Mandos will use 1 hour. + this server holds. By default Mandos will use 5 minutes. The TIME is specified as a @@ -319,6 +319,29 @@ + + + + + + This option is optional. + + + Extended timeout is an added timeout that is given once + after a password has been sent sucessfully to a client. + The timeout is by default longer than the normal timeout, + and is used for handling the extra long downtime while a + matchine is booting up. Time to take into consideration + when changing this value is system file checks and quota + checks. The default value is 15 minutes. + + + The format of TIME is the same + as for timeout above. + + + @@ -420,8 +443,8 @@ [DEFAULT] -timeout = 1h -interval = 5m +timeout = 5m +interval = 2m checker = fping -q -- %%(host)s # Client "foo" === modified file 'mandos-ctl' --- mandos-ctl 2011-07-27 17:58:27 +0000 +++ mandos-ctl 2011-09-18 14:28:47 +0000 @@ -52,6 +52,7 @@ "ApprovalDelay": "Approval Delay", "ApprovalDuration": "Approval Duration", "Checker": "Checker", + "ExtendedTimeout" : "Extended Timeout" } defaultkeywords = ("Name", "Enabled", "Timeout", "LastCheckedOK") domain = "se.bsnet.fukt" @@ -149,6 +150,7 @@ options.remove, options.checker is not None, options.timeout is not None, + options.extended_timeout is not None, options.interval is not None, options.approved_by_default is not None, options.approval_delay is not None, @@ -185,6 +187,8 @@ help="Set checker command for client") parser.add_argument("-t", "--timeout", help="Set timeout for client") + parser.add_argument("--extended-timeout", + help="Set extended timeout for client") parser.add_argument("-i", "--interval", help="Set checker interval for client") parser.add_argument("--approve-by-default", action="store_true", @@ -270,7 +274,8 @@ "LastEnabled", "ApprovalPending", "ApprovedByDefault", "LastApprovalRequest", "ApprovalDelay", - "ApprovalDuration", "Checker") + "ApprovalDuration", "Checker", + "ExtendedTimeout") else: keywords = defaultkeywords @@ -325,6 +330,11 @@ timedelta_to_milliseconds (string_to_delta(options.timeout)), dbus_interface=dbus.PROPERTIES_IFACE) + if options.extended_timeout: + client.Set(client_interface, "ExtendedTimeout", + timedelta_to_milliseconds + (string_to_delta(options.extended_timeout)), + dbus_interface=dbus.PROPERTIES_IFACE) if options.secret: client.Set(client_interface, "Secret", dbus.ByteArray(open(options.secret, === modified file 'mandos-ctl.xml' --- mandos-ctl.xml 2011-08-08 21:12:37 +0000 +++ mandos-ctl.xml 2011-09-18 14:28:47 +0000 @@ -95,6 +95,11 @@ + + + +