/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: 2012-02-21 21:29:12 UTC
  • mfrom: (237.4.29 release)
  • Revision ID: teddy@recompile.se-20120221212912-72ysftlcji3r1g7f
Merge from release branch.

Show diffs side-by-side

added added

removed removed

Lines of Context:
65
65
import types
66
66
import binascii
67
67
import tempfile
68
 
import itertools
69
68
 
70
69
import dbus
71
70
import dbus.service
176
175
    
177
176
    def encrypt(self, data, password):
178
177
        self.gnupg.passphrase = self.password_encode(password)
179
 
        with open(os.devnull, "w") as devnull:
 
178
        with open(os.devnull) as devnull:
180
179
            try:
181
180
                proc = self.gnupg.run(['--symmetric'],
182
181
                                      create_fhs=['stdin', 'stdout'],
193
192
    
194
193
    def decrypt(self, data, password):
195
194
        self.gnupg.passphrase = self.password_encode(password)
196
 
        with open(os.devnull, "w") as devnull:
 
195
        with open(os.devnull) as devnull:
197
196
            try:
198
197
                proc = self.gnupg.run(['--decrypt'],
199
198
                                      create_fhs=['stdin', 'stdout'],
200
199
                                      attach_fhs={'stderr': devnull})
201
 
                with contextlib.closing(proc.handles['stdin']) as f:
 
200
                with contextlib.closing(proc.handles['stdin'] ) as f:
202
201
                    f.write(data)
203
202
                with contextlib.closing(proc.handles['stdout']) as f:
204
203
                    decrypted_plaintext = f.read()
772
771
    return decorator
773
772
 
774
773
 
775
 
def dbus_interface_annotations(dbus_interface):
776
 
    """Decorator for marking functions returning interface annotations.
777
 
    
778
 
    Usage:
779
 
    
780
 
    @dbus_interface_annotations("org.example.Interface")
781
 
    def _foo(self):  # Function name does not matter
782
 
        return {"org.freedesktop.DBus.Deprecated": "true",
783
 
                "org.freedesktop.DBus.Property.EmitsChangedSignal":
784
 
                    "false"}
785
 
    """
786
 
    def decorator(func):
787
 
        func._dbus_is_interface = True
788
 
        func._dbus_interface = dbus_interface
789
 
        func._dbus_name = dbus_interface
790
 
        return func
791
 
    return decorator
792
 
 
793
 
 
794
 
def dbus_annotations(annotations):
795
 
    """Decorator to annotate D-Bus methods, signals or properties
796
 
    Usage:
797
 
    
798
 
    @dbus_service_property("org.example.Interface", signature="b",
799
 
                           access="r")
800
 
    @dbus_annotations({{"org.freedesktop.DBus.Deprecated": "true",
801
 
                        "org.freedesktop.DBus.Property."
802
 
                        "EmitsChangedSignal": "false"})
803
 
    def Property_dbus_property(self):
804
 
        return dbus.Boolean(False)
805
 
    """
806
 
    def decorator(func):
807
 
        func._dbus_annotations = annotations
808
 
        return func
809
 
    return decorator
810
 
 
811
 
 
812
774
class DBusPropertyException(dbus.exceptions.DBusException):
813
775
    """A base class for D-Bus property-related exceptions
814
776
    """
837
799
    """
838
800
    
839
801
    @staticmethod
840
 
    def _is_dbus_thing(thing):
841
 
        """Returns a function testing if an attribute is a D-Bus thing
842
 
        
843
 
        If called like _is_dbus_thing("method") it returns a function
844
 
        suitable for use as predicate to inspect.getmembers().
845
 
        """
846
 
        return lambda obj: getattr(obj, "_dbus_is_{0}".format(thing),
847
 
                                   False)
 
802
    def _is_dbus_property(obj):
 
803
        return getattr(obj, "_dbus_is_property", False)
848
804
    
849
 
    def _get_all_dbus_things(self, thing):
 
805
    def _get_all_dbus_properties(self):
850
806
        """Returns a generator of (name, attribute) pairs
851
807
        """
852
 
        return ((getattr(athing.__get__(self), "_dbus_name",
853
 
                         name),
854
 
                 athing.__get__(self))
 
808
        return ((prop.__get__(self)._dbus_name, prop.__get__(self))
855
809
                for cls in self.__class__.__mro__
856
 
                for name, athing in
857
 
                inspect.getmembers(cls,
858
 
                                   self._is_dbus_thing(thing)))
 
810
                for name, prop in
 
811
                inspect.getmembers(cls, self._is_dbus_property))
859
812
    
860
813
    def _get_dbus_property(self, interface_name, property_name):
861
814
        """Returns a bound method if one exists which is a D-Bus
863
816
        """
864
817
        for cls in  self.__class__.__mro__:
865
818
            for name, value in (inspect.getmembers
866
 
                                (cls,
867
 
                                 self._is_dbus_thing("property"))):
 
819
                                (cls, self._is_dbus_property)):
868
820
                if (value._dbus_name == property_name
869
821
                    and value._dbus_interface == interface_name):
870
822
                    return value.__get__(self)
912
864
        Note: Will not include properties with access="write".
913
865
        """
914
866
        properties = {}
915
 
        for name, prop in self._get_all_dbus_things("property"):
 
867
        for name, prop in self._get_all_dbus_properties():
916
868
            if (interface_name
917
869
                and interface_name != prop._dbus_interface):
918
870
                # Interface non-empty but did not match
933
885
                         path_keyword='object_path',
934
886
                         connection_keyword='connection')
935
887
    def Introspect(self, object_path, connection):
936
 
        """Overloading of standard D-Bus method.
937
 
        
938
 
        Inserts property tags and interface annotation tags.
 
888
        """Standard D-Bus method, overloaded to insert property tags.
939
889
        """
940
890
        xmlstring = dbus.service.Object.Introspect(self, object_path,
941
891
                                                   connection)
948
898
                e.setAttribute("access", prop._dbus_access)
949
899
                return e
950
900
            for if_tag in document.getElementsByTagName("interface"):
951
 
                # Add property tags
952
901
                for tag in (make_tag(document, name, prop)
953
902
                            for name, prop
954
 
                            in self._get_all_dbus_things("property")
 
903
                            in self._get_all_dbus_properties()
955
904
                            if prop._dbus_interface
956
905
                            == if_tag.getAttribute("name")):
957
906
                    if_tag.appendChild(tag)
958
 
                # Add annotation tags
959
 
                for typ in ("method", "signal", "property"):
960
 
                    for tag in if_tag.getElementsByTagName(typ):
961
 
                        annots = dict()
962
 
                        for name, prop in (self.
963
 
                                           _get_all_dbus_things(typ)):
964
 
                            if (name == tag.getAttribute("name")
965
 
                                and prop._dbus_interface
966
 
                                == if_tag.getAttribute("name")):
967
 
                                annots.update(getattr
968
 
                                              (prop,
969
 
                                               "_dbus_annotations",
970
 
                                               {}))
971
 
                        for name, value in annots.iteritems():
972
 
                            ann_tag = document.createElement(
973
 
                                "annotation")
974
 
                            ann_tag.setAttribute("name", name)
975
 
                            ann_tag.setAttribute("value", value)
976
 
                            tag.appendChild(ann_tag)
977
 
                # Add interface annotation tags
978
 
                for annotation, value in dict(
979
 
                    itertools.chain(
980
 
                        *(annotations().iteritems()
981
 
                          for name, annotations in
982
 
                          self._get_all_dbus_things("interface")
983
 
                          if name == if_tag.getAttribute("name")
984
 
                          ))).iteritems():
985
 
                    ann_tag = document.createElement("annotation")
986
 
                    ann_tag.setAttribute("name", annotation)
987
 
                    ann_tag.setAttribute("value", value)
988
 
                    if_tag.appendChild(ann_tag)
989
907
                # Add the names to the return values for the
990
908
                # "org.freedesktop.DBus.Properties" methods
991
909
                if (if_tag.getAttribute("name")
1026
944
    def __new__(mcs, name, bases, attr):
1027
945
        # Go through all the base classes which could have D-Bus
1028
946
        # methods, signals, or properties in them
1029
 
        old_interface_names = []
1030
947
        for base in (b for b in bases
1031
948
                     if issubclass(b, dbus.service.Object)):
1032
949
            # Go though all attributes of the base class
1042
959
                alt_interface = (attribute._dbus_interface
1043
960
                                 .replace("se.recompile.Mandos",
1044
961
                                          "se.bsnet.fukt.Mandos"))
1045
 
                if alt_interface != attribute._dbus_interface:
1046
 
                    old_interface_names.append(alt_interface)
1047
962
                # Is this a D-Bus signal?
1048
963
                if getattr(attribute, "_dbus_is_signal", False):
1049
964
                    # Extract the original non-method function by
1064
979
                                nonmethod_func.func_name,
1065
980
                                nonmethod_func.func_defaults,
1066
981
                                nonmethod_func.func_closure)))
1067
 
                    # Copy annotations, if any
1068
 
                    try:
1069
 
                        new_function._dbus_annotations = (
1070
 
                            dict(attribute._dbus_annotations))
1071
 
                    except AttributeError:
1072
 
                        pass
1073
982
                    # Define a creator of a function to call both the
1074
983
                    # old and new functions, so both the old and new
1075
984
                    # signals gets sent when the function is called
1103
1012
                                        attribute.func_name,
1104
1013
                                        attribute.func_defaults,
1105
1014
                                        attribute.func_closure)))
1106
 
                    # Copy annotations, if any
1107
 
                    try:
1108
 
                        attr[attrname]._dbus_annotations = (
1109
 
                            dict(attribute._dbus_annotations))
1110
 
                    except AttributeError:
1111
 
                        pass
1112
1015
                # Is this a D-Bus property?
1113
1016
                elif getattr(attribute, "_dbus_is_property", False):
1114
1017
                    # Create a new, but exactly alike, function
1128
1031
                                        attribute.func_name,
1129
1032
                                        attribute.func_defaults,
1130
1033
                                        attribute.func_closure)))
1131
 
                    # Copy annotations, if any
1132
 
                    try:
1133
 
                        attr[attrname]._dbus_annotations = (
1134
 
                            dict(attribute._dbus_annotations))
1135
 
                    except AttributeError:
1136
 
                        pass
1137
 
                # Is this a D-Bus interface?
1138
 
                elif getattr(attribute, "_dbus_is_interface", False):
1139
 
                    # Create a new, but exactly alike, function
1140
 
                    # object.  Decorate it to be a new D-Bus interface
1141
 
                    # with the alternate D-Bus interface name.  Add it
1142
 
                    # to the class.
1143
 
                    attr[attrname] = (dbus_interface_annotations
1144
 
                                      (alt_interface)
1145
 
                                      (types.FunctionType
1146
 
                                       (attribute.func_code,
1147
 
                                        attribute.func_globals,
1148
 
                                        attribute.func_name,
1149
 
                                        attribute.func_defaults,
1150
 
                                        attribute.func_closure)))
1151
 
        # Deprecate all old interfaces
1152
 
        basename="_AlternateDBusNamesMetaclass_interface_annotation{0}"
1153
 
        for old_interface_name in old_interface_names:
1154
 
            @dbus_interface_annotations(old_interface_name)
1155
 
            def func(self):
1156
 
                return { "org.freedesktop.DBus.Deprecated": "true" }
1157
 
            # Find an unused name
1158
 
            for aname in (basename.format(i) for i in
1159
 
                          itertools.count()):
1160
 
                if aname not in attr:
1161
 
                    attr[aname] = func
1162
 
                    break
1163
1034
        return type.__new__(mcs, name, bases, attr)
1164
1035
 
1165
1036
 
1315
1186
    ## D-Bus methods, signals & properties
1316
1187
    _interface = "se.recompile.Mandos.Client"
1317
1188
    
1318
 
    ## Interfaces
1319
 
    
1320
 
    @dbus_interface_annotations(_interface)
1321
 
    def _foo(self):
1322
 
        return { "org.freedesktop.DBus.Property.EmitsChangedSignal":
1323
 
                     "false"}
1324
 
    
1325
1189
    ## Signals
1326
1190
    
1327
1191
    # CheckerCompleted - signal
2099
1963
        sys.exit()
2100
1964
    if not noclose:
2101
1965
        # Close all standard open file descriptors
2102
 
        null = os.open(os.devnull, os.O_NOCTTY | os.O_RDWR)
 
1966
        null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
2103
1967
        if not stat.S_ISCHR(os.fstat(null).st_mode):
2104
1968
            raise OSError(errno.ENODEV,
2105
1969
                          "%s not a character device"
2106
 
                          % os.devnull)
 
1970
                          % os.path.devnull)
2107
1971
        os.dup2(null, sys.stdin.fileno())
2108
1972
        os.dup2(null, sys.stdout.fileno())
2109
1973
        os.dup2(null, sys.stderr.fileno())
2292
2156
         .gnutls_global_set_log_function(debug_gnutls))
2293
2157
        
2294
2158
        # Redirect stdin so all checkers get /dev/null
2295
 
        null = os.open(os.devnull, os.O_NOCTTY | os.O_RDWR)
 
2159
        null = os.open(os.path.devnull, os.O_NOCTTY | os.O_RDWR)
2296
2160
        os.dup2(null, sys.stdin.fileno())
2297
2161
        if null > 2:
2298
2162
            os.close(null)
2306
2170
    
2307
2171
    global main_loop
2308
2172
    # From the Avahi example code
2309
 
    DBusGMainLoop(set_as_default=True)
 
2173
    DBusGMainLoop(set_as_default=True )
2310
2174
    main_loop = gobject.MainLoop()
2311
2175
    bus = dbus.SystemBus()
2312
2176
    # End of Avahi example code
2453
2317
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
2454
2318
    
2455
2319
    if use_dbus:
2456
 
        class MandosDBusService(DBusObjectWithProperties):
 
2320
        class MandosDBusService(dbus.service.Object):
2457
2321
            """A D-Bus proxy object"""
2458
2322
            def __init__(self):
2459
2323
                dbus.service.Object.__init__(self, bus, "/")
2460
2324
            _interface = "se.recompile.Mandos"
2461
2325
            
2462
 
            @dbus_interface_annotations(_interface)
2463
 
            def _foo(self):
2464
 
                return { "org.freedesktop.DBus.Property"
2465
 
                         ".EmitsChangedSignal":
2466
 
                             "false"}
2467
 
            
2468
2326
            @dbus.service.signal(_interface, signature="o")
2469
2327
            def ClientAdded(self, objpath):
2470
2328
                "D-Bus signal"