/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: 2008-09-21 13:42:34 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080921134234-jo8p4rwtm50yb4xj
* clients.conf ([bar]/secfile): Do not imply armored format.

* debian/control: Build-Depend on pkg-config.

* debian/mandos.prerm (remove): Bug fix; check for
                                "/etc/init.d/mandos", not
                                "/etc/init.d/ssh".

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
# and some lines in "main".
12
12
13
13
# Everything else is
14
 
# Copyright © 2008 Teddy Hogeborn & Björn Påhlsson
 
14
# Copyright © 2007-2008 Teddy Hogeborn & Björn Påhlsson
15
15
16
16
# This program is free software: you can redistribute it and/or modify
17
17
# it under the terms of the GNU General Public License as published by
34
34
 
35
35
import SocketServer
36
36
import socket
 
37
import select
37
38
from optparse import OptionParser
38
39
import datetime
39
40
import errno
61
62
import avahi
62
63
from dbus.mainloop.glib import DBusGMainLoop
63
64
import ctypes
64
 
import ctypes.util
65
65
 
66
66
version = "1.0"
67
67
 
81
81
class AvahiError(Exception):
82
82
    def __init__(self, value):
83
83
        self.value = value
84
 
        super(AvahiError, self).__init__()
85
84
    def __str__(self):
86
85
        return repr(self.value)
87
86
 
109
108
                  a sensible number of times
110
109
    """
111
110
    def __init__(self, interface = avahi.IF_UNSPEC, name = None,
112
 
                 servicetype = None, port = None, TXT = None, domain = "",
 
111
                 type = None, port = None, TXT = None, domain = "",
113
112
                 host = "", max_renames = 32768):
114
113
        self.interface = interface
115
114
        self.name = name
116
 
        self.type = servicetype
 
115
        self.type = type
117
116
        self.port = port
118
117
        if TXT is None:
119
118
            self.TXT = []
128
127
        if self.rename_count >= self.max_renames:
129
128
            logger.critical(u"No suitable Zeroconf service name found"
130
129
                            u" after %i retries, exiting.",
131
 
                            self.rename_count)
 
130
                            rename_count)
132
131
            raise AvahiServiceError("Too many renames")
133
132
        self.name = server.GetAlternativeServiceName(self.name)
134
133
        logger.info(u"Changing Zeroconf service name to %r ...",
223
222
    interval = property(lambda self: self._interval,
224
223
                        _set_interval)
225
224
    del _set_interval
226
 
    def __init__(self, name = None, stop_hook=None, config=None):
 
225
    def __init__(self, name = None, stop_hook=None, config={}):
227
226
        """Note: the 'checker' key in 'config' sets the
228
227
        'checker_command' attribute and *not* the 'checker'
229
228
        attribute."""
230
 
        if config is None:
231
 
            config = {}
232
229
        self.name = name
233
230
        logger.debug(u"Creating client %r", self.name)
234
231
        # Uppercase and remove spaces from fingerprint for later
240
237
        if "secret" in config:
241
238
            self.secret = config["secret"].decode(u"base64")
242
239
        elif "secfile" in config:
243
 
            secfile = open(config["secfile"])
244
 
            self.secret = secfile.read()
245
 
            secfile.close()
 
240
            sf = open(config["secfile"])
 
241
            self.secret = sf.read()
 
242
            sf.close()
246
243
        else:
247
244
            raise TypeError(u"No secret or secfile for client %s"
248
245
                            % self.name)
418
415
                    (crt, ctypes.byref(datum),
419
416
                     gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
420
417
    # Verify the self signature in the key
421
 
    crtverify = ctypes.c_uint()
 
418
    crtverify = ctypes.c_uint();
422
419
    gnutls.library.functions.gnutls_openpgp_crt_verify_self\
423
420
        (crt, 0, ctypes.byref(crtverify))
424
421
    if crtverify.value != 0:
425
422
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
426
423
        raise gnutls.errors.CertificateSecurityError("Verify failed")
427
424
    # New buffer for the fingerprint
428
 
    buf = ctypes.create_string_buffer(20)
429
 
    buf_len = ctypes.c_size_t()
 
425
    buffer = ctypes.create_string_buffer(20)
 
426
    buffer_length = ctypes.c_size_t()
430
427
    # Get the fingerprint from the certificate into the buffer
431
428
    gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint\
432
 
        (crt, ctypes.byref(buf), ctypes.byref(buf_len))
 
429
        (crt, ctypes.byref(buffer), ctypes.byref(buffer_length))
433
430
    # Deinit the certificate
434
431
    gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
435
432
    # Convert the buffer to a Python bytestring
436
 
    fpr = ctypes.string_at(buf, buf_len.value)
 
433
    fpr = ctypes.string_at(buffer, buffer_length.value)
437
434
    # Convert the bytestring to hexadecimal notation
438
435
    hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
439
436
    return hex_fpr
440
437
 
441
438
 
442
 
class TCP_handler(SocketServer.BaseRequestHandler, object):
 
439
class tcp_handler(SocketServer.BaseRequestHandler, object):
443
440
    """A TCP request handler class.
444
441
    Instantiated by IPv6_TCPServer for each request to handle it.
445
442
    Note: This will run in its own forked process."""
472
469
        if self.server.settings["priority"]:
473
470
            priority = self.server.settings["priority"]
474
471
        gnutls.library.functions.gnutls_priority_set_direct\
475
 
            (session._c_object, priority, None)
 
472
            (session._c_object, priority, None);
476
473
        
477
474
        try:
478
475
            session.handshake()
532
529
            self.clients = kwargs["clients"]
533
530
            del kwargs["clients"]
534
531
        self.enabled = False
535
 
        super(IPv6_TCPServer, self).__init__(*args, **kwargs)
 
532
        return super(type(self), self).__init__(*args, **kwargs)
536
533
    def server_bind(self):
537
534
        """This overrides the normal server_bind() function
538
535
        to bind to an interface if one was specified, and also NOT to
567
564
#                                            if_nametoindex
568
565
#                                            (self.settings
569
566
#                                             ["interface"]))
570
 
            return super(IPv6_TCPServer, self).server_bind()
 
567
            return super(type(self), self).server_bind()
571
568
    def server_activate(self):
572
569
        if self.enabled:
573
 
            return super(IPv6_TCPServer, self).server_activate()
 
570
            return super(type(self), self).server_activate()
574
571
    def enable(self):
575
572
        self.enabled = True
576
573
 
594
591
    timevalue = datetime.timedelta(0)
595
592
    for s in interval.split():
596
593
        try:
597
 
            suffix = unicode(s[-1])
598
 
            value = int(s[:-1])
 
594
            suffix=unicode(s[-1])
 
595
            value=int(s[:-1])
599
596
            if suffix == u"d":
600
597
                delta = datetime.timedelta(value)
601
598
            elif suffix == u"s":
641
638
    """Call the C function if_nametoindex(), or equivalent"""
642
639
    global if_nametoindex
643
640
    try:
 
641
        if "ctypes.util" not in sys.modules:
 
642
            import ctypes.util
644
643
        if_nametoindex = ctypes.cdll.LoadLibrary\
645
644
            (ctypes.util.find_library("c")).if_nametoindex
646
645
    except (OSError, AttributeError):
684
683
 
685
684
 
686
685
def main():
 
686
    global main_loop_started
 
687
    main_loop_started = False
 
688
    
687
689
    parser = OptionParser(version = "%%prog %s" % version)
688
690
    parser.add_option("-i", "--interface", type="string",
689
691
                      metavar="IF", help="Bind to interface IF")
704
706
                      default="/etc/mandos", metavar="DIR",
705
707
                      help="Directory to search for configuration"
706
708
                      " files")
707
 
    options = parser.parse_args()[0]
 
709
    (options, args) = parser.parse_args()
708
710
    
709
711
    if options.check:
710
712
        import doctest
767
769
    clients = Set()
768
770
    tcp_server = IPv6_TCPServer((server_settings["address"],
769
771
                                 server_settings["port"]),
770
 
                                TCP_handler,
 
772
                                tcp_handler,
771
773
                                settings=server_settings,
772
774
                                clients=clients)
773
775
    pidfilename = "/var/run/mandos.pid"
801
803
    
802
804
    global service
803
805
    service = AvahiService(name = server_settings["servicename"],
804
 
                           servicetype = "_mandos._tcp", )
 
806
                           type = "_mandos._tcp", );
805
807
    if server_settings["interface"]:
806
808
        service.interface = if_nametoindex\
807
809
                            (server_settings["interface"])
850
852
        pidfile.write(str(pid) + "\n")
851
853
        pidfile.close()
852
854
        del pidfile
853
 
    except IOError:
 
855
    except IOError, err:
854
856
        logger.error(u"Could not write to file %r with PID %d",
855
857
                     pidfilename, pid)
856
858
    except NameError:
908
910
                             (*args[2:], **kwargs) or True)
909
911
        
910
912
        logger.debug(u"Starting main loop")
 
913
        main_loop_started = True
911
914
        main_loop.run()
912
915
    except AvahiError, error:
913
916
        logger.critical(u"AvahiError: %s" + unicode(error))