/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-10-12 07:27:43 UTC
  • Revision ID: teddy@fukt.bsnet.se-20081012072743-0g7o9e5mqqv4fkob
* README: Refer to man pages of usplash, splashy, and askpass-fifo.

* debian/copyright: Rewritten to conform to
  <http://wiki.debian.org/Proposals/CopyrightFormat?action=recall&rev=233>.

* mandos-keygen: Sign encrypted keys.

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