/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Teddy Hogeborn
  • Date: 2011-04-02 06:37:18 UTC
  • Revision ID: teddy@fukt.bsnet.se-20110402063718-13ldrcuu0t33sdc4
* mandos: Tolerate restarting Avahi servers.  Also Changed to new
          "except x as y" exception syntax.
  (AvahiService.entry_group_state_changed_match): New; contains the
                                                  SignalMatch object.
  (AvahiService.remove): Really remove the group and the signal
                         connection, if any.
  (AvahiService.add): Always create a new group and signal connection.
  (AvahiService.cleanup): Changed to simply call remove().
  (AvahiService.server_state_changed): Handle and log more bad states.
  (AvahiService.activate): Set "follow_name_owner_changes=True" on the
                           Avahi Server proxy object.
  (ClientDBus.checked_ok): Do not return anything.
  (ClientDBus.CheckedOK): Do not return anything, as documented.
* mandos-monitor: Call D-Bus methods asynchronously.

Show diffs side-by-side

added added

removed removed

Lines of Context:
82
82
        SO_BINDTODEVICE = None
83
83
 
84
84
 
85
 
version = "1.3.1"
 
85
version = "1.3.0"
86
86
 
87
87
#logger = logging.getLogger('mandos')
88
88
logger = logging.Logger('mandos')
176
176
        self.rename_count += 1
177
177
    def remove(self):
178
178
        """Derived from the Avahi example code"""
 
179
        if self.group is not None:
 
180
            try:
 
181
                self.group.Free()
 
182
            except (dbus.exceptions.UnknownMethodException,
 
183
                    dbus.exceptions.DBusException) as e:
 
184
                pass
 
185
            self.group = None
179
186
        if self.entry_group_state_changed_match is not None:
180
187
            self.entry_group_state_changed_match.remove()
181
188
            self.entry_group_state_changed_match = None
182
 
        if self.group is not None:
183
 
            self.group.Reset()
184
189
    def add(self):
185
190
        """Derived from the Avahi example code"""
186
191
        self.remove()
187
 
        if self.group is None:
188
 
            self.group = dbus.Interface(
189
 
                self.bus.get_object(avahi.DBUS_NAME,
190
 
                                    self.server.EntryGroupNew()),
191
 
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
 
192
        self.group = dbus.Interface(
 
193
            self.bus.get_object(avahi.DBUS_NAME,
 
194
                                self.server.EntryGroupNew(),
 
195
                                follow_name_owner_changes=True),
 
196
            avahi.DBUS_INTERFACE_ENTRY_GROUP)
192
197
        self.entry_group_state_changed_match = (
193
198
            self.group.connect_to_signal(
194
199
                'StateChanged', self .entry_group_state_changed))
219
224
                                  % unicode(error))
220
225
    def cleanup(self):
221
226
        """Derived from the Avahi example code"""
222
 
        if self.group is not None:
223
 
            try:
224
 
                self.group.Free()
225
 
            except (dbus.exceptions.UnknownMethodException,
226
 
                    dbus.exceptions.DBusException) as e:
227
 
                pass
228
 
            self.group = None
229
227
        self.remove()
230
228
    def server_state_changed(self, state, error=None):
231
229
        """Derived from the Avahi example code"""
238
236
                       avahi.SERVER_FAILURE:
239
237
                           "Zeroconf server failure" }
240
238
        if state in bad_states:
241
 
            if bad_states[state] is not None:
242
 
                if error is None:
243
 
                    logger.error(bad_states[state])
244
 
                else:
245
 
                    logger.error(bad_states[state] + ": %r", error)
246
 
            self.cleanup()
 
239
            if bad_states[state]:
 
240
                logger.error(bad_states[state])
 
241
            self.remove()
247
242
        elif state == avahi.SERVER_RUNNING:
248
243
            self.add()
249
244
        else:
250
 
            if error is None:
251
 
                logger.debug("Unknown state: %r", state)
252
 
            else:
253
 
                logger.debug("Unknown state: %r: %r", state, error)
 
245
            logger.debug("Unknown state: %r", state)
254
246
    def activate(self):
255
247
        """Derived from the Avahi example code"""
256
248
        if self.server is None:
297
289
    secret:     bytestring; sent verbatim (over TLS) to client
298
290
    timeout:    datetime.timedelta(); How long from last_checked_ok
299
291
                                      until this client is disabled
300
 
    extended_timeout:   extra long timeout when password has been sent
301
292
    runtime_expansions: Allowed attributes for runtime expansion.
302
 
    expires:    datetime.datetime(); time (UTC) when a client will be
303
 
                disabled, or None
304
293
    """
305
294
    
306
295
    runtime_expansions = ("approval_delay", "approval_duration",
318
307
    def timeout_milliseconds(self):
319
308
        "Return the 'timeout' attribute in milliseconds"
320
309
        return self._timedelta_to_milliseconds(self.timeout)
321
 
 
322
 
    def extended_timeout_milliseconds(self):
323
 
        "Return the 'extended_timeout' attribute in milliseconds"
324
 
        return self._timedelta_to_milliseconds(self.extended_timeout)    
325
310
    
326
311
    def interval_milliseconds(self):
327
312
        "Return the 'interval' attribute in milliseconds"
361
346
        self.last_enabled = None
362
347
        self.last_checked_ok = None
363
348
        self.timeout = string_to_delta(config["timeout"])
364
 
        self.extended_timeout = string_to_delta(config["extended_timeout"])
365
349
        self.interval = string_to_delta(config["interval"])
366
350
        self.disable_hook = disable_hook
367
351
        self.checker = None
368
352
        self.checker_initiator_tag = None
369
353
        self.disable_initiator_tag = None
370
 
        self.expires = None
371
354
        self.checker_callback_tag = None
372
355
        self.checker_command = config["checker"]
373
356
        self.current_checker_command = None
400
383
                                      (self.interval_milliseconds(),
401
384
                                       self.start_checker))
402
385
        # Schedule a disable() when 'timeout' has passed
403
 
        self.expires = datetime.datetime.utcnow() + self.timeout
404
386
        self.disable_initiator_tag = (gobject.timeout_add
405
387
                                   (self.timeout_milliseconds(),
406
388
                                    self.disable))
419
401
        if getattr(self, "disable_initiator_tag", False):
420
402
            gobject.source_remove(self.disable_initiator_tag)
421
403
            self.disable_initiator_tag = None
422
 
        self.expires = None
423
404
        if getattr(self, "checker_initiator_tag", False):
424
405
            gobject.source_remove(self.checker_initiator_tag)
425
406
            self.checker_initiator_tag = None
451
432
            logger.warning("Checker for %(name)s crashed?",
452
433
                           vars(self))
453
434
    
454
 
    def checked_ok(self, timeout=None):
 
435
    def checked_ok(self):
455
436
        """Bump up the timeout for this client.
456
437
        
457
438
        This should only be called when the client has been seen,
458
439
        alive and well.
459
440
        """
460
 
        if timeout is None:
461
 
            timeout = self.timeout
462
441
        self.last_checked_ok = datetime.datetime.utcnow()
463
442
        gobject.source_remove(self.disable_initiator_tag)
464
 
        self.expires = datetime.datetime.utcnow() + timeout
465
443
        self.disable_initiator_tag = (gobject.timeout_add
466
 
                                      (self._timedelta_to_milliseconds(timeout),
 
444
                                      (self.timeout_milliseconds(),
467
445
                                       self.disable))
468
446
    
469
447
    def need_approval(self):
777
755
                                 ("/clients/" + client_object_name))
778
756
        DBusObjectWithProperties.__init__(self, self.bus,
779
757
                                          self.dbus_object_path)
780
 
    def _set_expires(self, value):
781
 
        old_value = getattr(self, "_expires", None)
782
 
        self._expires = value
783
 
        if hasattr(self, "dbus_object_path") and old_value != value:
784
 
            dbus_time = (self._datetime_to_dbus(self._expires,
785
 
                                                variant_level=1))
786
 
            self.PropertyChanged(dbus.String("Expires"),
787
 
                                 dbus_time)
788
 
    expires = property(lambda self: self._expires, _set_expires)
789
 
    del _set_expires
790
758
        
791
759
    def _get_approvals_pending(self):
792
760
        return self._approvals_pending
807
775
    @staticmethod
808
776
    def _datetime_to_dbus(dt, variant_level=0):
809
777
        """Convert a UTC datetime.datetime() to a D-Bus type."""
810
 
        if dt is None:
811
 
            return dbus.String("", variant_level = variant_level)
812
778
        return dbus.String(dt.isoformat(),
813
779
                           variant_level=variant_level)
814
780
    
1012
978
    def ApprovedByDefault_dbus_property(self, value=None):
1013
979
        if value is None:       # get
1014
980
            return dbus.Boolean(self.approved_by_default)
1015
 
        old_value = self.approved_by_default
1016
981
        self.approved_by_default = bool(value)
1017
982
        # Emit D-Bus signal
1018
 
        if old_value != self.approved_by_default:
1019
 
            self.PropertyChanged(dbus.String("ApprovedByDefault"),
1020
 
                                 dbus.Boolean(value, variant_level=1))
 
983
        self.PropertyChanged(dbus.String("ApprovedByDefault"),
 
984
                             dbus.Boolean(value, variant_level=1))
1021
985
    
1022
986
    # ApprovalDelay - property
1023
987
    @dbus_service_property(_interface, signature="t",
1025
989
    def ApprovalDelay_dbus_property(self, value=None):
1026
990
        if value is None:       # get
1027
991
            return dbus.UInt64(self.approval_delay_milliseconds())
1028
 
        old_value = self.approval_delay
1029
992
        self.approval_delay = datetime.timedelta(0, 0, 0, value)
1030
993
        # Emit D-Bus signal
1031
 
        if old_value != self.approval_delay:
1032
 
            self.PropertyChanged(dbus.String("ApprovalDelay"),
1033
 
                                 dbus.UInt64(value, variant_level=1))
 
994
        self.PropertyChanged(dbus.String("ApprovalDelay"),
 
995
                             dbus.UInt64(value, variant_level=1))
1034
996
    
1035
997
    # ApprovalDuration - property
1036
998
    @dbus_service_property(_interface, signature="t",
1039
1001
        if value is None:       # get
1040
1002
            return dbus.UInt64(self._timedelta_to_milliseconds(
1041
1003
                    self.approval_duration))
1042
 
        old_value = self.approval_duration
1043
1004
        self.approval_duration = datetime.timedelta(0, 0, 0, value)
1044
1005
        # Emit D-Bus signal
1045
 
        if old_value != self.approval_duration:
1046
 
            self.PropertyChanged(dbus.String("ApprovalDuration"),
1047
 
                                 dbus.UInt64(value, variant_level=1))
 
1006
        self.PropertyChanged(dbus.String("ApprovalDuration"),
 
1007
                             dbus.UInt64(value, variant_level=1))
1048
1008
    
1049
1009
    # Name - property
1050
1010
    @dbus_service_property(_interface, signature="s", access="read")
1062
1022
    def Host_dbus_property(self, value=None):
1063
1023
        if value is None:       # get
1064
1024
            return dbus.String(self.host)
1065
 
        old_value = self.host
1066
1025
        self.host = value
1067
1026
        # Emit D-Bus signal
1068
 
        if old_value != self.host:
1069
 
            self.PropertyChanged(dbus.String("Host"),
1070
 
                                 dbus.String(value, variant_level=1))
 
1027
        self.PropertyChanged(dbus.String("Host"),
 
1028
                             dbus.String(value, variant_level=1))
1071
1029
    
1072
1030
    # Created - property
1073
1031
    @dbus_service_property(_interface, signature="s", access="read")
1077
1035
    # LastEnabled - property
1078
1036
    @dbus_service_property(_interface, signature="s", access="read")
1079
1037
    def LastEnabled_dbus_property(self):
1080
 
        return self._datetime_to_dbus(self.last_enabled)
 
1038
        if self.last_enabled is None:
 
1039
            return dbus.String("")
 
1040
        return dbus.String(self._datetime_to_dbus(self.last_enabled))
1081
1041
    
1082
1042
    # Enabled - property
1083
1043
    @dbus_service_property(_interface, signature="b",
1097
1057
        if value is not None:
1098
1058
            self.checked_ok()
1099
1059
            return
1100
 
        return self._datetime_to_dbus(self.last_checked_ok)
1101
 
    
1102
 
    # Expires - property
1103
 
    @dbus_service_property(_interface, signature="s", access="read")
1104
 
    def Expires_dbus_property(self):
1105
 
        return self._datetime_to_dbus(self.expires)
 
1060
        if self.last_checked_ok is None:
 
1061
            return dbus.String("")
 
1062
        return dbus.String(self._datetime_to_dbus(self
 
1063
                                                  .last_checked_ok))
1106
1064
    
1107
1065
    # LastApprovalRequest - property
1108
1066
    @dbus_service_property(_interface, signature="s", access="read")
1109
1067
    def LastApprovalRequest_dbus_property(self):
1110
 
        return self._datetime_to_dbus(self.last_approval_request)
 
1068
        if self.last_approval_request is None:
 
1069
            return dbus.String("")
 
1070
        return dbus.String(self.
 
1071
                           _datetime_to_dbus(self
 
1072
                                             .last_approval_request))
1111
1073
    
1112
1074
    # Timeout - property
1113
1075
    @dbus_service_property(_interface, signature="t",
1115
1077
    def Timeout_dbus_property(self, value=None):
1116
1078
        if value is None:       # get
1117
1079
            return dbus.UInt64(self.timeout_milliseconds())
1118
 
        old_value = self.timeout
1119
1080
        self.timeout = datetime.timedelta(0, 0, 0, value)
1120
1081
        # Emit D-Bus signal
1121
 
        if old_value != self.timeout:
1122
 
            self.PropertyChanged(dbus.String("Timeout"),
1123
 
                                 dbus.UInt64(value, variant_level=1))
 
1082
        self.PropertyChanged(dbus.String("Timeout"),
 
1083
                             dbus.UInt64(value, variant_level=1))
1124
1084
        if getattr(self, "disable_initiator_tag", None) is None:
1125
1085
            return
1126
1086
        # Reschedule timeout
1127
1087
        gobject.source_remove(self.disable_initiator_tag)
1128
1088
        self.disable_initiator_tag = None
1129
 
        self.expires = None
1130
1089
        time_to_die = (self.
1131
1090
                       _timedelta_to_milliseconds((self
1132
1091
                                                   .last_checked_ok
1137
1096
            # The timeout has passed
1138
1097
            self.disable()
1139
1098
        else:
1140
 
            self.expires = (datetime.datetime.utcnow()
1141
 
                            + datetime.timedelta(milliseconds = time_to_die))
1142
1099
            self.disable_initiator_tag = (gobject.timeout_add
1143
1100
                                          (time_to_die, self.disable))
1144
 
 
1145
 
    # ExtendedTimeout - property
1146
 
    @dbus_service_property(_interface, signature="t",
1147
 
                           access="readwrite")
1148
 
    def ExtendedTimeout_dbus_property(self, value=None):
1149
 
        if value is None:       # get
1150
 
            return dbus.UInt64(self.extended_timeout_milliseconds())
1151
 
        old_value = self.extended_timeout
1152
 
        self.extended_timeout = datetime.timedelta(0, 0, 0, value)
1153
 
        # Emit D-Bus signal
1154
 
        if old_value != self.extended_timeout:
1155
 
            self.PropertyChanged(dbus.String("ExtendedTimeout"),
1156
 
                                 dbus.UInt64(value, variant_level=1))
1157
 
 
 
1101
    
1158
1102
    # Interval - property
1159
1103
    @dbus_service_property(_interface, signature="t",
1160
1104
                           access="readwrite")
1161
1105
    def Interval_dbus_property(self, value=None):
1162
1106
        if value is None:       # get
1163
1107
            return dbus.UInt64(self.interval_milliseconds())
1164
 
        old_value = self.interval
1165
1108
        self.interval = datetime.timedelta(0, 0, 0, value)
1166
1109
        # Emit D-Bus signal
1167
 
        if old_value != self.interval:
1168
 
            self.PropertyChanged(dbus.String("Interval"),
1169
 
                                 dbus.UInt64(value, variant_level=1))
 
1110
        self.PropertyChanged(dbus.String("Interval"),
 
1111
                             dbus.UInt64(value, variant_level=1))
1170
1112
        if getattr(self, "checker_initiator_tag", None) is None:
1171
1113
            return
1172
1114
        # Reschedule checker run
1181
1123
    def Checker_dbus_property(self, value=None):
1182
1124
        if value is None:       # get
1183
1125
            return dbus.String(self.checker_command)
1184
 
        old_value = self.checker_command
1185
1126
        self.checker_command = value
1186
1127
        # Emit D-Bus signal
1187
 
        if old_value != self.checker_command:
1188
 
            self.PropertyChanged(dbus.String("Checker"),
1189
 
                                 dbus.String(self.checker_command,
1190
 
                                             variant_level=1))
 
1128
        self.PropertyChanged(dbus.String("Checker"),
 
1129
                             dbus.String(self.checker_command,
 
1130
                                         variant_level=1))
1191
1131
    
1192
1132
    # CheckerRunning - property
1193
1133
    @dbus_service_property(_interface, signature="b",
1320
1260
                
1321
1261
                while True:
1322
1262
                    if not client.enabled:
1323
 
                        logger.info("Client %s is disabled",
 
1263
                        logger.warning("Client %s is disabled",
1324
1264
                                       client.name)
1325
1265
                        if self.server.use_dbus:
1326
1266
                            # Emit D-Bus signal
1381
1321
 
1382
1322
                logger.info("Sending secret to %s", client.name)
1383
1323
                # bump the timeout as if seen
1384
 
                client.checked_ok(client.extended_timeout)
 
1324
                client.checked_ok()
1385
1325
                if self.server.use_dbus:
1386
1326
                    # Emit D-Bus signal
1387
1327
                    client.GotSecret()
1621
1561
                    client = c
1622
1562
                    break
1623
1563
            else:
1624
 
                logger.info("Client not found for fingerprint: %s, ad"
1625
 
                            "dress: %s", fpr, address)
 
1564
                logger.warning("Client not found for fingerprint: %s, ad"
 
1565
                               "dress: %s", fpr, address)
1626
1566
                if self.use_dbus:
1627
1567
                    # Emit D-Bus signal
1628
1568
                    mandos_dbus_service.ClientNotFound(fpr, address[0])
1848
1788
                                % server_settings["servicename"]))
1849
1789
    
1850
1790
    # Parse config file with clients
1851
 
    client_defaults = { "timeout": "5m",
1852
 
                        "extended_timeout": "15m",
1853
 
                        "interval": "2m",
 
1791
    client_defaults = { "timeout": "1h",
 
1792
                        "interval": "5m",
1854
1793
                        "checker": "fping -q -- %%(host)s",
1855
1794
                        "host": "",
1856
1795
                        "approval_delay": "0s",