/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-05-06 16:13:00 UTC
  • Revision ID: teddy@recompile.se-20120506161300-43rls2rr4qub3zhw
* mandos: Use a class decorator instead of a metaclass to provide
          alternate D-Bus interface names on D-Bus object attributes.
  (alternate_dbus_interfaces): New class decorator.
  (AlternateDBusNamesMetaclass, ClientDBusTransitional,
   MandosDBusServiceTransitional): Removed; all users changed.
  (ClientDbus, MandosDBusService): Use new "alternate_dbus_interfaces"
                                   class decorator.

Show diffs side-by-side

added added

removed removed

Lines of Context:
209
209
        return decrypted_plaintext
210
210
 
211
211
 
212
 
 
213
212
class AvahiError(Exception):
214
213
    def __init__(self, value, *args, **kwargs):
215
214
        self.value = value
244
243
    server: D-Bus Server
245
244
    bus: dbus.SystemBus()
246
245
    """
 
246
    
247
247
    def __init__(self, interface = avahi.IF_UNSPEC, name = None,
248
248
                 servicetype = None, port = None, TXT = None,
249
249
                 domain = "", host = "", max_renames = 32768,
262
262
        self.server = None
263
263
        self.bus = bus
264
264
        self.entry_group_state_changed_match = None
 
265
    
265
266
    def rename(self):
266
267
        """Derived from the Avahi example code"""
267
268
        if self.rename_count >= self.max_renames:
277
278
        try:
278
279
            self.add()
279
280
        except dbus.exceptions.DBusException as error:
280
 
            logger.critical("DBusException: %s", error)
 
281
            logger.critical("D-Bus Exception", exc_info=error)
281
282
            self.cleanup()
282
283
            os._exit(1)
283
284
        self.rename_count += 1
 
285
    
284
286
    def remove(self):
285
287
        """Derived from the Avahi example code"""
286
288
        if self.entry_group_state_changed_match is not None:
288
290
            self.entry_group_state_changed_match = None
289
291
        if self.group is not None:
290
292
            self.group.Reset()
 
293
    
291
294
    def add(self):
292
295
        """Derived from the Avahi example code"""
293
296
        self.remove()
310
313
            dbus.UInt16(self.port),
311
314
            avahi.string_array_to_txt_array(self.TXT))
312
315
        self.group.Commit()
 
316
    
313
317
    def entry_group_state_changed(self, state, error):
314
318
        """Derived from the Avahi example code"""
315
319
        logger.debug("Avahi entry group state change: %i", state)
322
326
        elif state == avahi.ENTRY_GROUP_FAILURE:
323
327
            logger.critical("Avahi: Error in group state changed %s",
324
328
                            unicode(error))
325
 
            raise AvahiGroupError("State changed: %s"
326
 
                                  % unicode(error))
 
329
            raise AvahiGroupError("State changed: {0!s}"
 
330
                                  .format(error))
 
331
    
327
332
    def cleanup(self):
328
333
        """Derived from the Avahi example code"""
329
334
        if self.group is not None:
334
339
                pass
335
340
            self.group = None
336
341
        self.remove()
 
342
    
337
343
    def server_state_changed(self, state, error=None):
338
344
        """Derived from the Avahi example code"""
339
345
        logger.debug("Avahi server state change: %i", state)
358
364
                logger.debug("Unknown state: %r", state)
359
365
            else:
360
366
                logger.debug("Unknown state: %r: %r", state, error)
 
367
    
361
368
    def activate(self):
362
369
        """Derived from the Avahi example code"""
363
370
        if self.server is None:
375
382
        """Add the new name to the syslog messages"""
376
383
        ret = AvahiService.rename(self)
377
384
        syslogger.setFormatter(logging.Formatter
378
 
                               ('Mandos (%s) [%%(process)d]:'
379
 
                                ' %%(levelname)s: %%(message)s'
380
 
                                % self.name))
 
385
                               ('Mandos ({0}) [%(process)d]:'
 
386
                                ' %(levelname)s: %(message)s'
 
387
                                .format(self.name)))
381
388
        return ret
382
389
 
383
390
def timedelta_to_milliseconds(td):
385
392
    return ((td.days * 24 * 60 * 60 * 1000)
386
393
            + (td.seconds * 1000)
387
394
            + (td.microseconds // 1000))
388
 
        
 
395
 
389
396
class Client(object):
390
397
    """A representation of a client host served by this server.
391
398
    
458
465
    
459
466
    def approval_delay_milliseconds(self):
460
467
        return timedelta_to_milliseconds(self.approval_delay)
461
 
 
 
468
    
462
469
    @staticmethod
463
470
    def config_parser(config):
464
471
        """Construct a new dict of client settings of this form:
489
496
                          "rb") as secfile:
490
497
                    client["secret"] = secfile.read()
491
498
            else:
492
 
                raise TypeError("No secret or secfile for section %s"
493
 
                                % section)
 
499
                raise TypeError("No secret or secfile for section {0}"
 
500
                                .format(section))
494
501
            client["timeout"] = string_to_delta(section["timeout"])
495
502
            client["extended_timeout"] = string_to_delta(
496
503
                section["extended_timeout"])
505
512
            client["last_checker_status"] = -2
506
513
        
507
514
        return settings
508
 
        
509
 
        
 
515
    
510
516
    def __init__(self, settings, name = None):
511
 
        """Note: the 'checker' key in 'config' sets the
512
 
        'checker_command' attribute and *not* the 'checker'
513
 
        attribute."""
514
517
        self.name = name
515
518
        # adding all client settings
516
519
        for setting, value in settings.iteritems():
525
528
        else:
526
529
            self.last_enabled = None
527
530
            self.expires = None
528
 
       
 
531
        
529
532
        logger.debug("Creating client %r", self.name)
530
533
        # Uppercase and remove spaces from fingerprint for later
531
534
        # comparison purposes with return value from the fingerprint()
533
536
        logger.debug("  Fingerprint: %s", self.fingerprint)
534
537
        self.created = settings.get("created",
535
538
                                    datetime.datetime.utcnow())
536
 
 
 
539
        
537
540
        # attributes specific for this server instance
538
541
        self.checker = None
539
542
        self.checker_initiator_tag = None
693
696
                try:
694
697
                    command = self.checker_command % escaped_attrs
695
698
                except TypeError as error:
696
 
                    logger.error('Could not format string "%s":'
697
 
                                 ' %s', self.checker_command, error)
 
699
                    logger.error('Could not format string "%s"',
 
700
                                 self.checker_command, exc_info=error)
698
701
                    return True # Try again later
699
702
            self.current_checker_command = command
700
703
            try:
718
721
                    gobject.source_remove(self.checker_callback_tag)
719
722
                    self.checker_callback(pid, status, command)
720
723
            except OSError as error:
721
 
                logger.error("Failed to start subprocess: %s",
722
 
                             error)
 
724
                logger.error("Failed to start subprocess",
 
725
                             exc_info=error)
723
726
        # Re-run this periodically if run by gobject.timeout_add
724
727
        return True
725
728
    
732
735
            return
733
736
        logger.debug("Stopping checker for %(name)s", vars(self))
734
737
        try:
735
 
            os.kill(self.checker.pid, signal.SIGTERM)
 
738
            self.checker.terminate()
736
739
            #time.sleep(0.5)
737
740
            #if self.checker.poll() is None:
738
 
            #    os.kill(self.checker.pid, signal.SIGKILL)
 
741
            #    self.checker.kill()
739
742
        except OSError as error:
740
743
            if error.errno != errno.ESRCH: # No such process
741
744
                raise
758
761
    # "Set" method, so we fail early here:
759
762
    if byte_arrays and signature != "ay":
760
763
        raise ValueError("Byte arrays not supported for non-'ay'"
761
 
                         " signature %r" % signature)
 
764
                         " signature {0!r}".format(signature))
762
765
    def decorator(func):
763
766
        func._dbus_is_property = True
764
767
        func._dbus_interface = dbus_interface
773
776
 
774
777
 
775
778
def dbus_interface_annotations(dbus_interface):
776
 
    """Decorator for marking functions returning interface annotations.
 
779
    """Decorator for marking functions returning interface annotations
777
780
    
778
781
    Usage:
779
782
    
791
794
    return decorator
792
795
 
793
796
 
 
797
def dbus_annotations(annotations):
 
798
    """Decorator to annotate D-Bus methods, signals or properties
 
799
    Usage:
 
800
    
 
801
    @dbus_service_property("org.example.Interface", signature="b",
 
802
                           access="r")
 
803
    @dbus_annotations({{"org.freedesktop.DBus.Deprecated": "true",
 
804
                        "org.freedesktop.DBus.Property."
 
805
                        "EmitsChangedSignal": "false"})
 
806
    def Property_dbus_property(self):
 
807
        return dbus.Boolean(False)
 
808
    """
 
809
    def decorator(func):
 
810
        func._dbus_annotations = annotations
 
811
        return func
 
812
    return decorator
 
813
 
 
814
 
794
815
class DBusPropertyException(dbus.exceptions.DBusException):
795
816
    """A base class for D-Bus property-related exceptions
796
817
    """
831
852
    def _get_all_dbus_things(self, thing):
832
853
        """Returns a generator of (name, attribute) pairs
833
854
        """
834
 
        return ((athing.__get__(self)._dbus_name,
 
855
        return ((getattr(athing.__get__(self), "_dbus_name",
 
856
                         name),
835
857
                 athing.__get__(self))
836
858
                for cls in self.__class__.__mro__
837
859
                for name, athing in
936
958
                            if prop._dbus_interface
937
959
                            == if_tag.getAttribute("name")):
938
960
                    if_tag.appendChild(tag)
 
961
                # Add annotation tags
 
962
                for typ in ("method", "signal", "property"):
 
963
                    for tag in if_tag.getElementsByTagName(typ):
 
964
                        annots = dict()
 
965
                        for name, prop in (self.
 
966
                                           _get_all_dbus_things(typ)):
 
967
                            if (name == tag.getAttribute("name")
 
968
                                and prop._dbus_interface
 
969
                                == if_tag.getAttribute("name")):
 
970
                                annots.update(getattr
 
971
                                              (prop,
 
972
                                               "_dbus_annotations",
 
973
                                               {}))
 
974
                        for name, value in annots.iteritems():
 
975
                            ann_tag = document.createElement(
 
976
                                "annotation")
 
977
                            ann_tag.setAttribute("name", name)
 
978
                            ann_tag.setAttribute("value", value)
 
979
                            tag.appendChild(ann_tag)
939
980
                # Add interface annotation tags
940
981
                for annotation, value in dict(
941
982
                    itertools.chain(
944
985
                          self._get_all_dbus_things("interface")
945
986
                          if name == if_tag.getAttribute("name")
946
987
                          ))).iteritems():
947
 
                    attr_tag = document.createElement("annotation")
948
 
                    attr_tag.setAttribute("name", annotation)
949
 
                    attr_tag.setAttribute("value", value)
950
 
                    if_tag.appendChild(attr_tag)
 
988
                    ann_tag = document.createElement("annotation")
 
989
                    ann_tag.setAttribute("name", annotation)
 
990
                    ann_tag.setAttribute("value", value)
 
991
                    if_tag.appendChild(ann_tag)
951
992
                # Add the names to the return values for the
952
993
                # "org.freedesktop.DBus.Properties" methods
953
994
                if (if_tag.getAttribute("name")
968
1009
        except (AttributeError, xml.dom.DOMException,
969
1010
                xml.parsers.expat.ExpatError) as error:
970
1011
            logger.error("Failed to override Introspection method",
971
 
                         error)
 
1012
                         exc_info=error)
972
1013
        return xmlstring
973
1014
 
974
1015
 
980
1021
                       variant_level=variant_level)
981
1022
 
982
1023
 
983
 
class AlternateDBusNamesMetaclass(DBusObjectWithProperties
984
 
                                  .__metaclass__):
985
 
    """Applied to an empty subclass of a D-Bus object, this metaclass
986
 
    will add additional D-Bus attributes matching a certain pattern.
 
1024
def alternate_dbus_interfaces(alt_interface_names, deprecate=True):
 
1025
    """A class decorator; applied to a subclass of
 
1026
    dbus.service.Object, it will add alternate D-Bus attributes with
 
1027
    interface names according to the "alt_interface_names" mapping.
 
1028
    Usage:
 
1029
    
 
1030
    @alternate_dbus_names({"org.example.Interface":
 
1031
                               "net.example.AlternateInterface"})
 
1032
    class SampleDBusObject(dbus.service.Object):
 
1033
        @dbus.service.method("org.example.Interface")
 
1034
        def SampleDBusMethod():
 
1035
            pass
 
1036
    
 
1037
    The above "SampleDBusMethod" on "SampleDBusObject" will be
 
1038
    reachable via two interfaces: "org.example.Interface" and
 
1039
    "net.example.AlternateInterface", the latter of which will have
 
1040
    its D-Bus annotation "org.freedesktop.DBus.Deprecated" set to
 
1041
    "true", unless "deprecate" is passed with a False value.
 
1042
    
 
1043
    This works for methods and signals, and also for D-Bus properties
 
1044
    (from DBusObjectWithProperties) and interfaces (from the
 
1045
    dbus_interface_annotations decorator).
987
1046
    """
988
 
    def __new__(mcs, name, bases, attr):
989
 
        # Go through all the base classes which could have D-Bus
990
 
        # methods, signals, or properties in them
991
 
        old_interface_names = []
992
 
        for base in (b for b in bases
993
 
                     if issubclass(b, dbus.service.Object)):
994
 
            # Go though all attributes of the base class
995
 
            for attrname, attribute in inspect.getmembers(base):
 
1047
    def wrapper(cls):
 
1048
        for orig_interface_name, alt_interface_name in (
 
1049
            alt_interface_names.iteritems()):
 
1050
            attr = {}
 
1051
            interface_names = set()
 
1052
            # Go though all attributes of the class
 
1053
            for attrname, attribute in inspect.getmembers(cls):
996
1054
                # Ignore non-D-Bus attributes, and D-Bus attributes
997
1055
                # with the wrong interface name
998
1056
                if (not hasattr(attribute, "_dbus_interface")
999
1057
                    or not attribute._dbus_interface
1000
 
                    .startswith("se.recompile.Mandos")):
 
1058
                    .startswith(orig_interface_name)):
1001
1059
                    continue
1002
1060
                # Create an alternate D-Bus interface name based on
1003
1061
                # the current name
1004
1062
                alt_interface = (attribute._dbus_interface
1005
 
                                 .replace("se.recompile.Mandos",
1006
 
                                          "se.bsnet.fukt.Mandos"))
1007
 
                if alt_interface != attribute._dbus_interface:
1008
 
                    old_interface_names.append(alt_interface)
 
1063
                                 .replace(orig_interface_name,
 
1064
                                          alt_interface_name))
 
1065
                interface_names.add(alt_interface)
1009
1066
                # Is this a D-Bus signal?
1010
1067
                if getattr(attribute, "_dbus_is_signal", False):
1011
1068
                    # Extract the original non-method function by
1026
1083
                                nonmethod_func.func_name,
1027
1084
                                nonmethod_func.func_defaults,
1028
1085
                                nonmethod_func.func_closure)))
 
1086
                    # Copy annotations, if any
 
1087
                    try:
 
1088
                        new_function._dbus_annotations = (
 
1089
                            dict(attribute._dbus_annotations))
 
1090
                    except AttributeError:
 
1091
                        pass
1029
1092
                    # Define a creator of a function to call both the
1030
 
                    # old and new functions, so both the old and new
1031
 
                    # signals gets sent when the function is called
 
1093
                    # original and alternate functions, so both the
 
1094
                    # original and alternate signals gets sent when
 
1095
                    # the function is called
1032
1096
                    def fixscope(func1, func2):
1033
1097
                        """This function is a scope container to pass
1034
1098
                        func1 and func2 to the "call_both" function
1041
1105
                        return call_both
1042
1106
                    # Create the "call_both" function and add it to
1043
1107
                    # the class
1044
 
                    attr[attrname] = fixscope(attribute,
1045
 
                                              new_function)
 
1108
                    attr[attrname] = fixscope(attribute, new_function)
1046
1109
                # Is this a D-Bus method?
1047
1110
                elif getattr(attribute, "_dbus_is_method", False):
1048
1111
                    # Create a new, but exactly alike, function
1059
1122
                                        attribute.func_name,
1060
1123
                                        attribute.func_defaults,
1061
1124
                                        attribute.func_closure)))
 
1125
                    # Copy annotations, if any
 
1126
                    try:
 
1127
                        attr[attrname]._dbus_annotations = (
 
1128
                            dict(attribute._dbus_annotations))
 
1129
                    except AttributeError:
 
1130
                        pass
1062
1131
                # Is this a D-Bus property?
1063
1132
                elif getattr(attribute, "_dbus_is_property", False):
1064
1133
                    # Create a new, but exactly alike, function
1078
1147
                                        attribute.func_name,
1079
1148
                                        attribute.func_defaults,
1080
1149
                                        attribute.func_closure)))
 
1150
                    # Copy annotations, if any
 
1151
                    try:
 
1152
                        attr[attrname]._dbus_annotations = (
 
1153
                            dict(attribute._dbus_annotations))
 
1154
                    except AttributeError:
 
1155
                        pass
1081
1156
                # Is this a D-Bus interface?
1082
1157
                elif getattr(attribute, "_dbus_is_interface", False):
1083
1158
                    # Create a new, but exactly alike, function
1092
1167
                                        attribute.func_name,
1093
1168
                                        attribute.func_defaults,
1094
1169
                                        attribute.func_closure)))
1095
 
        # Deprecate all old interfaces
1096
 
        basename="_AlternateDBusNamesMetaclass_interface_annotation{0}"
1097
 
        for old_interface_name in old_interface_names:
1098
 
            @dbus_interface_annotations(old_interface_name)
1099
 
            def func(self):
1100
 
                return { "org.freedesktop.DBus.Deprecated": "true" }
1101
 
            # Find an unused name
1102
 
            for aname in (basename.format(i) for i in
1103
 
                          itertools.count()):
1104
 
                if aname not in attr:
1105
 
                    attr[aname] = func
1106
 
                    break
1107
 
        return type.__new__(mcs, name, bases, attr)
1108
 
 
1109
 
 
 
1170
            if deprecate:
 
1171
                # Deprecate all alternate interfaces
 
1172
                iname="_AlternateDBusNames_interface_annotation{0}"
 
1173
                for interface_name in interface_names:
 
1174
                    @dbus_interface_annotations(interface_name)
 
1175
                    def func(self):
 
1176
                        return { "org.freedesktop.DBus.Deprecated":
 
1177
                                     "true" }
 
1178
                    # Find an unused name
 
1179
                    for aname in (iname.format(i)
 
1180
                                  for i in itertools.count()):
 
1181
                        if aname not in attr:
 
1182
                            attr[aname] = func
 
1183
                            break
 
1184
            if interface_names:
 
1185
                # Replace the class with a new subclass of it with
 
1186
                # methods, signals, etc. as created above.
 
1187
                cls = type(b"{0}Alternate".format(cls.__name__),
 
1188
                           (cls,), attr)
 
1189
        return cls
 
1190
    return wrapper
 
1191
 
 
1192
 
 
1193
@alternate_dbus_interfaces({"se.recompile.Mandos":
 
1194
                                "se.bsnet.fukt.Mandos"})
1110
1195
class ClientDBus(Client, DBusObjectWithProperties):
1111
1196
    """A Client class using D-Bus
1112
1197
    
1132
1217
                                 ("/clients/" + client_object_name))
1133
1218
        DBusObjectWithProperties.__init__(self, self.bus,
1134
1219
                                          self.dbus_object_path)
1135
 
        
 
1220
    
1136
1221
    def notifychangeproperty(transform_func,
1137
1222
                             dbus_name, type_func=lambda x: x,
1138
1223
                             variant_level=1):
1161
1246
        
1162
1247
        return property(lambda self: getattr(self, attrname), setter)
1163
1248
    
1164
 
    
1165
1249
    expires = notifychangeproperty(datetime_to_dbus, "Expires")
1166
1250
    approvals_pending = notifychangeproperty(dbus.Boolean,
1167
1251
                                             "ApprovalPending",
1255
1339
                            (self.approval_duration),
1256
1340
                            self._reset_approved)
1257
1341
    
1258
 
    
1259
1342
    ## D-Bus methods, signals & properties
1260
1343
    _interface = "se.recompile.Mandos.Client"
1261
1344
    
1548
1631
        self._pipe.send(('setattr', name, value))
1549
1632
 
1550
1633
 
1551
 
class ClientDBusTransitional(ClientDBus):
1552
 
    __metaclass__ = AlternateDBusNamesMetaclass
1553
 
 
1554
 
 
1555
1634
class ClientHandler(socketserver.BaseRequestHandler, object):
1556
1635
    """A class to handle client connections.
1557
1636
    
1685
1764
                    try:
1686
1765
                        sent = session.send(client.secret[sent_size:])
1687
1766
                    except gnutls.errors.GNUTLSError as error:
1688
 
                        logger.warning("gnutls send failed")
 
1767
                        logger.warning("gnutls send failed",
 
1768
                                       exc_info=error)
1689
1769
                        return
1690
1770
                    logger.debug("Sent: %d, remaining: %d",
1691
1771
                                 sent, len(client.secret)
1705
1785
                try:
1706
1786
                    session.bye()
1707
1787
                except gnutls.errors.GNUTLSError as error:
1708
 
                    logger.warning("GnuTLS bye failed")
 
1788
                    logger.warning("GnuTLS bye failed",
 
1789
                                   exc_info=error)
1709
1790
    
1710
1791
    @staticmethod
1711
1792
    def peer_certificate(session):
2023
2104
            elif suffix == "w":
2024
2105
                delta = datetime.timedelta(0, 0, 0, 0, 0, 0, value)
2025
2106
            else:
2026
 
                raise ValueError("Unknown suffix %r" % suffix)
 
2107
                raise ValueError("Unknown suffix {0!r}"
 
2108
                                 .format(suffix))
2027
2109
        except (ValueError, IndexError) as e:
2028
2110
            raise ValueError(*(e.args))
2029
2111
        timevalue += delta
2046
2128
        null = os.open(os.devnull, os.O_NOCTTY | os.O_RDWR)
2047
2129
        if not stat.S_ISCHR(os.fstat(null).st_mode):
2048
2130
            raise OSError(errno.ENODEV,
2049
 
                          "%s not a character device"
2050
 
                          % os.devnull)
 
2131
                          "{0} not a character device"
 
2132
                          .format(os.devnull))
2051
2133
        os.dup2(null, sys.stdin.fileno())
2052
2134
        os.dup2(null, sys.stdout.fileno())
2053
2135
        os.dup2(null, sys.stderr.fileno())
2062
2144
    
2063
2145
    parser = argparse.ArgumentParser()
2064
2146
    parser.add_argument("-v", "--version", action="version",
2065
 
                        version = "%%(prog)s %s" % version,
 
2147
                        version = "%(prog)s {0}".format(version),
2066
2148
                        help="show version number and exit")
2067
2149
    parser.add_argument("-i", "--interface", metavar="IF",
2068
2150
                        help="Bind to interface IF")
2171
2253
    
2172
2254
    if server_settings["servicename"] != "Mandos":
2173
2255
        syslogger.setFormatter(logging.Formatter
2174
 
                               ('Mandos (%s) [%%(process)d]:'
2175
 
                                ' %%(levelname)s: %%(message)s'
2176
 
                                % server_settings["servicename"]))
 
2256
                               ('Mandos ({0}) [%(process)d]:'
 
2257
                                ' %(levelname)s: %(message)s'
 
2258
                                .format(server_settings
 
2259
                                        ["servicename"])))
2177
2260
    
2178
2261
    # Parse config file with clients
2179
2262
    client_config = configparser.SafeConfigParser(Client
2197
2280
        pidfilename = "/var/run/mandos.pid"
2198
2281
        try:
2199
2282
            pidfile = open(pidfilename, "w")
2200
 
        except IOError:
2201
 
            logger.error("Could not open file %r", pidfilename)
 
2283
        except IOError as e:
 
2284
            logger.error("Could not open file %r", pidfilename,
 
2285
                         exc_info=e)
2202
2286
    
2203
 
    try:
2204
 
        uid = pwd.getpwnam("_mandos").pw_uid
2205
 
        gid = pwd.getpwnam("_mandos").pw_gid
2206
 
    except KeyError:
 
2287
    for name in ("_mandos", "mandos", "nobody"):
2207
2288
        try:
2208
 
            uid = pwd.getpwnam("mandos").pw_uid
2209
 
            gid = pwd.getpwnam("mandos").pw_gid
 
2289
            uid = pwd.getpwnam(name).pw_uid
 
2290
            gid = pwd.getpwnam(name).pw_gid
 
2291
            break
2210
2292
        except KeyError:
2211
 
            try:
2212
 
                uid = pwd.getpwnam("nobody").pw_uid
2213
 
                gid = pwd.getpwnam("nobody").pw_gid
2214
 
            except KeyError:
2215
 
                uid = 65534
2216
 
                gid = 65534
 
2293
            continue
 
2294
    else:
 
2295
        uid = 65534
 
2296
        gid = 65534
2217
2297
    try:
2218
2298
        os.setgid(gid)
2219
2299
        os.setuid(uid)
2262
2342
                            ("se.bsnet.fukt.Mandos", bus,
2263
2343
                             do_not_queue=True))
2264
2344
        except dbus.exceptions.NameExistsException as e:
2265
 
            logger.error(unicode(e) + ", disabling D-Bus")
 
2345
            logger.error("Disabling D-Bus:", exc_info=e)
2266
2346
            use_dbus = False
2267
2347
            server_settings["use_dbus"] = False
2268
2348
            tcp_server.use_dbus = False
2280
2360
    
2281
2361
    client_class = Client
2282
2362
    if use_dbus:
2283
 
        client_class = functools.partial(ClientDBusTransitional,
2284
 
                                         bus = bus)
 
2363
        client_class = functools.partial(ClientDBus, bus = bus)
2285
2364
    
2286
2365
    client_settings = Client.config_parser(client_config)
2287
2366
    old_client_settings = {}
2295
2374
                                                     (stored_state))
2296
2375
            os.remove(stored_state_path)
2297
2376
        except IOError as e:
2298
 
            logger.warning("Could not load persistent state: {0}"
2299
 
                           .format(e))
2300
 
            if e.errno != errno.ENOENT:
 
2377
            if e.errno == errno.ENOENT:
 
2378
                logger.warning("Could not load persistent state: {0}"
 
2379
                                .format(os.strerror(e.errno)))
 
2380
            else:
 
2381
                logger.critical("Could not load persistent state:",
 
2382
                                exc_info=e)
2301
2383
                raise
2302
2384
        except EOFError as e:
2303
2385
            logger.warning("Could not load persistent state: "
2304
 
                           "EOFError: {0}".format(e))
 
2386
                           "EOFError:", exc_info=e)
2305
2387
    
2306
2388
    with PGPEngine() as pgp:
2307
2389
        for client_name, client in clients_data.iteritems():
2360
2442
                             .format(client_name))
2361
2443
                client["secret"] = (
2362
2444
                    client_settings[client_name]["secret"])
2363
 
 
2364
2445
    
2365
2446
    # Add/remove clients based on new changes made to config
2366
2447
    for client_name in (set(old_client_settings)
2369
2450
    for client_name in (set(client_settings)
2370
2451
                        - set(old_client_settings)):
2371
2452
        clients_data[client_name] = client_settings[client_name]
2372
 
 
 
2453
    
2373
2454
    # Create all client objects
2374
2455
    for client_name, client in clients_data.iteritems():
2375
2456
        tcp_server.clients[client_name] = client_class(
2377
2458
    
2378
2459
    if not tcp_server.clients:
2379
2460
        logger.warning("No clients defined")
2380
 
        
 
2461
    
2381
2462
    if not debug:
2382
2463
        try:
2383
2464
            with pidfile:
2397
2478
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
2398
2479
    
2399
2480
    if use_dbus:
 
2481
        @alternate_dbus_interfaces({"se.recompile.Mandos":
 
2482
                                        "se.bsnet.fukt.Mandos"})
2400
2483
        class MandosDBusService(DBusObjectWithProperties):
2401
2484
            """A D-Bus proxy object"""
2402
2485
            def __init__(self):
2456
2539
            
2457
2540
            del _interface
2458
2541
        
2459
 
        class MandosDBusServiceTransitional(MandosDBusService):
2460
 
            __metaclass__ = AlternateDBusNamesMetaclass
2461
 
        mandos_dbus_service = MandosDBusServiceTransitional()
 
2542
        mandos_dbus_service = MandosDBusService()
2462
2543
    
2463
2544
    def cleanup():
2464
2545
        "Cleanup function; run on exit"
2505
2586
                pickle.dump((clients, client_settings), stored_state)
2506
2587
            os.rename(tempname, stored_state_path)
2507
2588
        except (IOError, OSError) as e:
2508
 
            logger.warning("Could not save persistent state: {0}"
2509
 
                           .format(e))
2510
2589
            if not debug:
2511
2590
                try:
2512
2591
                    os.remove(tempname)
2513
2592
                except NameError:
2514
2593
                    pass
2515
 
            if e.errno not in set((errno.ENOENT, errno.EACCES,
2516
 
                                   errno.EEXIST)):
 
2594
            if e.errno in (errno.ENOENT, errno.EACCES, errno.EEXIST):
 
2595
                logger.warning("Could not save persistent state: {0}"
 
2596
                               .format(os.strerror(e.errno)))
 
2597
            else:
 
2598
                logger.warning("Could not save persistent state:",
 
2599
                               exc_info=e)
2517
2600
                raise e
2518
2601
        
2519
2602
        # Delete all clients, and settings from config
2547
2630
    service.port = tcp_server.socket.getsockname()[1]
2548
2631
    if use_ipv6:
2549
2632
        logger.info("Now listening on address %r, port %d,"
2550
 
                    " flowinfo %d, scope_id %d"
2551
 
                    % tcp_server.socket.getsockname())
 
2633
                    " flowinfo %d, scope_id %d",
 
2634
                    *tcp_server.socket.getsockname())
2552
2635
    else:                       # IPv4
2553
 
        logger.info("Now listening on address %r, port %d"
2554
 
                    % tcp_server.socket.getsockname())
 
2636
        logger.info("Now listening on address %r, port %d",
 
2637
                    *tcp_server.socket.getsockname())
2555
2638
    
2556
2639
    #service.interface = tcp_server.socket.getsockname()[3]
2557
2640
    
2560
2643
        try:
2561
2644
            service.activate()
2562
2645
        except dbus.exceptions.DBusException as error:
2563
 
            logger.critical("DBusException: %s", error)
 
2646
            logger.critical("D-Bus Exception", exc_info=error)
2564
2647
            cleanup()
2565
2648
            sys.exit(1)
2566
2649
        # End of Avahi example code
2573
2656
        logger.debug("Starting main loop")
2574
2657
        main_loop.run()
2575
2658
    except AvahiError as error:
2576
 
        logger.critical("AvahiError: %s", error)
 
2659
        logger.critical("Avahi Error", exc_info=error)
2577
2660
        cleanup()
2578
2661
        sys.exit(1)
2579
2662
    except KeyboardInterrupt: