/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-07-25 18:50:00 UTC
  • mfrom: (24.1.176 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20110725185000-paes3keuo0dj4m0z
Merge from Björn.

Show diffs side-by-side

added added

removed removed

Lines of Context:
62
62
import functools
63
63
import cPickle as pickle
64
64
import multiprocessing
65
 
import types
66
65
 
67
66
import dbus
68
67
import dbus.service
83
82
        SO_BINDTODEVICE = None
84
83
 
85
84
 
86
 
version = "1.3.1"
 
85
version = "1.3.0"
87
86
 
88
87
#logger = logging.getLogger('mandos')
89
88
logger = logging.Logger('mandos')
265
264
        self.server_state_changed(self.server.GetState())
266
265
 
267
266
 
268
 
def _timedelta_to_milliseconds(td):
269
 
    "Convert a datetime.timedelta() to milliseconds"
270
 
    return ((td.days * 24 * 60 * 60 * 1000)
271
 
            + (td.seconds * 1000)
272
 
            + (td.microseconds // 1000))
273
 
        
274
267
class Client(object):
275
268
    """A representation of a client host served by this server.
276
269
    
304
297
    secret:     bytestring; sent verbatim (over TLS) to client
305
298
    timeout:    datetime.timedelta(); How long from last_checked_ok
306
299
                                      until this client is disabled
307
 
    extended_timeout:   extra long timeout when password has been sent
308
300
    runtime_expansions: Allowed attributes for runtime expansion.
309
 
    expires:    datetime.datetime(); time (UTC) when a client will be
310
 
                disabled, or None
311
301
    """
312
302
    
313
303
    runtime_expansions = ("approval_delay", "approval_duration",
315
305
                          "host", "interval", "last_checked_ok",
316
306
                          "last_enabled", "name", "timeout")
317
307
    
 
308
    @staticmethod
 
309
    def _timedelta_to_milliseconds(td):
 
310
        "Convert a datetime.timedelta() to milliseconds"
 
311
        return ((td.days * 24 * 60 * 60 * 1000)
 
312
                + (td.seconds * 1000)
 
313
                + (td.microseconds // 1000))
 
314
    
318
315
    def timeout_milliseconds(self):
319
316
        "Return the 'timeout' attribute in milliseconds"
320
 
        return _timedelta_to_milliseconds(self.timeout)
321
 
    
322
 
    def extended_timeout_milliseconds(self):
323
 
        "Return the 'extended_timeout' attribute in milliseconds"
324
 
        return _timedelta_to_milliseconds(self.extended_timeout)    
 
317
        return self._timedelta_to_milliseconds(self.timeout)
325
318
    
326
319
    def interval_milliseconds(self):
327
320
        "Return the 'interval' attribute in milliseconds"
328
 
        return _timedelta_to_milliseconds(self.interval)
329
 
    
 
321
        return self._timedelta_to_milliseconds(self.interval)
 
322
 
330
323
    def approval_delay_milliseconds(self):
331
 
        return _timedelta_to_milliseconds(self.approval_delay)
 
324
        return self._timedelta_to_milliseconds(self.approval_delay)
332
325
    
333
326
    def __init__(self, name = None, disable_hook=None, config=None):
334
327
        """Note: the 'checker' key in 'config' sets the
361
354
        self.last_enabled = None
362
355
        self.last_checked_ok = None
363
356
        self.timeout = string_to_delta(config["timeout"])
364
 
        self.extended_timeout = string_to_delta(config["extended_timeout"])
365
357
        self.interval = string_to_delta(config["interval"])
366
358
        self.disable_hook = disable_hook
367
359
        self.checker = None
368
360
        self.checker_initiator_tag = None
369
361
        self.disable_initiator_tag = None
370
 
        self.expires = None
371
362
        self.checker_callback_tag = None
372
363
        self.checker_command = config["checker"]
373
364
        self.current_checker_command = None
393
384
            # Already enabled
394
385
            return
395
386
        self.send_changedstate()
 
387
        self.last_enabled = datetime.datetime.utcnow()
396
388
        # Schedule a new checker to be started an 'interval' from now,
397
389
        # and every interval from then on.
398
390
        self.checker_initiator_tag = (gobject.timeout_add
399
391
                                      (self.interval_milliseconds(),
400
392
                                       self.start_checker))
401
393
        # Schedule a disable() when 'timeout' has passed
402
 
        self.expires = datetime.datetime.utcnow() + self.timeout
403
394
        self.disable_initiator_tag = (gobject.timeout_add
404
395
                                   (self.timeout_milliseconds(),
405
396
                                    self.disable))
406
397
        self.enabled = True
407
 
        self.last_enabled = datetime.datetime.utcnow()
408
398
        # Also start a new checker *right now*.
409
399
        self.start_checker()
410
400
    
419
409
        if getattr(self, "disable_initiator_tag", False):
420
410
            gobject.source_remove(self.disable_initiator_tag)
421
411
            self.disable_initiator_tag = None
422
 
        self.expires = None
423
412
        if getattr(self, "checker_initiator_tag", False):
424
413
            gobject.source_remove(self.checker_initiator_tag)
425
414
            self.checker_initiator_tag = None
451
440
            logger.warning("Checker for %(name)s crashed?",
452
441
                           vars(self))
453
442
    
454
 
    def checked_ok(self, timeout=None):
 
443
    def checked_ok(self):
455
444
        """Bump up the timeout for this client.
456
445
        
457
446
        This should only be called when the client has been seen,
458
447
        alive and well.
459
448
        """
460
 
        if timeout is None:
461
 
            timeout = self.timeout
462
449
        self.last_checked_ok = datetime.datetime.utcnow()
463
450
        gobject.source_remove(self.disable_initiator_tag)
464
 
        self.expires = datetime.datetime.utcnow() + timeout
465
451
        self.disable_initiator_tag = (gobject.timeout_add
466
 
                                      (_timedelta_to_milliseconds(timeout),
 
452
                                      (self.timeout_milliseconds(),
467
453
                                       self.disable))
468
454
    
469
455
    def need_approval(self):
510
496
                                       'replace')))
511
497
                    for attr in
512
498
                    self.runtime_expansions)
513
 
                
 
499
 
514
500
                try:
515
501
                    command = self.checker_command % escaped_attrs
516
502
                except TypeError as error:
562
548
                raise
563
549
        self.checker = None
564
550
 
565
 
 
566
551
def dbus_service_property(dbus_interface, signature="v",
567
552
                          access="readwrite", byte_arrays=False):
568
553
    """Decorators for marking methods of a DBusObjectWithProperties to
614
599
 
615
600
class DBusObjectWithProperties(dbus.service.Object):
616
601
    """A D-Bus object with properties.
617
 
    
 
602
 
618
603
    Classes inheriting from this can use the dbus_service_property
619
604
    decorator to expose methods as D-Bus properties.  It exposes the
620
605
    standard Get(), Set(), and GetAll() methods on the D-Bus.
627
612
    def _get_all_dbus_properties(self):
628
613
        """Returns a generator of (name, attribute) pairs
629
614
        """
630
 
        return ((prop.__get__(self)._dbus_name, prop.__get__(self))
631
 
                for cls in self.__class__.__mro__
632
 
                for name, prop in inspect.getmembers(cls, self._is_dbus_property))
 
615
        return ((prop._dbus_name, prop)
 
616
                for name, prop in
 
617
                inspect.getmembers(self, self._is_dbus_property))
633
618
    
634
619
    def _get_dbus_property(self, interface_name, property_name):
635
620
        """Returns a bound method if one exists which is a D-Bus
636
621
        property with the specified name and interface.
637
622
        """
638
 
        for cls in  self.__class__.__mro__:
639
 
            for name, value in inspect.getmembers(cls, self._is_dbus_property):
640
 
                if value._dbus_name == property_name and value._dbus_interface == interface_name:
641
 
                    return value.__get__(self)
642
 
        
 
623
        for name in (property_name,
 
624
                     property_name + "_dbus_property"):
 
625
            prop = getattr(self, name, None)
 
626
            if (prop is None
 
627
                or not self._is_dbus_property(prop)
 
628
                or prop._dbus_name != property_name
 
629
                or (interface_name and prop._dbus_interface
 
630
                    and interface_name != prop._dbus_interface)):
 
631
                continue
 
632
            return prop
643
633
        # No such property
644
634
        raise DBusPropertyNotFound(self.dbus_object_path + ":"
645
635
                                   + interface_name + "."
679
669
    def GetAll(self, interface_name):
680
670
        """Standard D-Bus property GetAll() method, see D-Bus
681
671
        standard.
682
 
        
 
672
 
683
673
        Note: Will not include properties with access="write".
684
674
        """
685
675
        all = {}
747
737
        return xmlstring
748
738
 
749
739
 
750
 
def datetime_to_dbus (dt, variant_level=0):
751
 
    """Convert a UTC datetime.datetime() to a D-Bus type."""
752
 
    if dt is None:
753
 
        return dbus.String("", variant_level = variant_level)
754
 
    return dbus.String(dt.isoformat(),
755
 
                       variant_level=variant_level)
756
 
 
757
 
class transitional_dbus_metaclass(DBusObjectWithProperties.__metaclass__):
758
 
    def __new__(mcs, name, bases, attr):
759
 
        for attrname, old_dbusobj in inspect.getmembers(bases[0]):
760
 
            new_interface = getattr(old_dbusobj, "_dbus_interface", "").replace("se.bsnet.fukt.", "se.recompile.")
761
 
            if (getattr(old_dbusobj, "_dbus_is_signal", False)
762
 
                and old_dbusobj._dbus_interface.startswith("se.bsnet.fukt.Mandos")):
763
 
                unwrappedfunc = dict(zip(old_dbusobj.func_code.co_freevars,
764
 
                                    old_dbusobj.__closure__))["func"].cell_contents
765
 
                newfunc = types.FunctionType(unwrappedfunc.func_code,
766
 
                                             unwrappedfunc.func_globals,
767
 
                                             unwrappedfunc.func_name,
768
 
                                             unwrappedfunc.func_defaults,
769
 
                                             unwrappedfunc.func_closure)
770
 
                new_dbusfunc = dbus.service.signal(
771
 
                    new_interface, old_dbusobj._dbus_signature)(newfunc)            
772
 
                attr["_transitional_" + attrname] = new_dbusfunc
773
 
 
774
 
                def fixscope(func1, func2):
775
 
                    def newcall(*args, **kwargs):
776
 
                        func1(*args, **kwargs)
777
 
                        func2(*args, **kwargs)
778
 
                    return newcall
779
 
 
780
 
                attr[attrname] = fixscope(old_dbusobj, new_dbusfunc)
781
 
            
782
 
            elif (getattr(old_dbusobj, "_dbus_is_method", False)
783
 
                and old_dbusobj._dbus_interface.startswith("se.bsnet.fukt.Mandos")):
784
 
                new_dbusfunc = (dbus.service.method
785
 
                                (new_interface,
786
 
                                 old_dbusobj._dbus_in_signature,
787
 
                                 old_dbusobj._dbus_out_signature)
788
 
                                (types.FunctionType
789
 
                                 (old_dbusobj.func_code,
790
 
                                  old_dbusobj.func_globals,
791
 
                                  old_dbusobj.func_name,
792
 
                                  old_dbusobj.func_defaults,
793
 
                                  old_dbusobj.func_closure)))
794
 
 
795
 
                attr[attrname] = new_dbusfunc
796
 
            elif (getattr(old_dbusobj, "_dbus_is_property", False)
797
 
                  and old_dbusobj._dbus_interface.startswith("se.bsnet.fukt.Mandos")):
798
 
                new_dbusfunc = (dbus_service_property
799
 
                                (new_interface,
800
 
                                 old_dbusobj._dbus_signature,
801
 
                                 old_dbusobj._dbus_access,
802
 
                                 old_dbusobj._dbus_get_args_options["byte_arrays"])
803
 
                                (types.FunctionType
804
 
                                 (old_dbusobj.func_code,
805
 
                                  old_dbusobj.func_globals,
806
 
                                  old_dbusobj.func_name,
807
 
                                  old_dbusobj.func_defaults,
808
 
                                  old_dbusobj.func_closure)))
809
 
 
810
 
                attr[attrname] = new_dbusfunc
811
 
        return type.__new__(mcs, name, bases, attr)
812
 
 
813
740
class ClientDBus(Client, DBusObjectWithProperties):
814
741
    """A Client class using D-Bus
815
742
    
837
764
        DBusObjectWithProperties.__init__(self, self.bus,
838
765
                                          self.dbus_object_path)
839
766
        
840
 
    def notifychangeproperty(transform_func,
841
 
                             dbus_name, type_func=lambda x: x,
842
 
                             variant_level=1):
843
 
        """ Modify a variable so that its a property that announce its
844
 
        changes to DBus.
845
 
        transform_fun: Function that takes a value and transform it to
846
 
                       DBus type.
847
 
        dbus_name: DBus name of the variable
848
 
        type_func: Function that transform the value before sending it
849
 
                   to DBus
850
 
        variant_level: DBus variant level. default: 1
851
 
        """
852
 
        real_value = [None,]
853
 
        def setter(self, value):
854
 
            old_value = real_value[0]
855
 
            real_value[0] = value
856
 
            if hasattr(self, "dbus_object_path"):
857
 
                if type_func(old_value) != type_func(real_value[0]):
858
 
                    dbus_value = transform_func(type_func(real_value[0]),
859
 
                                                variant_level)
860
 
                    self.PropertyChanged(dbus.String(dbus_name),
861
 
                                         dbus_value)
862
 
        
863
 
        return property(lambda self: real_value[0], setter)
864
 
    
865
 
    
866
 
    expires = notifychangeproperty(datetime_to_dbus, "Expires")
867
 
    approvals_pending = notifychangeproperty(dbus.Boolean,
868
 
                                             "ApprovalPending",
869
 
                                             type_func = bool)
870
 
    enabled = notifychangeproperty(dbus.Boolean, "Enabled")
871
 
    last_enabled = notifychangeproperty(datetime_to_dbus,
872
 
                                        "LastEnabled")
873
 
    checker = notifychangeproperty(dbus.Boolean, "CheckerRunning",
874
 
                                   type_func = lambda checker: checker is not None)
875
 
    last_checked_ok = notifychangeproperty(datetime_to_dbus,
876
 
                                           "LastCheckedOK")
877
 
    last_approval_request = notifychangeproperty(datetime_to_dbus,
878
 
                                                 "LastApprovalRequest")
879
 
    approved_by_default = notifychangeproperty(dbus.Boolean,
880
 
                                               "ApprovedByDefault")
881
 
    approval_delay = notifychangeproperty(dbus.UInt16, "ApprovalDelay",
882
 
                                          type_func = _timedelta_to_milliseconds)
883
 
    approval_duration = notifychangeproperty(dbus.UInt16, "ApprovalDuration",
884
 
                                             type_func = _timedelta_to_milliseconds)
885
 
    host = notifychangeproperty(dbus.String, "Host")
886
 
    timeout = notifychangeproperty(dbus.UInt16, "Timeout",
887
 
                                   type_func = _timedelta_to_milliseconds)
888
 
    extended_timeout = notifychangeproperty(dbus.UInt16, "ExtendedTimeout",
889
 
                                            type_func = _timedelta_to_milliseconds)
890
 
    interval = notifychangeproperty(dbus.UInt16, "Interval",
891
 
                                    type_func = _timedelta_to_milliseconds)
892
 
    checker_command = notifychangeproperty(dbus.String, "Checker")
893
 
    
894
 
    del notifychangeproperty
 
767
    def _get_approvals_pending(self):
 
768
        return self._approvals_pending
 
769
    def _set_approvals_pending(self, value):
 
770
        old_value = self._approvals_pending
 
771
        self._approvals_pending = value
 
772
        bval = bool(value)
 
773
        if (hasattr(self, "dbus_object_path")
 
774
            and bval is not bool(old_value)):
 
775
            dbus_bool = dbus.Boolean(bval, variant_level=1)
 
776
            self.PropertyChanged(dbus.String("ApprovalPending"),
 
777
                                 dbus_bool)
 
778
 
 
779
    approvals_pending = property(_get_approvals_pending,
 
780
                                 _set_approvals_pending)
 
781
    del _get_approvals_pending, _set_approvals_pending
 
782
    
 
783
    @staticmethod
 
784
    def _datetime_to_dbus(dt, variant_level=0):
 
785
        """Convert a UTC datetime.datetime() to a D-Bus type."""
 
786
        return dbus.String(dt.isoformat(),
 
787
                           variant_level=variant_level)
 
788
    
 
789
    def enable(self):
 
790
        oldstate = getattr(self, "enabled", False)
 
791
        r = Client.enable(self)
 
792
        if oldstate != self.enabled:
 
793
            # Emit D-Bus signals
 
794
            self.PropertyChanged(dbus.String("Enabled"),
 
795
                                 dbus.Boolean(True, variant_level=1))
 
796
            self.PropertyChanged(
 
797
                dbus.String("LastEnabled"),
 
798
                self._datetime_to_dbus(self.last_enabled,
 
799
                                       variant_level=1))
 
800
        return r
 
801
    
 
802
    def disable(self, quiet = False):
 
803
        oldstate = getattr(self, "enabled", False)
 
804
        r = Client.disable(self, quiet=quiet)
 
805
        if not quiet and oldstate != self.enabled:
 
806
            # Emit D-Bus signal
 
807
            self.PropertyChanged(dbus.String("Enabled"),
 
808
                                 dbus.Boolean(False, variant_level=1))
 
809
        return r
895
810
    
896
811
    def __del__(self, *args, **kwargs):
897
812
        try:
906
821
                         *args, **kwargs):
907
822
        self.checker_callback_tag = None
908
823
        self.checker = None
 
824
        # Emit D-Bus signal
 
825
        self.PropertyChanged(dbus.String("CheckerRunning"),
 
826
                             dbus.Boolean(False, variant_level=1))
909
827
        if os.WIFEXITED(condition):
910
828
            exitstatus = os.WEXITSTATUS(condition)
911
829
            # Emit D-Bus signal
921
839
        return Client.checker_callback(self, pid, condition, command,
922
840
                                       *args, **kwargs)
923
841
    
 
842
    def checked_ok(self, *args, **kwargs):
 
843
        Client.checked_ok(self, *args, **kwargs)
 
844
        # Emit D-Bus signal
 
845
        self.PropertyChanged(
 
846
            dbus.String("LastCheckedOK"),
 
847
            (self._datetime_to_dbus(self.last_checked_ok,
 
848
                                    variant_level=1)))
 
849
    
 
850
    def need_approval(self, *args, **kwargs):
 
851
        r = Client.need_approval(self, *args, **kwargs)
 
852
        # Emit D-Bus signal
 
853
        self.PropertyChanged(
 
854
            dbus.String("LastApprovalRequest"),
 
855
            (self._datetime_to_dbus(self.last_approval_request,
 
856
                                    variant_level=1)))
 
857
        return r
 
858
    
924
859
    def start_checker(self, *args, **kwargs):
925
860
        old_checker = self.checker
926
861
        if self.checker is not None:
933
868
            and old_checker_pid != self.checker.pid):
934
869
            # Emit D-Bus signal
935
870
            self.CheckerStarted(self.current_checker_command)
 
871
            self.PropertyChanged(
 
872
                dbus.String("CheckerRunning"),
 
873
                dbus.Boolean(True, variant_level=1))
936
874
        return r
937
875
    
 
876
    def stop_checker(self, *args, **kwargs):
 
877
        old_checker = getattr(self, "checker", None)
 
878
        r = Client.stop_checker(self, *args, **kwargs)
 
879
        if (old_checker is not None
 
880
            and getattr(self, "checker", None) is None):
 
881
            self.PropertyChanged(dbus.String("CheckerRunning"),
 
882
                                 dbus.Boolean(False, variant_level=1))
 
883
        return r
 
884
 
938
885
    def _reset_approved(self):
939
886
        self._approved = None
940
887
        return False
942
889
    def approve(self, value=True):
943
890
        self.send_changedstate()
944
891
        self._approved = value
945
 
        gobject.timeout_add(_timedelta_to_milliseconds
 
892
        gobject.timeout_add(self._timedelta_to_milliseconds
946
893
                            (self.approval_duration),
947
894
                            self._reset_approved)
948
895
    
1040
987
        if value is None:       # get
1041
988
            return dbus.Boolean(self.approved_by_default)
1042
989
        self.approved_by_default = bool(value)
 
990
        # Emit D-Bus signal
 
991
        self.PropertyChanged(dbus.String("ApprovedByDefault"),
 
992
                             dbus.Boolean(value, variant_level=1))
1043
993
    
1044
994
    # ApprovalDelay - property
1045
995
    @dbus_service_property(_interface, signature="t",
1048
998
        if value is None:       # get
1049
999
            return dbus.UInt64(self.approval_delay_milliseconds())
1050
1000
        self.approval_delay = datetime.timedelta(0, 0, 0, value)
 
1001
        # Emit D-Bus signal
 
1002
        self.PropertyChanged(dbus.String("ApprovalDelay"),
 
1003
                             dbus.UInt64(value, variant_level=1))
1051
1004
    
1052
1005
    # ApprovalDuration - property
1053
1006
    @dbus_service_property(_interface, signature="t",
1054
1007
                           access="readwrite")
1055
1008
    def ApprovalDuration_dbus_property(self, value=None):
1056
1009
        if value is None:       # get
1057
 
            return dbus.UInt64(_timedelta_to_milliseconds(
 
1010
            return dbus.UInt64(self._timedelta_to_milliseconds(
1058
1011
                    self.approval_duration))
1059
1012
        self.approval_duration = datetime.timedelta(0, 0, 0, value)
 
1013
        # Emit D-Bus signal
 
1014
        self.PropertyChanged(dbus.String("ApprovalDuration"),
 
1015
                             dbus.UInt64(value, variant_level=1))
1060
1016
    
1061
1017
    # Name - property
1062
1018
    @dbus_service_property(_interface, signature="s", access="read")
1075
1031
        if value is None:       # get
1076
1032
            return dbus.String(self.host)
1077
1033
        self.host = value
 
1034
        # Emit D-Bus signal
 
1035
        self.PropertyChanged(dbus.String("Host"),
 
1036
                             dbus.String(value, variant_level=1))
1078
1037
    
1079
1038
    # Created - property
1080
1039
    @dbus_service_property(_interface, signature="s", access="read")
1081
1040
    def Created_dbus_property(self):
1082
 
        return dbus.String(datetime_to_dbus(self.created))
 
1041
        return dbus.String(self._datetime_to_dbus(self.created))
1083
1042
    
1084
1043
    # LastEnabled - property
1085
1044
    @dbus_service_property(_interface, signature="s", access="read")
1086
1045
    def LastEnabled_dbus_property(self):
1087
 
        return datetime_to_dbus(self.last_enabled)
 
1046
        if self.last_enabled is None:
 
1047
            return dbus.String("")
 
1048
        return dbus.String(self._datetime_to_dbus(self.last_enabled))
1088
1049
    
1089
1050
    # Enabled - property
1090
1051
    @dbus_service_property(_interface, signature="b",
1104
1065
        if value is not None:
1105
1066
            self.checked_ok()
1106
1067
            return
1107
 
        return datetime_to_dbus(self.last_checked_ok)
1108
 
    
1109
 
    # Expires - property
1110
 
    @dbus_service_property(_interface, signature="s", access="read")
1111
 
    def Expires_dbus_property(self):
1112
 
        return datetime_to_dbus(self.expires)
 
1068
        if self.last_checked_ok is None:
 
1069
            return dbus.String("")
 
1070
        return dbus.String(self._datetime_to_dbus(self
 
1071
                                                  .last_checked_ok))
1113
1072
    
1114
1073
    # LastApprovalRequest - property
1115
1074
    @dbus_service_property(_interface, signature="s", access="read")
1116
1075
    def LastApprovalRequest_dbus_property(self):
1117
 
        return datetime_to_dbus(self.last_approval_request)
 
1076
        if self.last_approval_request is None:
 
1077
            return dbus.String("")
 
1078
        return dbus.String(self.
 
1079
                           _datetime_to_dbus(self
 
1080
                                             .last_approval_request))
1118
1081
    
1119
1082
    # Timeout - property
1120
1083
    @dbus_service_property(_interface, signature="t",
1123
1086
        if value is None:       # get
1124
1087
            return dbus.UInt64(self.timeout_milliseconds())
1125
1088
        self.timeout = datetime.timedelta(0, 0, 0, value)
 
1089
        # Emit D-Bus signal
 
1090
        self.PropertyChanged(dbus.String("Timeout"),
 
1091
                             dbus.UInt64(value, variant_level=1))
1126
1092
        if getattr(self, "disable_initiator_tag", None) is None:
1127
1093
            return
1128
1094
        # Reschedule timeout
1129
1095
        gobject.source_remove(self.disable_initiator_tag)
1130
1096
        self.disable_initiator_tag = None
1131
 
        self.expires = None
1132
1097
        time_to_die = (self.
1133
1098
                       _timedelta_to_milliseconds((self
1134
1099
                                                   .last_checked_ok
1139
1104
            # The timeout has passed
1140
1105
            self.disable()
1141
1106
        else:
1142
 
            self.expires = (datetime.datetime.utcnow()
1143
 
                            + datetime.timedelta(milliseconds = time_to_die))
1144
1107
            self.disable_initiator_tag = (gobject.timeout_add
1145
1108
                                          (time_to_die, self.disable))
1146
1109
    
1147
 
    # ExtendedTimeout - property
1148
 
    @dbus_service_property(_interface, signature="t",
1149
 
                           access="readwrite")
1150
 
    def ExtendedTimeout_dbus_property(self, value=None):
1151
 
        if value is None:       # get
1152
 
            return dbus.UInt64(self.extended_timeout_milliseconds())
1153
 
        self.extended_timeout = datetime.timedelta(0, 0, 0, value)
1154
 
    
1155
1110
    # Interval - property
1156
1111
    @dbus_service_property(_interface, signature="t",
1157
1112
                           access="readwrite")
1159
1114
        if value is None:       # get
1160
1115
            return dbus.UInt64(self.interval_milliseconds())
1161
1116
        self.interval = datetime.timedelta(0, 0, 0, value)
 
1117
        # Emit D-Bus signal
 
1118
        self.PropertyChanged(dbus.String("Interval"),
 
1119
                             dbus.UInt64(value, variant_level=1))
1162
1120
        if getattr(self, "checker_initiator_tag", None) is None:
1163
1121
            return
1164
1122
        # Reschedule checker run
1166
1124
        self.checker_initiator_tag = (gobject.timeout_add
1167
1125
                                      (value, self.start_checker))
1168
1126
        self.start_checker()    # Start one now, too
1169
 
    
 
1127
 
1170
1128
    # Checker - property
1171
1129
    @dbus_service_property(_interface, signature="s",
1172
1130
                           access="readwrite")
1174
1132
        if value is None:       # get
1175
1133
            return dbus.String(self.checker_command)
1176
1134
        self.checker_command = value
 
1135
        # Emit D-Bus signal
 
1136
        self.PropertyChanged(dbus.String("Checker"),
 
1137
                             dbus.String(self.checker_command,
 
1138
                                         variant_level=1))
1177
1139
    
1178
1140
    # CheckerRunning - property
1179
1141
    @dbus_service_property(_interface, signature="b",
1206
1168
        self._pipe.send(('init', fpr, address))
1207
1169
        if not self._pipe.recv():
1208
1170
            raise KeyError()
1209
 
    
 
1171
 
1210
1172
    def __getattribute__(self, name):
1211
1173
        if(name == '_pipe'):
1212
1174
            return super(ProxyClient, self).__getattribute__(name)
1219
1181
                self._pipe.send(('funcall', name, args, kwargs))
1220
1182
                return self._pipe.recv()[1]
1221
1183
            return func
1222
 
    
 
1184
 
1223
1185
    def __setattr__(self, name, value):
1224
1186
        if(name == '_pipe'):
1225
1187
            return super(ProxyClient, self).__setattr__(name, value)
1226
1188
        self._pipe.send(('setattr', name, value))
1227
1189
 
1228
 
class ClientDBusTransitional(ClientDBus):
1229
 
    __metaclass__ = transitional_dbus_metaclass
1230
1190
 
1231
1191
class ClientHandler(socketserver.BaseRequestHandler, object):
1232
1192
    """A class to handle client connections.
1240
1200
                        unicode(self.client_address))
1241
1201
            logger.debug("Pipe FD: %d",
1242
1202
                         self.server.child_pipe.fileno())
1243
 
            
 
1203
 
1244
1204
            session = (gnutls.connection
1245
1205
                       .ClientSession(self.request,
1246
1206
                                      gnutls.connection
1247
1207
                                      .X509Credentials()))
1248
 
            
 
1208
 
1249
1209
            # Note: gnutls.connection.X509Credentials is really a
1250
1210
            # generic GnuTLS certificate credentials object so long as
1251
1211
            # no X.509 keys are added to it.  Therefore, we can use it
1252
1212
            # here despite using OpenPGP certificates.
1253
 
            
 
1213
 
1254
1214
            #priority = ':'.join(("NONE", "+VERS-TLS1.1",
1255
1215
            #                      "+AES-256-CBC", "+SHA1",
1256
1216
            #                      "+COMP-NULL", "+CTYPE-OPENPGP",
1262
1222
            (gnutls.library.functions
1263
1223
             .gnutls_priority_set_direct(session._c_object,
1264
1224
                                         priority, None))
1265
 
            
 
1225
 
1266
1226
            # Start communication using the Mandos protocol
1267
1227
            # Get protocol number
1268
1228
            line = self.request.makefile().readline()
1273
1233
            except (ValueError, IndexError, RuntimeError) as error:
1274
1234
                logger.error("Unknown protocol version: %s", error)
1275
1235
                return
1276
 
            
 
1236
 
1277
1237
            # Start GnuTLS connection
1278
1238
            try:
1279
1239
                session.handshake()
1283
1243
                # established.  Just abandon the request.
1284
1244
                return
1285
1245
            logger.debug("Handshake succeeded")
1286
 
            
 
1246
 
1287
1247
            approval_required = False
1288
1248
            try:
1289
1249
                try:
1294
1254
                    logger.warning("Bad certificate: %s", error)
1295
1255
                    return
1296
1256
                logger.debug("Fingerprint: %s", fpr)
1297
 
                
 
1257
 
1298
1258
                try:
1299
1259
                    client = ProxyClient(child_pipe, fpr,
1300
1260
                                         self.client_address)
1366
1326
                                 sent, len(client.secret)
1367
1327
                                 - (sent_size + sent))
1368
1328
                    sent_size += sent
1369
 
                
 
1329
 
1370
1330
                logger.info("Sending secret to %s", client.name)
1371
1331
                # bump the timeout as if seen
1372
 
                client.checked_ok(client.extended_timeout)
 
1332
                client.checked_ok()
1373
1333
                if self.server.use_dbus:
1374
1334
                    # Emit D-Bus signal
1375
1335
                    client.GotSecret()
1460
1420
        multiprocessing.Process(target = self.sub_process_main,
1461
1421
                                args = (request, address)).start()
1462
1422
 
1463
 
 
1464
1423
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
1465
1424
    """ adds a pipe to the MixIn """
1466
1425
    def process_request(self, request, client_address):
1469
1428
        This function creates a new pipe in self.pipe
1470
1429
        """
1471
1430
        parent_pipe, self.child_pipe = multiprocessing.Pipe()
1472
 
        
 
1431
 
1473
1432
        super(MultiprocessingMixInWithPipe,
1474
1433
              self).process_request(request, client_address)
1475
1434
        self.child_pipe.close()
1476
1435
        self.add_pipe(parent_pipe)
1477
 
    
 
1436
 
1478
1437
    def add_pipe(self, parent_pipe):
1479
1438
        """Dummy function; override as necessary"""
1480
1439
        raise NotImplementedError
1481
1440
 
1482
 
 
1483
1441
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
1484
1442
                     socketserver.TCPServer, object):
1485
1443
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
1633
1591
            kwargs = request[3]
1634
1592
            
1635
1593
            parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs)))
1636
 
        
 
1594
 
1637
1595
        if command == 'getattr':
1638
1596
            attrname = request[1]
1639
1597
            if callable(client_object.__getattribute__(attrname)):
1645
1603
            attrname = request[1]
1646
1604
            value = request[2]
1647
1605
            setattr(client_object, attrname, value)
1648
 
        
 
1606
 
1649
1607
        return True
1650
1608
 
1651
1609
 
1830
1788
    debuglevel = server_settings["debuglevel"]
1831
1789
    use_dbus = server_settings["use_dbus"]
1832
1790
    use_ipv6 = server_settings["use_ipv6"]
1833
 
    
 
1791
 
1834
1792
    if server_settings["servicename"] != "Mandos":
1835
1793
        syslogger.setFormatter(logging.Formatter
1836
1794
                               ('Mandos (%s) [%%(process)d]:'
1838
1796
                                % server_settings["servicename"]))
1839
1797
    
1840
1798
    # Parse config file with clients
1841
 
    client_defaults = { "timeout": "5m",
1842
 
                        "extended_timeout": "15m",
1843
 
                        "interval": "2m",
 
1799
    client_defaults = { "timeout": "1h",
 
1800
                        "interval": "5m",
1844
1801
                        "checker": "fping -q -- %%(host)s",
1845
1802
                        "host": "",
1846
1803
                        "approval_delay": "0s",
1897
1854
        level = getattr(logging, debuglevel.upper())
1898
1855
        syslogger.setLevel(level)
1899
1856
        console.setLevel(level)
1900
 
    
 
1857
 
1901
1858
    if debug:
1902
1859
        # Enable all possible GnuTLS debugging
1903
1860
        
1934
1891
    # End of Avahi example code
1935
1892
    if use_dbus:
1936
1893
        try:
1937
 
            bus_name = dbus.service.BusName("se.recompile.Mandos",
 
1894
            bus_name = dbus.service.BusName("se.bsnet.fukt.Mandos",
1938
1895
                                            bus, do_not_queue=True)
1939
 
            bus_name_transitional = dbus.service.BusName("se.bsnet.fukt.Mandos",
1940
 
                                                         bus, do_not_queue=True)
1941
1896
        except dbus.exceptions.NameExistsException as e:
1942
1897
            logger.error(unicode(e) + ", disabling D-Bus")
1943
1898
            use_dbus = False
1956
1911
    
1957
1912
    client_class = Client
1958
1913
    if use_dbus:
1959
 
        client_class = functools.partial(ClientDBusTransitional, bus = bus)        
 
1914
        client_class = functools.partial(ClientDBus, bus = bus)
1960
1915
    def client_config_items(config, section):
1961
1916
        special_settings = {
1962
1917
            "approved_by_default":
1992
1947
        del pidfilename
1993
1948
        
1994
1949
        signal.signal(signal.SIGINT, signal.SIG_IGN)
1995
 
    
 
1950
 
1996
1951
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1997
1952
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1998
1953
    
2049
2004
            
2050
2005
            del _interface
2051
2006
        
2052
 
        class MandosDBusServiceTransitional(MandosDBusService):
2053
 
            __metaclass__ = transitional_dbus_metaclass
2054
 
        mandos_dbus_service = MandosDBusServiceTransitional()
 
2007
        mandos_dbus_service = MandosDBusService()
2055
2008
    
2056
2009
    def cleanup():
2057
2010
        "Cleanup function; run on exit"
2121
2074
    # Must run before the D-Bus bus name gets deregistered
2122
2075
    cleanup()
2123
2076
 
2124
 
 
2125
2077
if __name__ == '__main__':
2126
2078
    main()