/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: Björn Påhlsson
  • Date: 2011-10-02 19:18:24 UTC
  • mto: This revision was merged to the branch mainline in revision 505.
  • Revision ID: belorn@fukt.bsnet.se-20111002191824-eweh4pvneeg3qzia
transitional stuff actually working
documented change to D-Bus API

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
65
66
 
66
67
import dbus
67
68
import dbus.service
264
265
        self.server_state_changed(self.server.GetState())
265
266
 
266
267
 
 
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
        
267
274
class Client(object):
268
275
    """A representation of a client host served by this server.
269
276
    
299
306
                                      until this client is disabled
300
307
    extended_timeout:   extra long timeout when password has been sent
301
308
    runtime_expansions: Allowed attributes for runtime expansion.
302
 
    expire:     datetime.datetime(); time (UTC) when a client will be
 
309
    expires:    datetime.datetime(); time (UTC) when a client will be
303
310
                disabled, or None
304
311
    """
305
312
    
308
315
                          "host", "interval", "last_checked_ok",
309
316
                          "last_enabled", "name", "timeout")
310
317
    
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
 
    
318
318
    def timeout_milliseconds(self):
319
319
        "Return the 'timeout' attribute in milliseconds"
320
 
        return self._timedelta_to_milliseconds(self.timeout)
321
 
 
 
320
        return _timedelta_to_milliseconds(self.timeout)
 
321
    
322
322
    def extended_timeout_milliseconds(self):
323
323
        "Return the 'extended_timeout' attribute in milliseconds"
324
 
        return self._timedelta_to_milliseconds(self.extended_timeout)    
 
324
        return _timedelta_to_milliseconds(self.extended_timeout)    
325
325
    
326
326
    def interval_milliseconds(self):
327
327
        "Return the 'interval' attribute in milliseconds"
328
 
        return self._timedelta_to_milliseconds(self.interval)
329
 
 
 
328
        return _timedelta_to_milliseconds(self.interval)
 
329
    
330
330
    def approval_delay_milliseconds(self):
331
 
        return self._timedelta_to_milliseconds(self.approval_delay)
 
331
        return _timedelta_to_milliseconds(self.approval_delay)
332
332
    
333
333
    def __init__(self, name = None, disable_hook=None, config=None):
334
334
        """Note: the 'checker' key in 'config' sets the
393
393
            # Already enabled
394
394
            return
395
395
        self.send_changedstate()
396
 
        self.last_enabled = datetime.datetime.utcnow()
397
396
        # Schedule a new checker to be started an 'interval' from now,
398
397
        # and every interval from then on.
399
398
        self.checker_initiator_tag = (gobject.timeout_add
405
404
                                   (self.timeout_milliseconds(),
406
405
                                    self.disable))
407
406
        self.enabled = True
 
407
        self.last_enabled = datetime.datetime.utcnow()
408
408
        # Also start a new checker *right now*.
409
409
        self.start_checker()
410
410
    
463
463
        gobject.source_remove(self.disable_initiator_tag)
464
464
        self.expires = datetime.datetime.utcnow() + timeout
465
465
        self.disable_initiator_tag = (gobject.timeout_add
466
 
                                      (self._timedelta_to_milliseconds(timeout),
 
466
                                      (_timedelta_to_milliseconds(timeout),
467
467
                                       self.disable))
468
468
    
469
469
    def need_approval(self):
510
510
                                       'replace')))
511
511
                    for attr in
512
512
                    self.runtime_expansions)
513
 
 
 
513
                
514
514
                try:
515
515
                    command = self.checker_command % escaped_attrs
516
516
                except TypeError as error:
562
562
                raise
563
563
        self.checker = None
564
564
 
 
565
 
565
566
def dbus_service_property(dbus_interface, signature="v",
566
567
                          access="readwrite", byte_arrays=False):
567
568
    """Decorators for marking methods of a DBusObjectWithProperties to
613
614
 
614
615
class DBusObjectWithProperties(dbus.service.Object):
615
616
    """A D-Bus object with properties.
616
 
 
 
617
    
617
618
    Classes inheriting from this can use the dbus_service_property
618
619
    decorator to expose methods as D-Bus properties.  It exposes the
619
620
    standard Get(), Set(), and GetAll() methods on the D-Bus.
626
627
    def _get_all_dbus_properties(self):
627
628
        """Returns a generator of (name, attribute) pairs
628
629
        """
629
 
        return ((prop._dbus_name, prop)
630
 
                for name, prop in
631
 
                inspect.getmembers(self, self._is_dbus_property))
 
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))
632
633
    
633
634
    def _get_dbus_property(self, interface_name, property_name):
634
635
        """Returns a bound method if one exists which is a D-Bus
635
636
        property with the specified name and interface.
636
637
        """
637
 
        for name in (property_name,
638
 
                     property_name + "_dbus_property"):
639
 
            prop = getattr(self, name, None)
640
 
            if (prop is None
641
 
                or not self._is_dbus_property(prop)
642
 
                or prop._dbus_name != property_name
643
 
                or (interface_name and prop._dbus_interface
644
 
                    and interface_name != prop._dbus_interface)):
645
 
                continue
646
 
            return prop
 
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
        
647
643
        # No such property
648
644
        raise DBusPropertyNotFound(self.dbus_object_path + ":"
649
645
                                   + interface_name + "."
650
646
                                   + property_name)
 
647
 
651
648
    
652
649
    @dbus.service.method(dbus.PROPERTIES_IFACE, in_signature="ss",
653
650
                         out_signature="v")
683
680
    def GetAll(self, interface_name):
684
681
        """Standard D-Bus property GetAll() method, see D-Bus
685
682
        standard.
686
 
 
 
683
        
687
684
        Note: Will not include properties with access="write".
688
685
        """
689
686
        all = {}
751
748
        return xmlstring
752
749
 
753
750
 
 
751
def datetime_to_dbus (dt, variant_level=0):
 
752
    """Convert a UTC datetime.datetime() to a D-Bus type."""
 
753
    if dt is None:
 
754
        return dbus.String("", variant_level = variant_level)
 
755
    return dbus.String(dt.isoformat(),
 
756
                       variant_level=variant_level)
 
757
 
 
758
class transitional_dbus_metaclass(DBusObjectWithProperties.__metaclass__):
 
759
    def __new__(mcs, name, bases, attr):
 
760
        for attrname, old_dbusobj in inspect.getmembers(bases[0]):
 
761
            new_interface = getattr(old_dbusobj, "_dbus_interface", "").replace("se.bsnet.fukt.", "se.recompile.")
 
762
            if (getattr(old_dbusobj, "_dbus_is_signal", False)
 
763
                and old_dbusobj._dbus_interface.startswith("se.bsnet.fukt.Mandos")):
 
764
                unwrappedfunc = dict(zip(old_dbusobj.func_code.co_freevars,
 
765
                                    old_dbusobj.__closure__))["func"].cell_contents
 
766
                newfunc = types.FunctionType(unwrappedfunc.func_code,
 
767
                                             unwrappedfunc.func_globals,
 
768
                                             unwrappedfunc.func_name,
 
769
                                             unwrappedfunc.func_defaults,
 
770
                                             unwrappedfunc.func_closure)
 
771
                new_dbusfunc = dbus.service.signal(
 
772
                    new_interface, old_dbusobj._dbus_signature)(newfunc)            
 
773
                attr["_transitional_" + attrname] = new_dbusfunc
 
774
 
 
775
                def fixscope(func1, func2):
 
776
                    def newcall(*args, **kwargs):
 
777
                        func1(*args, **kwargs)
 
778
                        func2(*args, **kwargs)
 
779
                    return newcall
 
780
 
 
781
                attr[attrname] = fixscope(old_dbusobj, new_dbusfunc)
 
782
            
 
783
            elif (getattr(old_dbusobj, "_dbus_is_method", False)
 
784
                and old_dbusobj._dbus_interface.startswith("se.bsnet.fukt.Mandos")):
 
785
                new_dbusfunc = (dbus.service.method
 
786
                                (new_interface,
 
787
                                 old_dbusobj._dbus_in_signature,
 
788
                                 old_dbusobj._dbus_out_signature)
 
789
                                (types.FunctionType
 
790
                                 (old_dbusobj.func_code,
 
791
                                  old_dbusobj.func_globals,
 
792
                                  old_dbusobj.func_name,
 
793
                                  old_dbusobj.func_defaults,
 
794
                                  old_dbusobj.func_closure)))
 
795
 
 
796
                attr[attrname] = new_dbusfunc
 
797
            elif (getattr(old_dbusobj, "_dbus_is_property", False)
 
798
                  and old_dbusobj._dbus_interface.startswith("se.bsnet.fukt.Mandos")):
 
799
                new_dbusfunc = (dbus_service_property
 
800
                                (new_interface,
 
801
                                 old_dbusobj._dbus_signature,
 
802
                                 old_dbusobj._dbus_access,
 
803
                                 old_dbusobj._dbus_get_args_options["byte_arrays"])
 
804
                                (types.FunctionType
 
805
                                 (old_dbusobj.func_code,
 
806
                                  old_dbusobj.func_globals,
 
807
                                  old_dbusobj.func_name,
 
808
                                  old_dbusobj.func_defaults,
 
809
                                  old_dbusobj.func_closure)))
 
810
 
 
811
                attr[attrname] = new_dbusfunc
 
812
        return type.__new__(mcs, name, bases, attr)
 
813
 
754
814
class ClientDBus(Client, DBusObjectWithProperties):
755
815
    """A Client class using D-Bus
756
816
    
777
837
                                 ("/clients/" + client_object_name))
778
838
        DBusObjectWithProperties.__init__(self, self.bus,
779
839
                                          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
 
        
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
 
840
        
 
841
    def notifychangeproperty(transform_func,
 
842
                             dbus_name, type_func=lambda x: x,
 
843
                             variant_level=1):
 
844
        """ Modify a variable so that its a property that announce its
 
845
        changes to DBus.
 
846
        transform_fun: Function that takes a value and transform it to
 
847
                       DBus type.
 
848
        dbus_name: DBus name of the variable
 
849
        type_func: Function that transform the value before sending it
 
850
                   to DBus
 
851
        variant_level: DBus variant level. default: 1
 
852
        """
 
853
        real_value = [None,]
 
854
        def setter(self, value):
 
855
            old_value = real_value[0]
 
856
            real_value[0] = value
 
857
            if hasattr(self, "dbus_object_path"):
 
858
                if type_func(old_value) != type_func(real_value[0]):
 
859
                    dbus_value = transform_func(type_func(real_value[0]),
 
860
                                                variant_level)
 
861
                    self.PropertyChanged(dbus.String(dbus_name),
 
862
                                         dbus_value)
 
863
        
 
864
        return property(lambda self: real_value[0], setter)
 
865
    
 
866
    
 
867
    expires = notifychangeproperty(datetime_to_dbus, "Expires")
 
868
    approvals_pending = notifychangeproperty(dbus.Boolean,
 
869
                                             "ApprovalPending",
 
870
                                             type_func = bool)
 
871
    enabled = notifychangeproperty(dbus.Boolean, "Enabled")
 
872
    last_enabled = notifychangeproperty(datetime_to_dbus,
 
873
                                        "LastEnabled")
 
874
    checker = notifychangeproperty(dbus.Boolean, "CheckerRunning",
 
875
                                   type_func = lambda checker: checker is not None)
 
876
    last_checked_ok = notifychangeproperty(datetime_to_dbus,
 
877
                                           "LastCheckedOK")
 
878
    last_approval_request = notifychangeproperty(datetime_to_dbus,
 
879
                                                 "LastApprovalRequest")
 
880
    approved_by_default = notifychangeproperty(dbus.Boolean,
 
881
                                               "ApprovedByDefault")
 
882
    approval_delay = notifychangeproperty(dbus.UInt16, "ApprovalDelay",
 
883
                                          type_func = _timedelta_to_milliseconds)
 
884
    approval_duration = notifychangeproperty(dbus.UInt16, "ApprovalDuration",
 
885
                                             type_func = _timedelta_to_milliseconds)
 
886
    host = notifychangeproperty(dbus.String, "Host")
 
887
    timeout = notifychangeproperty(dbus.UInt16, "Timeout",
 
888
                                   type_func = _timedelta_to_milliseconds)
 
889
    extended_timeout = notifychangeproperty(dbus.UInt16, "ExtendedTimeout",
 
890
                                            type_func = _timedelta_to_milliseconds)
 
891
    interval = notifychangeproperty(dbus.UInt16, "Interval",
 
892
                                    type_func = _timedelta_to_milliseconds)
 
893
    checker_command = notifychangeproperty(dbus.String, "Checker")
 
894
    
 
895
    del notifychangeproperty
836
896
    
837
897
    def __del__(self, *args, **kwargs):
838
898
        try:
847
907
                         *args, **kwargs):
848
908
        self.checker_callback_tag = None
849
909
        self.checker = None
850
 
        # Emit D-Bus signal
851
 
        self.PropertyChanged(dbus.String("CheckerRunning"),
852
 
                             dbus.Boolean(False, variant_level=1))
853
910
        if os.WIFEXITED(condition):
854
911
            exitstatus = os.WEXITSTATUS(condition)
855
912
            # Emit D-Bus signal
865
922
        return Client.checker_callback(self, pid, condition, command,
866
923
                                       *args, **kwargs)
867
924
    
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
 
    
885
925
    def start_checker(self, *args, **kwargs):
886
926
        old_checker = self.checker
887
927
        if self.checker is not None:
894
934
            and old_checker_pid != self.checker.pid):
895
935
            # Emit D-Bus signal
896
936
            self.CheckerStarted(self.current_checker_command)
897
 
            self.PropertyChanged(
898
 
                dbus.String("CheckerRunning"),
899
 
                dbus.Boolean(True, variant_level=1))
900
937
        return r
901
938
    
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
939
    def _reset_approved(self):
912
940
        self._approved = None
913
941
        return False
915
943
    def approve(self, value=True):
916
944
        self.send_changedstate()
917
945
        self._approved = value
918
 
        gobject.timeout_add(self._timedelta_to_milliseconds
 
946
        gobject.timeout_add(_timedelta_to_milliseconds
919
947
                            (self.approval_duration),
920
948
                            self._reset_approved)
921
949
    
922
950
    
923
951
    ## D-Bus methods, signals & properties
924
952
    _interface = "se.bsnet.fukt.Mandos.Client"
925
 
    
 
953
 
926
954
    ## Signals
927
955
    
928
956
    # CheckerCompleted - signal
1012
1040
    def ApprovedByDefault_dbus_property(self, value=None):
1013
1041
        if value is None:       # get
1014
1042
            return dbus.Boolean(self.approved_by_default)
1015
 
        old_value = self.approved_by_default
1016
1043
        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
1044
    
1022
1045
    # ApprovalDelay - property
1023
1046
    @dbus_service_property(_interface, signature="t",
1025
1048
    def ApprovalDelay_dbus_property(self, value=None):
1026
1049
        if value is None:       # get
1027
1050
            return dbus.UInt64(self.approval_delay_milliseconds())
1028
 
        old_value = self.approval_delay
1029
1051
        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
1052
    
1035
1053
    # ApprovalDuration - property
1036
1054
    @dbus_service_property(_interface, signature="t",
1037
1055
                           access="readwrite")
1038
1056
    def ApprovalDuration_dbus_property(self, value=None):
1039
1057
        if value is None:       # get
1040
 
            return dbus.UInt64(self._timedelta_to_milliseconds(
 
1058
            return dbus.UInt64(_timedelta_to_milliseconds(
1041
1059
                    self.approval_duration))
1042
 
        old_value = self.approval_duration
1043
1060
        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
1061
    
1049
1062
    # Name - property
1050
1063
    @dbus_service_property(_interface, signature="s", access="read")
1062
1075
    def Host_dbus_property(self, value=None):
1063
1076
        if value is None:       # get
1064
1077
            return dbus.String(self.host)
1065
 
        old_value = self.host
1066
1078
        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
1079
    
1072
1080
    # Created - property
1073
1081
    @dbus_service_property(_interface, signature="s", access="read")
1074
1082
    def Created_dbus_property(self):
1075
 
        return dbus.String(self._datetime_to_dbus(self.created))
 
1083
        return dbus.String(datetime_to_dbus(self.created))
1076
1084
    
1077
1085
    # LastEnabled - property
1078
1086
    @dbus_service_property(_interface, signature="s", access="read")
1079
1087
    def LastEnabled_dbus_property(self):
1080
 
        return self._datetime_to_dbus(self.last_enabled)
 
1088
        return datetime_to_dbus(self.last_enabled)
1081
1089
    
1082
1090
    # Enabled - property
1083
1091
    @dbus_service_property(_interface, signature="b",
1097
1105
        if value is not None:
1098
1106
            self.checked_ok()
1099
1107
            return
1100
 
        return self._datetime_to_dbus(self.last_checked_ok)
 
1108
        return datetime_to_dbus(self.last_checked_ok)
1101
1109
    
1102
1110
    # Expires - property
1103
1111
    @dbus_service_property(_interface, signature="s", access="read")
1104
1112
    def Expires_dbus_property(self):
1105
 
        return self._datetime_to_dbus(self.expires)
 
1113
        return datetime_to_dbus(self.expires)
1106
1114
    
1107
1115
    # LastApprovalRequest - property
1108
1116
    @dbus_service_property(_interface, signature="s", access="read")
1109
1117
    def LastApprovalRequest_dbus_property(self):
1110
 
        return self._datetime_to_dbus(self.last_approval_request)
 
1118
        return datetime_to_dbus(self.last_approval_request)
1111
1119
    
1112
1120
    # Timeout - property
1113
1121
    @dbus_service_property(_interface, signature="t",
1115
1123
    def Timeout_dbus_property(self, value=None):
1116
1124
        if value is None:       # get
1117
1125
            return dbus.UInt64(self.timeout_milliseconds())
1118
 
        old_value = self.timeout
1119
1126
        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
1127
        if getattr(self, "disable_initiator_tag", None) is None:
1125
1128
            return
1126
1129
        # Reschedule timeout
1141
1144
                            + datetime.timedelta(milliseconds = time_to_die))
1142
1145
            self.disable_initiator_tag = (gobject.timeout_add
1143
1146
                                          (time_to_die, self.disable))
1144
 
 
 
1147
    
1145
1148
    # ExtendedTimeout - property
1146
1149
    @dbus_service_property(_interface, signature="t",
1147
1150
                           access="readwrite")
1148
1151
    def ExtendedTimeout_dbus_property(self, value=None):
1149
1152
        if value is None:       # get
1150
1153
            return dbus.UInt64(self.extended_timeout_milliseconds())
1151
 
        old_value = self.extended_timeout
1152
1154
        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
 
 
 
1155
    
1158
1156
    # Interval - property
1159
1157
    @dbus_service_property(_interface, signature="t",
1160
1158
                           access="readwrite")
1161
1159
    def Interval_dbus_property(self, value=None):
1162
1160
        if value is None:       # get
1163
1161
            return dbus.UInt64(self.interval_milliseconds())
1164
 
        old_value = self.interval
1165
1162
        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
1163
        if getattr(self, "checker_initiator_tag", None) is None:
1171
1164
            return
1172
1165
        # Reschedule checker run
1174
1167
        self.checker_initiator_tag = (gobject.timeout_add
1175
1168
                                      (value, self.start_checker))
1176
1169
        self.start_checker()    # Start one now, too
1177
 
 
 
1170
    
1178
1171
    # Checker - property
1179
1172
    @dbus_service_property(_interface, signature="s",
1180
1173
                           access="readwrite")
1181
1174
    def Checker_dbus_property(self, value=None):
1182
1175
        if value is None:       # get
1183
1176
            return dbus.String(self.checker_command)
1184
 
        old_value = self.checker_command
1185
1177
        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
1178
    
1192
1179
    # CheckerRunning - property
1193
1180
    @dbus_service_property(_interface, signature="b",
1220
1207
        self._pipe.send(('init', fpr, address))
1221
1208
        if not self._pipe.recv():
1222
1209
            raise KeyError()
1223
 
 
 
1210
    
1224
1211
    def __getattribute__(self, name):
1225
1212
        if(name == '_pipe'):
1226
1213
            return super(ProxyClient, self).__getattribute__(name)
1233
1220
                self._pipe.send(('funcall', name, args, kwargs))
1234
1221
                return self._pipe.recv()[1]
1235
1222
            return func
1236
 
 
 
1223
    
1237
1224
    def __setattr__(self, name, value):
1238
1225
        if(name == '_pipe'):
1239
1226
            return super(ProxyClient, self).__setattr__(name, value)
1240
1227
        self._pipe.send(('setattr', name, value))
1241
1228
 
 
1229
class ClientDBusTransitional(ClientDBus):
 
1230
    __metaclass__ = transitional_dbus_metaclass
1242
1231
 
1243
1232
class ClientHandler(socketserver.BaseRequestHandler, object):
1244
1233
    """A class to handle client connections.
1252
1241
                        unicode(self.client_address))
1253
1242
            logger.debug("Pipe FD: %d",
1254
1243
                         self.server.child_pipe.fileno())
1255
 
 
 
1244
            
1256
1245
            session = (gnutls.connection
1257
1246
                       .ClientSession(self.request,
1258
1247
                                      gnutls.connection
1259
1248
                                      .X509Credentials()))
1260
 
 
 
1249
            
1261
1250
            # Note: gnutls.connection.X509Credentials is really a
1262
1251
            # generic GnuTLS certificate credentials object so long as
1263
1252
            # no X.509 keys are added to it.  Therefore, we can use it
1264
1253
            # here despite using OpenPGP certificates.
1265
 
 
 
1254
            
1266
1255
            #priority = ':'.join(("NONE", "+VERS-TLS1.1",
1267
1256
            #                      "+AES-256-CBC", "+SHA1",
1268
1257
            #                      "+COMP-NULL", "+CTYPE-OPENPGP",
1274
1263
            (gnutls.library.functions
1275
1264
             .gnutls_priority_set_direct(session._c_object,
1276
1265
                                         priority, None))
1277
 
 
 
1266
            
1278
1267
            # Start communication using the Mandos protocol
1279
1268
            # Get protocol number
1280
1269
            line = self.request.makefile().readline()
1285
1274
            except (ValueError, IndexError, RuntimeError) as error:
1286
1275
                logger.error("Unknown protocol version: %s", error)
1287
1276
                return
1288
 
 
 
1277
            
1289
1278
            # Start GnuTLS connection
1290
1279
            try:
1291
1280
                session.handshake()
1295
1284
                # established.  Just abandon the request.
1296
1285
                return
1297
1286
            logger.debug("Handshake succeeded")
1298
 
 
 
1287
            
1299
1288
            approval_required = False
1300
1289
            try:
1301
1290
                try:
1306
1295
                    logger.warning("Bad certificate: %s", error)
1307
1296
                    return
1308
1297
                logger.debug("Fingerprint: %s", fpr)
1309
 
 
 
1298
                
1310
1299
                try:
1311
1300
                    client = ProxyClient(child_pipe, fpr,
1312
1301
                                         self.client_address)
1378
1367
                                 sent, len(client.secret)
1379
1368
                                 - (sent_size + sent))
1380
1369
                    sent_size += sent
1381
 
 
 
1370
                
1382
1371
                logger.info("Sending secret to %s", client.name)
1383
1372
                # bump the timeout as if seen
1384
1373
                client.checked_ok(client.extended_timeout)
1472
1461
        multiprocessing.Process(target = self.sub_process_main,
1473
1462
                                args = (request, address)).start()
1474
1463
 
 
1464
 
1475
1465
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
1476
1466
    """ adds a pipe to the MixIn """
1477
1467
    def process_request(self, request, client_address):
1480
1470
        This function creates a new pipe in self.pipe
1481
1471
        """
1482
1472
        parent_pipe, self.child_pipe = multiprocessing.Pipe()
1483
 
 
 
1473
        
1484
1474
        super(MultiprocessingMixInWithPipe,
1485
1475
              self).process_request(request, client_address)
1486
1476
        self.child_pipe.close()
1487
1477
        self.add_pipe(parent_pipe)
1488
 
 
 
1478
    
1489
1479
    def add_pipe(self, parent_pipe):
1490
1480
        """Dummy function; override as necessary"""
1491
1481
        raise NotImplementedError
1492
1482
 
 
1483
 
1493
1484
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
1494
1485
                     socketserver.TCPServer, object):
1495
1486
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
1643
1634
            kwargs = request[3]
1644
1635
            
1645
1636
            parent_pipe.send(('data', getattr(client_object, funcname)(*args, **kwargs)))
1646
 
 
 
1637
        
1647
1638
        if command == 'getattr':
1648
1639
            attrname = request[1]
1649
1640
            if callable(client_object.__getattribute__(attrname)):
1655
1646
            attrname = request[1]
1656
1647
            value = request[2]
1657
1648
            setattr(client_object, attrname, value)
1658
 
 
 
1649
        
1659
1650
        return True
1660
1651
 
1661
1652
 
1840
1831
    debuglevel = server_settings["debuglevel"]
1841
1832
    use_dbus = server_settings["use_dbus"]
1842
1833
    use_ipv6 = server_settings["use_ipv6"]
1843
 
 
 
1834
    
1844
1835
    if server_settings["servicename"] != "Mandos":
1845
1836
        syslogger.setFormatter(logging.Formatter
1846
1837
                               ('Mandos (%s) [%%(process)d]:'
1907
1898
        level = getattr(logging, debuglevel.upper())
1908
1899
        syslogger.setLevel(level)
1909
1900
        console.setLevel(level)
1910
 
 
 
1901
    
1911
1902
    if debug:
1912
1903
        # Enable all possible GnuTLS debugging
1913
1904
        
1946
1937
        try:
1947
1938
            bus_name = dbus.service.BusName("se.bsnet.fukt.Mandos",
1948
1939
                                            bus, do_not_queue=True)
 
1940
            bus_name2 = dbus.service.BusName("se.recompile.Mandos",
 
1941
                                            bus, do_not_queue=True)
1949
1942
        except dbus.exceptions.NameExistsException as e:
1950
1943
            logger.error(unicode(e) + ", disabling D-Bus")
1951
1944
            use_dbus = False
1964
1957
    
1965
1958
    client_class = Client
1966
1959
    if use_dbus:
1967
 
        client_class = functools.partial(ClientDBus, bus = bus)
 
1960
        client_class = functools.partial(ClientDBusTransitional, bus = bus)        
1968
1961
    def client_config_items(config, section):
1969
1962
        special_settings = {
1970
1963
            "approved_by_default":
2000
1993
        del pidfilename
2001
1994
        
2002
1995
        signal.signal(signal.SIGINT, signal.SIG_IGN)
2003
 
 
 
1996
    
2004
1997
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
2005
1998
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
2006
1999
    
2057
2050
            
2058
2051
            del _interface
2059
2052
        
2060
 
        mandos_dbus_service = MandosDBusService()
 
2053
        class MandosDBusServiceTransitional(MandosDBusService):
 
2054
            __metaclass__ = transitional_dbus_metaclass
 
2055
        mandos_dbus_service = MandosDBusServiceTransitional()
2061
2056
    
2062
2057
    def cleanup():
2063
2058
        "Cleanup function; run on exit"
2127
2122
    # Must run before the D-Bus bus name gets deregistered
2128
2123
    cleanup()
2129
2124
 
 
2125
 
2130
2126
if __name__ == '__main__':
2131
2127
    main()