71
71
logger = logging.Logger('mandos')
 
72
72
syslogger = (logging.handlers.SysLogHandler
 
73
73
             (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
 
74
74
              address = "/dev/log"))
 
75
75
syslogger.setFormatter(logging.Formatter
 
76
 
                       ('Mandos: %(levelname)s: %(message)s'))
 
 
76
                       ('Mandos [%(process)d]: %(levelname)s:'
 
77
78
logger.addHandler(syslogger)
 
79
80
console = logging.StreamHandler()
 
80
 
console.setFormatter(logging.Formatter('%(name)s: %(levelname)s:'
 
 
81
console.setFormatter(logging.Formatter('%(name)s [%(process)d]:'
 
 
82
                                       ' %(levelname)s: %(message)s'))
 
82
83
logger.addHandler(console)
 
84
85
class AvahiError(Exception):
 
 
178
179
class Client(dbus.service.Object):
 
179
180
    """A representation of a client host served by this server.
 
181
 
    name:       string; from the config file, used in log messages
 
 
182
    name:       string; from the config file, used in log messages and
 
182
184
    fingerprint: string (40 or 32 hexadecimal digits); used to
 
183
185
                 uniquely identify the client
 
184
186
    secret:     bytestring; sent verbatim (over TLS) to client
 
 
225
227
        if config is None:
 
227
229
        logger.debug(u"Creating client %r", self.name)
 
228
 
        self.use_dbus = use_dbus
 
230
 
            self.dbus_object_path = (dbus.ObjectPath
 
232
 
                                      + self.name.replace(".", "_")))
 
233
 
            dbus.service.Object.__init__(self, bus,
 
234
 
                                         self.dbus_object_path)
 
 
230
        self.use_dbus = False   # During __init__
 
235
231
        # Uppercase and remove spaces from fingerprint for later
 
236
232
        # comparison purposes with return value from the fingerprint()
 
 
261
257
        self.disable_initiator_tag = None
 
262
258
        self.checker_callback_tag = None
 
263
259
        self.checker_command = config["checker"]
 
 
260
        self.last_connect = None
 
 
261
        # Only now, when this client is initialized, can it show up on
 
 
263
        self.use_dbus = use_dbus
 
 
265
            self.dbus_object_path = (dbus.ObjectPath
 
 
267
                                      + self.name.replace(".", "_")))
 
 
268
            dbus.service.Object.__init__(self, bus,
 
 
269
                                         self.dbus_object_path)
 
265
271
    def enable(self):
 
266
272
        """Start this client's checker and timeout hooks"""
 
 
319
325
            # Emit D-Bus signal
 
320
326
            self.PropertyChanged(dbus.String(u"checker_running"),
 
321
327
                                 dbus.Boolean(False, variant_level=1))
 
322
 
        if (os.WIFEXITED(condition)
 
323
 
            and (os.WEXITSTATUS(condition) == 0)):
 
324
 
            logger.info(u"Checker for %(name)s succeeded",
 
 
328
        if os.WIFEXITED(condition):
 
 
329
            exitstatus = os.WEXITSTATUS(condition)
 
 
331
                logger.info(u"Checker for %(name)s succeeded",
 
 
335
                logger.info(u"Checker for %(name)s failed",
 
326
337
            if self.use_dbus:
 
327
338
                # Emit D-Bus signal
 
328
 
                self.CheckerCompleted(dbus.Boolean(True),
 
329
 
                                      dbus.UInt16(condition),
 
 
339
                self.CheckerCompleted(dbus.Int16(exitstatus),
 
 
340
                                      dbus.Int64(condition),
 
330
341
                                      dbus.String(command))
 
332
 
        elif not os.WIFEXITED(condition):
 
333
343
            logger.warning(u"Checker for %(name)s crashed?",
 
335
345
            if self.use_dbus:
 
336
346
                # Emit D-Bus signal
 
337
 
                self.CheckerCompleted(dbus.Boolean(False),
 
338
 
                                      dbus.UInt16(condition),
 
339
 
                                      dbus.String(command))
 
341
 
            logger.info(u"Checker for %(name)s failed",
 
345
 
                self.CheckerCompleted(dbus.Boolean(False),
 
346
 
                                      dbus.UInt16(condition),
 
 
347
                self.CheckerCompleted(dbus.Int16(-1),
 
 
348
                                      dbus.Int64(condition),
 
347
349
                                      dbus.String(command))
 
349
 
    def bump_timeout(self):
 
 
351
    def checked_ok(self):
 
350
352
        """Bump up the timeout for this client.
 
351
353
        This should only be called when the client has been seen,
 
 
448
450
            return now < (self.last_checked_ok + self.timeout)
 
450
452
    ## D-Bus methods & signals
 
451
 
    _interface = u"org.mandos_system.Mandos.Client"
 
 
453
    _interface = u"se.bsnet.fukt.Mandos.Client"
 
453
 
    # BumpTimeout - method
 
454
 
    BumpTimeout = dbus.service.method(_interface)(bump_timeout)
 
455
 
    BumpTimeout.__name__ = "BumpTimeout"
 
 
456
    CheckedOK = dbus.service.method(_interface)(checked_ok)
 
 
457
    CheckedOK.__name__ = "CheckedOK"
 
457
459
    # CheckerCompleted - signal
 
458
 
    @dbus.service.signal(_interface, signature="bqs")
 
459
 
    def CheckerCompleted(self, success, condition, command):
 
 
460
    @dbus.service.signal(_interface, signature="nxs")
 
 
461
    def CheckerCompleted(self, exitcode, waitstatus, command):
 
 
503
505
                dbus.String("checker_running"):
 
504
506
                    dbus.Boolean(self.checker is not None,
 
505
507
                                 variant_level=1),
 
 
508
                dbus.String("object_path"):
 
 
509
                    dbus.ObjectPath(self.dbus_object_path,
 
506
511
                }, signature="sv")
 
508
513
    # IsStillValid - method
 
 
591
596
        != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
 
592
597
        # ...do the normal thing
 
593
598
        return session.peer_certificate
 
594
 
    list_size = ctypes.c_uint()
 
 
599
    list_size = ctypes.c_uint(1)
 
595
600
    cert_list = (gnutls.library.functions
 
596
601
                 .gnutls_certificate_get_peers
 
597
602
                 (session._c_object, ctypes.byref(list_size)))
 
 
603
    if not bool(cert_list) and list_size.value != 0:
 
 
604
        raise gnutls.errors.GNUTLSError("error getting peer"
 
598
606
    if list_size.value == 0:
 
600
608
    cert = cert_list[0]
 
 
669
677
        # using OpenPGP certificates.
 
671
679
        #priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
 
672
 
        #                "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
 
 
680
        #                     "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
 
674
682
        # Use a fallback default, since this MUST be set.
 
675
683
        priority = self.server.settings.get("priority", "NORMAL")
 
676
684
        (gnutls.library.functions
 
 
684
692
            # Do not run session.bye() here: the session is not
 
685
693
            # established.  Just abandon the request.
 
 
695
        logger.debug(u"Handshake succeeded")
 
688
697
            fpr = fingerprint(peer_certificate(session))
 
689
698
        except (TypeError, gnutls.errors.GNUTLSError), error:
 
 
755
765
                                 u" bind to interface %s",
 
756
766
                                 self.settings["interface"])
 
759
769
        # Only bind(2) the socket if we really need to.
 
760
770
        if self.server_address[0] or self.server_address[1]:
 
761
771
            if not self.server_address[0]:
 
 
892
 
    parser = OptionParser(version = "%%prog %s" % version)
 
 
902
    parser = optparse.OptionParser(version = "%%prog %s" % version)
 
893
903
    parser.add_option("-i", "--interface", type="string",
 
894
904
                      metavar="IF", help="Bind to interface IF")
 
895
905
    parser.add_option("-a", "--address", type="string",
 
 
937
947
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
 
938
948
    # Convert the SafeConfigParser object to a dict
 
939
949
    server_settings = server_config.defaults()
 
940
 
    # Use getboolean on the boolean config options
 
941
 
    server_settings["debug"] = (server_config.getboolean
 
942
 
                                ("DEFAULT", "debug"))
 
943
 
    server_settings["use_dbus"] = (server_config.getboolean
 
944
 
                                   ("DEFAULT", "use_dbus"))
 
 
950
    # Use the appropriate methods on the non-string config options
 
 
951
    server_settings["debug"] = server_config.getboolean("DEFAULT",
 
 
953
    server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
 
 
955
    if server_settings["port"]:
 
 
956
        server_settings["port"] = server_config.getint("DEFAULT",
 
945
958
    del server_config
 
947
960
    # Override the settings from the config file with command line
 
 
1011
1024
    except OSError, error:
 
1012
1025
        if error[0] != errno.EPERM:
 
 
1028
    # Enable all possible GnuTLS debugging
 
 
1030
        # "Use a log level over 10 to enable all debugging options."
 
 
1032
        gnutls.library.functions.gnutls_global_set_log_level(11)
 
 
1034
        @gnutls.library.types.gnutls_log_func
 
 
1035
        def debug_gnutls(level, string):
 
 
1036
            logger.debug("GnuTLS: %s", string[:-1])
 
 
1038
        (gnutls.library.functions
 
 
1039
         .gnutls_global_set_log_function(debug_gnutls))
 
1016
1042
    service = AvahiService(name = server_settings["servicename"],
 
1017
1043
                           servicetype = "_mandos._tcp", )
 
 
1031
1057
                            avahi.DBUS_INTERFACE_SERVER)
 
1032
1058
    # End of Avahi example code
 
1034
 
        bus_name = dbus.service.BusName(u"org.mandos-system.Mandos",
 
 
1060
        bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
 
1037
1062
    clients.update(Set(Client(name = section,
 
 
1092
1117
        class MandosServer(dbus.service.Object):
 
1093
1118
            """A D-Bus proxy object"""
 
1094
1119
            def __init__(self):
 
1095
 
                dbus.service.Object.__init__(self, bus,
 
1097
 
            _interface = u"org.mandos_system.Mandos"
 
 
1120
                dbus.service.Object.__init__(self, bus, "/")
 
 
1121
            _interface = u"se.bsnet.fukt.Mandos"
 
1099
1123
            @dbus.service.signal(_interface, signature="oa{sv}")
 
1100
1124
            def ClientAdded(self, objpath, properties):
 
1104
 
            @dbus.service.signal(_interface, signature="o")
 
1105
 
            def ClientRemoved(self, objpath):
 
 
1128
            @dbus.service.signal(_interface, signature="os")
 
 
1129
            def ClientRemoved(self, objpath, name):
 
1109
1133
            @dbus.service.method(_interface, out_signature="ao")
 
1110
1134
            def GetAllClients(self):
 
1111
1136
                return dbus.Array(c.dbus_object_path for c in clients)
 
1113
1138
            @dbus.service.method(_interface, out_signature="a{oa{sv}}")
 
1114
1139
            def GetAllClientsWithProperties(self):
 
1115
1141
                return dbus.Dictionary(
 
1116
1142
                    ((c.dbus_object_path, c.GetAllProperties())
 
1117
1143
                     for c in clients),
 
1118
1144
                    signature="oa{sv}")
 
1120
1146
            @dbus.service.method(_interface, in_signature="o")
 
1121
1147
            def RemoveClient(self, object_path):
 
1122
1149
                for c in clients:
 
1123
1150
                    if c.dbus_object_path == object_path:
 
1124
1151
                        clients.remove(c)
 
 
1126
1153
                        c.use_dbus = False
 
1128
1155
                        # Emit D-Bus signal
 
1129
 
                        self.ClientRemoved(object_path)
 
 
1156
                        self.ClientRemoved(object_path, c.name)
 
1132
 
            @dbus.service.method(_interface)
 
1138
1162
        mandos_server = MandosServer()
 
1140
1164
    for client in clients: