/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-30 07:23:39 UTC
  • Revision ID: teddy@fukt.bsnet.se-20080930072339-jn15gyrtfpdk2dhx
* .bzrignore: Added "man" directory (created by "make install-html").

* Makefile: Add "common.ent" dependency to all manual pages.
  (htmldir, version, SED): New variables.
  (CFLAGS): Add -D option to define VERSION to $(version).
  (MANPOST, HTMLPOST): Use $(SED).
  (PROGS): Use $(CPROGS)
  (CPROGS): New; C-only programs.
  (objects): Use $(CPROGS).
  (common.ent, mandos, mandos-keygen): New targets; update version
                                       number to $(version).
  (clean): Use $(CPROGS).
  (check): Depend on "all".
  (install-html): Install to $(htmldir).

* common.ent: New file with "version" entity.

* mandos-clients.conf.xml: Use "common.ent".
* mandos-keygen.xml: - '' -
* mandos.conf.xml: - '' -
* mandos.xml: - '' -
* plugin-runner.xml: - '' -
* plugins.d/mandos-client.xml: - '' -
* plugins.d/password-prompt.xml: - '' -

* plugin-runner.c (argp_program_version): Use VERSION.
* plugins.d/mandos-client.c (argp_program_version): - '' -
* plugins.d/password-prompt.c (argp_program_version): - '' -

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