/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Björn Påhlsson
  • Date: 2009-01-19 06:55:59 UTC
  • mto: (237.7.1 mandos) (24.1.154 mandos)
  • mto: This revision was merged to the branch mainline in revision 250.
  • Revision ID: belorn@braxen-20090119065559-vvflkj7ffxtn4ez4
fixed a bugg in mandos-ctl + added remove client option

Show diffs side-by-side

added added

removed removed

Lines of Context:
73
73
             (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
74
74
              address = "/dev/log"))
75
75
syslogger.setFormatter(logging.Formatter
76
 
                       ('Mandos [%(process)d]: %(levelname)s:'
77
 
                        ' %(message)s'))
 
76
                       ('Mandos: %(levelname)s: %(message)s'))
78
77
logger.addHandler(syslogger)
79
78
 
80
79
console = logging.StreamHandler()
81
 
console.setFormatter(logging.Formatter('%(name)s [%(process)d]:'
82
 
                                       ' %(levelname)s: %(message)s'))
 
80
console.setFormatter(logging.Formatter('%(name)s: %(levelname)s:'
 
81
                                       ' %(message)s'))
83
82
logger.addHandler(console)
84
83
 
85
84
class AvahiError(Exception):
227
226
        if config is None:
228
227
            config = {}
229
228
        logger.debug(u"Creating client %r", self.name)
230
 
        self.use_dbus = False   # During __init__
 
229
        self.use_dbus = use_dbus
 
230
        if self.use_dbus:
 
231
            self.dbus_object_path = (dbus.ObjectPath
 
232
                                     ("/Mandos/clients/"
 
233
                                      + self.name.replace(".", "_")))
 
234
            dbus.service.Object.__init__(self, bus,
 
235
                                         self.dbus_object_path)
231
236
        # Uppercase and remove spaces from fingerprint for later
232
237
        # comparison purposes with return value from the fingerprint()
233
238
        # function
257
262
        self.disable_initiator_tag = None
258
263
        self.checker_callback_tag = None
259
264
        self.checker_command = config["checker"]
260
 
        self.last_connect = None
261
 
        # Only now, when this client is initialized, can it show up on
262
 
        # the D-Bus
263
 
        self.use_dbus = use_dbus
264
 
        if self.use_dbus:
265
 
            self.dbus_object_path = (dbus.ObjectPath
266
 
                                     ("/clients/"
267
 
                                      + self.name.replace(".", "_")))
268
 
            dbus.service.Object.__init__(self, bus,
269
 
                                         self.dbus_object_path)
270
265
    
271
266
    def enable(self):
272
267
        """Start this client's checker and timeout hooks"""
325
320
            # Emit D-Bus signal
326
321
            self.PropertyChanged(dbus.String(u"checker_running"),
327
322
                                 dbus.Boolean(False, variant_level=1))
328
 
        if os.WIFEXITED(condition):
329
 
            exitstatus = os.WEXITSTATUS(condition)
330
 
            if exitstatus == 0:
331
 
                logger.info(u"Checker for %(name)s succeeded",
332
 
                            vars(self))
333
 
                self.checked_ok()
334
 
            else:
335
 
                logger.info(u"Checker for %(name)s failed",
336
 
                            vars(self))
 
323
        if (os.WIFEXITED(condition)
 
324
            and (os.WEXITSTATUS(condition) == 0)):
 
325
            logger.info(u"Checker for %(name)s succeeded",
 
326
                        vars(self))
337
327
            if self.use_dbus:
338
328
                # Emit D-Bus signal
339
 
                self.CheckerCompleted(dbus.Int16(exitstatus),
340
 
                                      dbus.Int64(condition),
 
329
                self.CheckerCompleted(dbus.Boolean(True),
 
330
                                      dbus.UInt16(condition),
341
331
                                      dbus.String(command))
342
 
        else:
 
332
            self.bump_timeout()
 
333
        elif not os.WIFEXITED(condition):
343
334
            logger.warning(u"Checker for %(name)s crashed?",
344
335
                           vars(self))
345
336
            if self.use_dbus:
346
337
                # Emit D-Bus signal
347
 
                self.CheckerCompleted(dbus.Int16(-1),
348
 
                                      dbus.Int64(condition),
 
338
                self.CheckerCompleted(dbus.Boolean(False),
 
339
                                      dbus.UInt16(condition),
 
340
                                      dbus.String(command))
 
341
        else:
 
342
            logger.info(u"Checker for %(name)s failed",
 
343
                        vars(self))
 
344
            if self.use_dbus:
 
345
                # Emit D-Bus signal
 
346
                self.CheckerCompleted(dbus.Boolean(False),
 
347
                                      dbus.UInt16(condition),
349
348
                                      dbus.String(command))
350
349
    
351
 
    def checked_ok(self):
 
350
    def bump_timeout(self):
352
351
        """Bump up the timeout for this client.
353
352
        This should only be called when the client has been seen,
354
353
        alive and well.
412
411
                                             (self.checker.pid,
413
412
                                              self.checker_callback,
414
413
                                              data=command))
415
 
                # The checker may have completed before the gobject
416
 
                # watch was added.  Check for this.
417
 
                pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
418
 
                if pid:
419
 
                    gobject.source_remove(self.checker_callback_tag)
420
 
                    self.checker_callback(pid, status, command)
421
414
            except OSError, error:
422
415
                logger.error(u"Failed to start subprocess: %s",
423
416
                             error)
456
449
            return now < (self.last_checked_ok + self.timeout)
457
450
    
458
451
    ## D-Bus methods & signals
459
 
    _interface = u"se.bsnet.fukt.Mandos.Client"
 
452
    _interface = u"org.mandos_system.Mandos.Client"
460
453
    
461
 
    # CheckedOK - method
462
 
    CheckedOK = dbus.service.method(_interface)(checked_ok)
463
 
    CheckedOK.__name__ = "CheckedOK"
 
454
    # BumpTimeout - method
 
455
    BumpTimeout = dbus.service.method(_interface)(bump_timeout)
 
456
    BumpTimeout.__name__ = "BumpTimeout"
464
457
    
465
458
    # CheckerCompleted - signal
466
 
    @dbus.service.signal(_interface, signature="nxs")
467
 
    def CheckerCompleted(self, exitcode, waitstatus, command):
 
459
    @dbus.service.signal(_interface, signature="bqs")
 
460
    def CheckerCompleted(self, success, condition, command):
468
461
        "D-Bus signal"
469
462
        pass
470
463
    
602
595
        != gnutls.library.constants.GNUTLS_CRT_OPENPGP):
603
596
        # ...do the normal thing
604
597
        return session.peer_certificate
605
 
    list_size = ctypes.c_uint(1)
 
598
    list_size = ctypes.c_uint()
606
599
    cert_list = (gnutls.library.functions
607
600
                 .gnutls_certificate_get_peers
608
601
                 (session._c_object, ctypes.byref(list_size)))
609
 
    if not bool(cert_list) and list_size.value != 0:
610
 
        raise gnutls.errors.GNUTLSError("error getting peer"
611
 
                                        " certificate")
612
602
    if list_size.value == 0:
613
603
        return None
614
604
    cert = cert_list[0]
683
673
        # using OpenPGP certificates.
684
674
        
685
675
        #priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
686
 
        #                     "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
687
 
        #                     "+DHE-DSS"))
 
676
        #                "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
 
677
        #                "+DHE-DSS"))
688
678
        # Use a fallback default, since this MUST be set.
689
679
        priority = self.server.settings.get("priority", "NORMAL")
690
680
        (gnutls.library.functions
698
688
            # Do not run session.bye() here: the session is not
699
689
            # established.  Just abandon the request.
700
690
            return
701
 
        logger.debug(u"Handshake succeeded")
702
691
        try:
703
692
            fpr = fingerprint(peer_certificate(session))
704
693
        except (TypeError, gnutls.errors.GNUTLSError), error:
706
695
            session.bye()
707
696
            return
708
697
        logger.debug(u"Fingerprint: %s", fpr)
709
 
        
710
698
        for c in self.server.clients:
711
699
            if c.fingerprint == fpr:
712
700
                client = c
725
713
            session.bye()
726
714
            return
727
715
        ## This won't work here, since we're in a fork.
728
 
        # client.checked_ok()
 
716
        # client.bump_timeout()
729
717
        sent_size = 0
730
718
        while sent_size < len(client.secret):
731
719
            sent = session.send(client.secret[sent_size:])
771
759
                                 u" bind to interface %s",
772
760
                                 self.settings["interface"])
773
761
                else:
774
 
                    raise
 
762
                    raise error
775
763
        # Only bind(2) the socket if we really need to.
776
764
        if self.server_address[0] or self.server_address[1]:
777
765
            if not self.server_address[0]:
798
786
 
799
787
def string_to_delta(interval):
800
788
    """Parse a string and return a datetime.timedelta
801
 
    
 
789
 
802
790
    >>> string_to_delta('7d')
803
791
    datetime.timedelta(7)
804
792
    >>> string_to_delta('60s')
953
941
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
954
942
    # Convert the SafeConfigParser object to a dict
955
943
    server_settings = server_config.defaults()
956
 
    # Use the appropriate methods on the non-string config options
957
 
    server_settings["debug"] = server_config.getboolean("DEFAULT",
958
 
                                                        "debug")
959
 
    server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
960
 
                                                           "use_dbus")
961
 
    if server_settings["port"]:
962
 
        server_settings["port"] = server_config.getint("DEFAULT",
963
 
                                                       "port")
 
944
    # Use getboolean on the boolean config options
 
945
    server_settings["debug"] = (server_config.getboolean
 
946
                                ("DEFAULT", "debug"))
 
947
    server_settings["use_dbus"] = (server_config.getboolean
 
948
                                   ("DEFAULT", "use_dbus"))
964
949
    del server_config
965
950
    
966
951
    # Override the settings from the config file with command line
1007
992
    pidfilename = "/var/run/mandos.pid"
1008
993
    try:
1009
994
        pidfile = open(pidfilename, "w")
1010
 
    except IOError:
 
995
    except IOError, error:
1011
996
        logger.error("Could not open file %r", pidfilename)
1012
997
    
1013
998
    try:
1025
1010
                uid = 65534
1026
1011
                gid = 65534
1027
1012
    try:
 
1013
        os.setuid(uid)
1028
1014
        os.setgid(gid)
1029
 
        os.setuid(uid)
1030
1015
    except OSError, error:
1031
1016
        if error[0] != errno.EPERM:
1032
1017
            raise error
1033
1018
    
1034
 
    # Enable all possible GnuTLS debugging
1035
 
    if debug:
1036
 
        # "Use a log level over 10 to enable all debugging options."
1037
 
        # - GnuTLS manual
1038
 
        gnutls.library.functions.gnutls_global_set_log_level(11)
1039
 
        
1040
 
        @gnutls.library.types.gnutls_log_func
1041
 
        def debug_gnutls(level, string):
1042
 
            logger.debug("GnuTLS: %s", string[:-1])
1043
 
        
1044
 
        (gnutls.library.functions
1045
 
         .gnutls_global_set_log_function(debug_gnutls))
1046
 
    
1047
1019
    global service
1048
1020
    service = AvahiService(name = server_settings["servicename"],
1049
1021
                           servicetype = "_mandos._tcp", )
1063
1035
                            avahi.DBUS_INTERFACE_SERVER)
1064
1036
    # End of Avahi example code
1065
1037
    if use_dbus:
1066
 
        bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
 
1038
        bus_name = dbus.service.BusName(u"org.mandos-system.Mandos",
 
1039
                                        bus)
1067
1040
    
1068
1041
    clients.update(Set(Client(name = section,
1069
1042
                              config
1123
1096
        class MandosServer(dbus.service.Object):
1124
1097
            """A D-Bus proxy object"""
1125
1098
            def __init__(self):
1126
 
                dbus.service.Object.__init__(self, bus, "/")
1127
 
            _interface = u"se.bsnet.fukt.Mandos"
 
1099
                dbus.service.Object.__init__(self, bus,
 
1100
                                             "/Mandos")
 
1101
            _interface = u"org.mandos_system.Mandos"
1128
1102
            
1129
1103
            @dbus.service.signal(_interface, signature="oa{sv}")
1130
1104
            def ClientAdded(self, objpath, properties):
1138
1112
            
1139
1113
            @dbus.service.method(_interface, out_signature="ao")
1140
1114
            def GetAllClients(self):
1141
 
                "D-Bus method"
1142
1115
                return dbus.Array(c.dbus_object_path for c in clients)
1143
1116
            
1144
1117
            @dbus.service.method(_interface, out_signature="a{oa{sv}}")
1145
1118
            def GetAllClientsWithProperties(self):
1146
 
                "D-Bus method"
1147
1119
                return dbus.Dictionary(
1148
1120
                    ((c.dbus_object_path, c.GetAllProperties())
1149
1121
                     for c in clients),
1151
1123
            
1152
1124
            @dbus.service.method(_interface, in_signature="o")
1153
1125
            def RemoveClient(self, object_path):
1154
 
                "D-Bus method"
1155
1126
                for c in clients:
1156
1127
                    if c.dbus_object_path == object_path:
1157
1128
                        clients.remove(c)
1163
1134
                        return
1164
1135
                raise KeyError
1165
1136
            
 
1137
            @dbus.service.method(_interface, in_signature="s")
 
1138
            def RemoveClientByName(self, name):
 
1139
                for c in clients:
 
1140
                    if c.name == name:
 
1141
                        clients.remove(c)
 
1142
                        # Don't signal anything except ClientRemoved
 
1143
                        c.use_dbus = False
 
1144
                        c.disable()
 
1145
                        # Emit D-Bus signal
 
1146
                        self.ClientRemoved(c.dbus_object_path, name)
 
1147
                        return
 
1148
                raise KeyError
 
1149
            
 
1150
            @dbus.service.method(_interface)
 
1151
            def Quit(self):
 
1152
                main_loop.quit()
 
1153
            
1166
1154
            del _interface
1167
1155
        
1168
1156
        mandos_server = MandosServer()
1206
1194
        sys.exit(1)
1207
1195
    except KeyboardInterrupt:
1208
1196
        if debug:
1209
 
            print >> sys.stderr
1210
 
        logger.debug("Server received KeyboardInterrupt")
1211
 
    logger.debug("Server exiting")
 
1197
            print
1212
1198
 
1213
1199
if __name__ == '__main__':
1214
1200
    main()