/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-09-26 19:36:18 UTC
  • mfrom: (24.1.184 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20110926193618-vtj5c9hena1maixx
Merge from Björn

Show diffs side-by-side

added added

removed removed

Lines of Context:
264
264
        self.server_state_changed(self.server.GetState())
265
265
 
266
266
 
 
267
def _timedelta_to_milliseconds(td):
 
268
    "Convert a datetime.timedelta() to milliseconds"
 
269
    return ((td.days * 24 * 60 * 60 * 1000)
 
270
            + (td.seconds * 1000)
 
271
            + (td.microseconds // 1000))
 
272
        
267
273
class Client(object):
268
274
    """A representation of a client host served by this server.
269
275
    
299
305
                                      until this client is disabled
300
306
    extended_timeout:   extra long timeout when password has been sent
301
307
    runtime_expansions: Allowed attributes for runtime expansion.
302
 
    expire:     datetime.datetime(); time (UTC) when a client will be
 
308
    expires:    datetime.datetime(); time (UTC) when a client will be
303
309
                disabled, or None
304
310
    """
305
311
    
307
313
                          "created", "enabled", "fingerprint",
308
314
                          "host", "interval", "last_checked_ok",
309
315
                          "last_enabled", "name", "timeout")
310
 
    
311
 
    @staticmethod
312
 
    def _timedelta_to_milliseconds(td):
313
 
        "Convert a datetime.timedelta() to milliseconds"
314
 
        return ((td.days * 24 * 60 * 60 * 1000)
315
 
                + (td.seconds * 1000)
316
 
                + (td.microseconds // 1000))
317
 
    
 
316
        
318
317
    def timeout_milliseconds(self):
319
318
        "Return the 'timeout' attribute in milliseconds"
320
 
        return self._timedelta_to_milliseconds(self.timeout)
 
319
        return _timedelta_to_milliseconds(self.timeout)
321
320
 
322
321
    def extended_timeout_milliseconds(self):
323
322
        "Return the 'extended_timeout' attribute in milliseconds"
324
 
        return self._timedelta_to_milliseconds(self.extended_timeout)    
 
323
        return _timedelta_to_milliseconds(self.extended_timeout)    
325
324
    
326
325
    def interval_milliseconds(self):
327
326
        "Return the 'interval' attribute in milliseconds"
328
 
        return self._timedelta_to_milliseconds(self.interval)
 
327
        return _timedelta_to_milliseconds(self.interval)
329
328
 
330
329
    def approval_delay_milliseconds(self):
331
 
        return self._timedelta_to_milliseconds(self.approval_delay)
 
330
        return _timedelta_to_milliseconds(self.approval_delay)
332
331
    
333
332
    def __init__(self, name = None, disable_hook=None, config=None):
334
333
        """Note: the 'checker' key in 'config' sets the
393
392
            # Already enabled
394
393
            return
395
394
        self.send_changedstate()
396
 
        self.last_enabled = datetime.datetime.utcnow()
397
395
        # Schedule a new checker to be started an 'interval' from now,
398
396
        # and every interval from then on.
399
397
        self.checker_initiator_tag = (gobject.timeout_add
405
403
                                   (self.timeout_milliseconds(),
406
404
                                    self.disable))
407
405
        self.enabled = True
 
406
        self.last_enabled = datetime.datetime.utcnow()
408
407
        # Also start a new checker *right now*.
409
408
        self.start_checker()
410
409
    
463
462
        gobject.source_remove(self.disable_initiator_tag)
464
463
        self.expires = datetime.datetime.utcnow() + timeout
465
464
        self.disable_initiator_tag = (gobject.timeout_add
466
 
                                      (self._timedelta_to_milliseconds(timeout),
 
465
                                      (_timedelta_to_milliseconds(timeout),
467
466
                                       self.disable))
468
467
    
469
468
    def need_approval(self):
751
750
        return xmlstring
752
751
 
753
752
 
 
753
def datetime_to_dbus (dt, variant_level=0):
 
754
    """Convert a UTC datetime.datetime() to a D-Bus type."""
 
755
    if dt is None:
 
756
        return dbus.String("", variant_level = variant_level)
 
757
    return dbus.String(dt.isoformat(),
 
758
                       variant_level=variant_level)
 
759
 
754
760
class ClientDBus(Client, DBusObjectWithProperties):
755
761
    """A Client class using D-Bus
756
762
    
777
783
                                 ("/clients/" + client_object_name))
778
784
        DBusObjectWithProperties.__init__(self, self.bus,
779
785
                                          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
786
        
791
 
    def _get_approvals_pending(self):
792
 
        return self._approvals_pending
793
 
    def _set_approvals_pending(self, value):
794
 
        old_value = self._approvals_pending
795
 
        self._approvals_pending = value
796
 
        bval = bool(value)
797
 
        if (hasattr(self, "dbus_object_path")
798
 
            and bval is not bool(old_value)):
799
 
            dbus_bool = dbus.Boolean(bval, variant_level=1)
800
 
            self.PropertyChanged(dbus.String("ApprovalPending"),
801
 
                                 dbus_bool)
802
 
 
803
 
    approvals_pending = property(_get_approvals_pending,
804
 
                                 _set_approvals_pending)
805
 
    del _get_approvals_pending, _set_approvals_pending
806
 
    
807
 
    @staticmethod
808
 
    def _datetime_to_dbus(dt, variant_level=0):
809
 
        """Convert a UTC datetime.datetime() to a D-Bus type."""
810
 
        if dt is None:
811
 
            return dbus.String("", variant_level = variant_level)
812
 
        return dbus.String(dt.isoformat(),
813
 
                           variant_level=variant_level)
814
 
    
815
 
    def enable(self):
816
 
        oldstate = getattr(self, "enabled", False)
817
 
        r = Client.enable(self)
818
 
        if oldstate != self.enabled:
819
 
            # Emit D-Bus signals
820
 
            self.PropertyChanged(dbus.String("Enabled"),
821
 
                                 dbus.Boolean(True, variant_level=1))
822
 
            self.PropertyChanged(
823
 
                dbus.String("LastEnabled"),
824
 
                self._datetime_to_dbus(self.last_enabled,
825
 
                                       variant_level=1))
826
 
        return r
827
 
    
828
 
    def disable(self, quiet = False):
829
 
        oldstate = getattr(self, "enabled", False)
830
 
        r = Client.disable(self, quiet=quiet)
831
 
        if not quiet and oldstate != self.enabled:
832
 
            # Emit D-Bus signal
833
 
            self.PropertyChanged(dbus.String("Enabled"),
834
 
                                 dbus.Boolean(False, variant_level=1))
835
 
        return r
 
787
    def notifychangeproperty(transform_func,
 
788
                             dbus_name, type_func=lambda x: x,
 
789
                             variant_level=1):
 
790
        """ Modify a variable so that its a property that announce its
 
791
        changes to DBus.
 
792
        transform_fun: Function that takes a value and transform it to
 
793
                       DBus type.
 
794
        dbus_name: DBus name of the variable
 
795
        type_func: Function that transform the value before sending it
 
796
                   to DBus
 
797
        variant_level: DBus variant level. default: 1
 
798
        """
 
799
        real_value = [None,]
 
800
        def setter(self, value):
 
801
            old_value = real_value[0]
 
802
            real_value[0] = value
 
803
            if hasattr(self, "dbus_object_path"):
 
804
                if type_func(old_value) != type_func(real_value[0]):
 
805
                    dbus_value = transform_func(type_func(real_value[0]),
 
806
                                                variant_level)
 
807
                    self.PropertyChanged(dbus.String(dbus_name),
 
808
                                         dbus_value)
 
809
 
 
810
        return property(lambda self: real_value[0], setter)
 
811
 
 
812
 
 
813
    expires = notifychangeproperty(datetime_to_dbus, "Expires")
 
814
    approvals_pending = notifychangeproperty(dbus.Boolean,
 
815
                                             "ApprovalPending",
 
816
                                             type_func = bool)
 
817
    enabled = notifychangeproperty(dbus.Boolean, "Enabled")
 
818
    last_enabled = notifychangeproperty(datetime_to_dbus,
 
819
                                        "LastEnabled")
 
820
    checker = notifychangeproperty(dbus.Boolean, "CheckerRunning",
 
821
                                   type_func = lambda checker: checker is not None)
 
822
    last_checked_ok = notifychangeproperty(datetime_to_dbus,
 
823
                                           "LastCheckedOK")
 
824
    last_approval_request = notifychangeproperty(datetime_to_dbus,
 
825
                                                 "LastApprovalRequest")
 
826
    approved_by_default = notifychangeproperty(dbus.Boolean,
 
827
                                               "ApprovedByDefault")
 
828
    approval_delay = notifychangeproperty(dbus.UInt16, "ApprovalDelay",
 
829
                                          type_func = _timedelta_to_milliseconds)
 
830
    approval_duration = notifychangeproperty(dbus.UInt16, "ApprovalDuration",
 
831
                                             type_func = _timedelta_to_milliseconds)
 
832
    host = notifychangeproperty(dbus.String, "Host")
 
833
    timeout = notifychangeproperty(dbus.UInt16, "Timeout",
 
834
                                   type_func = _timedelta_to_milliseconds)
 
835
    extended_timeout = notifychangeproperty(dbus.UInt16, "ExtendedTimeout",
 
836
                                            type_func = _timedelta_to_milliseconds)
 
837
    interval = notifychangeproperty(dbus.UInt16, "Interval",
 
838
                                    type_func = _timedelta_to_milliseconds)
 
839
    checker_command = notifychangeproperty(dbus.String, "Checker")
 
840
    
 
841
    del notifychangeproperty
836
842
    
837
843
    def __del__(self, *args, **kwargs):
838
844
        try:
847
853
                         *args, **kwargs):
848
854
        self.checker_callback_tag = None
849
855
        self.checker = None
850
 
        # Emit D-Bus signal
851
 
        self.PropertyChanged(dbus.String("CheckerRunning"),
852
 
                             dbus.Boolean(False, variant_level=1))
853
856
        if os.WIFEXITED(condition):
854
857
            exitstatus = os.WEXITSTATUS(condition)
855
858
            # Emit D-Bus signal
864
867
        
865
868
        return Client.checker_callback(self, pid, condition, command,
866
869
                                       *args, **kwargs)
867
 
    
868
 
    def checked_ok(self, *args, **kwargs):
869
 
        Client.checked_ok(self, *args, **kwargs)
870
 
        # Emit D-Bus signal
871
 
        self.PropertyChanged(
872
 
            dbus.String("LastCheckedOK"),
873
 
            (self._datetime_to_dbus(self.last_checked_ok,
874
 
                                    variant_level=1)))
875
 
    
876
 
    def need_approval(self, *args, **kwargs):
877
 
        r = Client.need_approval(self, *args, **kwargs)
878
 
        # Emit D-Bus signal
879
 
        self.PropertyChanged(
880
 
            dbus.String("LastApprovalRequest"),
881
 
            (self._datetime_to_dbus(self.last_approval_request,
882
 
                                    variant_level=1)))
883
 
        return r
884
 
    
 
870
 
885
871
    def start_checker(self, *args, **kwargs):
886
872
        old_checker = self.checker
887
873
        if self.checker is not None:
894
880
            and old_checker_pid != self.checker.pid):
895
881
            # Emit D-Bus signal
896
882
            self.CheckerStarted(self.current_checker_command)
897
 
            self.PropertyChanged(
898
 
                dbus.String("CheckerRunning"),
899
 
                dbus.Boolean(True, variant_level=1))
900
883
        return r
901
884
    
902
 
    def stop_checker(self, *args, **kwargs):
903
 
        old_checker = getattr(self, "checker", None)
904
 
        r = Client.stop_checker(self, *args, **kwargs)
905
 
        if (old_checker is not None
906
 
            and getattr(self, "checker", None) is None):
907
 
            self.PropertyChanged(dbus.String("CheckerRunning"),
908
 
                                 dbus.Boolean(False, variant_level=1))
909
 
        return r
910
 
 
911
885
    def _reset_approved(self):
912
886
        self._approved = None
913
887
        return False
915
889
    def approve(self, value=True):
916
890
        self.send_changedstate()
917
891
        self._approved = value
918
 
        gobject.timeout_add(self._timedelta_to_milliseconds
 
892
        gobject.timeout_add(_timedelta_to_milliseconds
919
893
                            (self.approval_duration),
920
894
                            self._reset_approved)
921
895
    
1012
986
    def ApprovedByDefault_dbus_property(self, value=None):
1013
987
        if value is None:       # get
1014
988
            return dbus.Boolean(self.approved_by_default)
1015
 
        old_value = self.approved_by_default
1016
989
        self.approved_by_default = bool(value)
1017
 
        # 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))
1021
990
    
1022
991
    # ApprovalDelay - property
1023
992
    @dbus_service_property(_interface, signature="t",
1025
994
    def ApprovalDelay_dbus_property(self, value=None):
1026
995
        if value is None:       # get
1027
996
            return dbus.UInt64(self.approval_delay_milliseconds())
1028
 
        old_value = self.approval_delay
1029
997
        self.approval_delay = datetime.timedelta(0, 0, 0, value)
1030
 
        # Emit D-Bus signal
1031
 
        if old_value != self.approval_delay:
1032
 
            self.PropertyChanged(dbus.String("ApprovalDelay"),
1033
 
                                 dbus.UInt64(value, variant_level=1))
1034
998
    
1035
999
    # ApprovalDuration - property
1036
1000
    @dbus_service_property(_interface, signature="t",
1037
1001
                           access="readwrite")
1038
1002
    def ApprovalDuration_dbus_property(self, value=None):
1039
1003
        if value is None:       # get
1040
 
            return dbus.UInt64(self._timedelta_to_milliseconds(
 
1004
            return dbus.UInt64(_timedelta_to_milliseconds(
1041
1005
                    self.approval_duration))
1042
 
        old_value = self.approval_duration
1043
1006
        self.approval_duration = datetime.timedelta(0, 0, 0, value)
1044
 
        # Emit D-Bus signal
1045
 
        if old_value != self.approval_duration:
1046
 
            self.PropertyChanged(dbus.String("ApprovalDuration"),
1047
 
                                 dbus.UInt64(value, variant_level=1))
1048
1007
    
1049
1008
    # Name - property
1050
1009
    @dbus_service_property(_interface, signature="s", access="read")
1062
1021
    def Host_dbus_property(self, value=None):
1063
1022
        if value is None:       # get
1064
1023
            return dbus.String(self.host)
1065
 
        old_value = self.host
1066
1024
        self.host = value
1067
 
        # Emit D-Bus signal
1068
 
        if old_value != self.host:
1069
 
            self.PropertyChanged(dbus.String("Host"),
1070
 
                                 dbus.String(value, variant_level=1))
1071
1025
    
1072
1026
    # Created - property
1073
1027
    @dbus_service_property(_interface, signature="s", access="read")
1074
1028
    def Created_dbus_property(self):
1075
 
        return dbus.String(self._datetime_to_dbus(self.created))
 
1029
        return dbus.String(datetime_to_dbus(self.created))
1076
1030
    
1077
1031
    # LastEnabled - property
1078
1032
    @dbus_service_property(_interface, signature="s", access="read")
1079
1033
    def LastEnabled_dbus_property(self):
1080
 
        return self._datetime_to_dbus(self.last_enabled)
 
1034
        return datetime_to_dbus(self.last_enabled)
1081
1035
    
1082
1036
    # Enabled - property
1083
1037
    @dbus_service_property(_interface, signature="b",
1097
1051
        if value is not None:
1098
1052
            self.checked_ok()
1099
1053
            return
1100
 
        return self._datetime_to_dbus(self.last_checked_ok)
 
1054
        return datetime_to_dbus(self.last_checked_ok)
1101
1055
    
1102
1056
    # Expires - property
1103
1057
    @dbus_service_property(_interface, signature="s", access="read")
1104
1058
    def Expires_dbus_property(self):
1105
 
        return self._datetime_to_dbus(self.expires)
 
1059
        return datetime_to_dbus(self.expires)
1106
1060
    
1107
1061
    # LastApprovalRequest - property
1108
1062
    @dbus_service_property(_interface, signature="s", access="read")
1109
1063
    def LastApprovalRequest_dbus_property(self):
1110
 
        return self._datetime_to_dbus(self.last_approval_request)
 
1064
        return datetime_to_dbus(self.last_approval_request)
1111
1065
    
1112
1066
    # Timeout - property
1113
1067
    @dbus_service_property(_interface, signature="t",
1115
1069
    def Timeout_dbus_property(self, value=None):
1116
1070
        if value is None:       # get
1117
1071
            return dbus.UInt64(self.timeout_milliseconds())
1118
 
        old_value = self.timeout
1119
1072
        self.timeout = datetime.timedelta(0, 0, 0, value)
1120
 
        # Emit D-Bus signal
1121
 
        if old_value != self.timeout:
1122
 
            self.PropertyChanged(dbus.String("Timeout"),
1123
 
                                 dbus.UInt64(value, variant_level=1))
1124
1073
        if getattr(self, "disable_initiator_tag", None) is None:
1125
1074
            return
1126
1075
        # Reschedule timeout
1148
1097
    def ExtendedTimeout_dbus_property(self, value=None):
1149
1098
        if value is None:       # get
1150
1099
            return dbus.UInt64(self.extended_timeout_milliseconds())
1151
 
        old_value = self.extended_timeout
1152
1100
        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",
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
 
        # Emit D-Bus signal
1167
 
        if old_value != self.interval:
1168
 
            self.PropertyChanged(dbus.String("Interval"),
1169
 
                                 dbus.UInt64(value, variant_level=1))
1170
1109
        if getattr(self, "checker_initiator_tag", None) is None:
1171
1110
            return
1172
1111
        # Reschedule checker run
1181
1120
    def Checker_dbus_property(self, value=None):
1182
1121
        if value is None:       # get
1183
1122
            return dbus.String(self.checker_command)
1184
 
        old_value = self.checker_command
1185
1123
        self.checker_command = value
1186
 
        # 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))
1191
1124
    
1192
1125
    # CheckerRunning - property
1193
1126
    @dbus_service_property(_interface, signature="b",