/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-13 15:36:18 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080913153618-atp386q2bqj0ku99
* Makefile (install-client-nokey): Do "&&" instead of ";" to catch
                                   errors.

* README: Kill the straight quotes.  Add copyright notice.

* overview.xml: Improved wording.

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
 
version = "1.0.2"
 
66
version = "1.0"
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__()
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(os.path.expanduser(os.path.expandvars
244
 
                                              (config["secfile"])))
245
 
            self.secret = secfile.read()
246
 
            secfile.close()
 
240
            sf = open(config["secfile"])
 
241
            self.secret = sf.read()
 
242
            sf.close()
247
243
        else:
248
244
            raise TypeError(u"No secret or secfile for client %s"
249
245
                            % self.name)
419
415
                    (crt, ctypes.byref(datum),
420
416
                     gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
421
417
    # Verify the self signature in the key
422
 
    crtverify = ctypes.c_uint()
 
418
    crtverify = ctypes.c_uint();
423
419
    gnutls.library.functions.gnutls_openpgp_crt_verify_self\
424
420
        (crt, 0, ctypes.byref(crtverify))
425
421
    if crtverify.value != 0:
426
422
        gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
427
423
        raise gnutls.errors.CertificateSecurityError("Verify failed")
428
424
    # New buffer for the fingerprint
429
 
    buf = ctypes.create_string_buffer(20)
430
 
    buf_len = ctypes.c_size_t()
 
425
    buffer = ctypes.create_string_buffer(20)
 
426
    buffer_length = ctypes.c_size_t()
431
427
    # Get the fingerprint from the certificate into the buffer
432
428
    gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint\
433
 
        (crt, ctypes.byref(buf), ctypes.byref(buf_len))
 
429
        (crt, ctypes.byref(buffer), ctypes.byref(buffer_length))
434
430
    # Deinit the certificate
435
431
    gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
436
432
    # Convert the buffer to a Python bytestring
437
 
    fpr = ctypes.string_at(buf, buf_len.value)
 
433
    fpr = ctypes.string_at(buffer, buffer_length.value)
438
434
    # Convert the bytestring to hexadecimal notation
439
435
    hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
440
436
    return hex_fpr
441
437
 
442
438
 
443
 
class TCP_handler(SocketServer.BaseRequestHandler, object):
 
439
class tcp_handler(SocketServer.BaseRequestHandler, object):
444
440
    """A TCP request handler class.
445
441
    Instantiated by IPv6_TCPServer for each request to handle it.
446
442
    Note: This will run in its own forked process."""
473
469
        if self.server.settings["priority"]:
474
470
            priority = self.server.settings["priority"]
475
471
        gnutls.library.functions.gnutls_priority_set_direct\
476
 
            (session._c_object, priority, None)
 
472
            (session._c_object, priority, None);
477
473
        
478
474
        try:
479
475
            session.handshake()
533
529
            self.clients = kwargs["clients"]
534
530
            del kwargs["clients"]
535
531
        self.enabled = False
536
 
        super(IPv6_TCPServer, self).__init__(*args, **kwargs)
 
532
        return super(type(self), self).__init__(*args, **kwargs)
537
533
    def server_bind(self):
538
534
        """This overrides the normal server_bind() function
539
535
        to bind to an interface if one was specified, and also NOT to
568
564
#                                            if_nametoindex
569
565
#                                            (self.settings
570
566
#                                             ["interface"]))
571
 
            return super(IPv6_TCPServer, self).server_bind()
 
567
            return super(type(self), self).server_bind()
572
568
    def server_activate(self):
573
569
        if self.enabled:
574
 
            return super(IPv6_TCPServer, self).server_activate()
 
570
            return super(type(self), self).server_activate()
575
571
    def enable(self):
576
572
        self.enabled = True
577
573
 
595
591
    timevalue = datetime.timedelta(0)
596
592
    for s in interval.split():
597
593
        try:
598
 
            suffix = unicode(s[-1])
599
 
            value = int(s[:-1])
 
594
            suffix=unicode(s[-1])
 
595
            value=int(s[:-1])
600
596
            if suffix == u"d":
601
597
                delta = datetime.timedelta(value)
602
598
            elif suffix == u"s":
642
638
    """Call the C function if_nametoindex(), or equivalent"""
643
639
    global if_nametoindex
644
640
    try:
 
641
        if "ctypes.util" not in sys.modules:
 
642
            import ctypes.util
645
643
        if_nametoindex = ctypes.cdll.LoadLibrary\
646
644
            (ctypes.util.find_library("c")).if_nametoindex
647
645
    except (OSError, AttributeError):
685
683
 
686
684
 
687
685
def main():
 
686
    global main_loop_started
 
687
    main_loop_started = False
 
688
    
688
689
    parser = OptionParser(version = "%%prog %s" % version)
689
690
    parser.add_option("-i", "--interface", type="string",
690
691
                      metavar="IF", help="Bind to interface IF")
705
706
                      default="/etc/mandos", metavar="DIR",
706
707
                      help="Directory to search for configuration"
707
708
                      " files")
708
 
    options = parser.parse_args()[0]
 
709
    (options, args) = parser.parse_args()
709
710
    
710
711
    if options.check:
711
712
        import doctest
768
769
    clients = Set()
769
770
    tcp_server = IPv6_TCPServer((server_settings["address"],
770
771
                                 server_settings["port"]),
771
 
                                TCP_handler,
 
772
                                tcp_handler,
772
773
                                settings=server_settings,
773
774
                                clients=clients)
774
775
    pidfilename = "/var/run/mandos.pid"
802
803
    
803
804
    global service
804
805
    service = AvahiService(name = server_settings["servicename"],
805
 
                           servicetype = "_mandos._tcp", )
 
806
                           type = "_mandos._tcp", );
806
807
    if server_settings["interface"]:
807
808
        service.interface = if_nametoindex\
808
809
                            (server_settings["interface"])
851
852
        pidfile.write(str(pid) + "\n")
852
853
        pidfile.close()
853
854
        del pidfile
854
 
    except IOError:
 
855
    except IOError, err:
855
856
        logger.error(u"Could not write to file %r with PID %d",
856
857
                     pidfilename, pid)
857
858
    except NameError:
909
910
                             (*args[2:], **kwargs) or True)
910
911
        
911
912
        logger.debug(u"Starting main loop")
 
913
        main_loop_started = True
912
914
        main_loop.run()
913
915
    except AvahiError, error:
914
916
        logger.critical(u"AvahiError: %s" + unicode(error))