RSS

(root)/trunk : 13

Björn Påhlsson
2008-07-20 04:52:20
Revision ID: belorn@braxen-20080720025220-r5u0388uy9iu23h6
Added following support: Pluginbased client handler rewritten Mandos client        Avahi instead of udp server discovery        openpgp encrypted key support Passprompt stand alone application for direct console input Added logging for Mandos server

collapse all collapse all

added added

removed removed

1
CXXFLAGS=-Wall -W -g
1
CFLAGS="-Wall -std=gnu99"
2
LDFLAGS=-lgnutls
2
LDFLAGS=-lgnutls
3
 
3
 
4
all: client server
4
all: plugbasedclient
5
 
5
 
6
clean:
6
clean:
7
        rm -f server client client_debug
7
        rm -f plugbasedclient
8
 
8
 
9
client_debug: client
9
client_debug: client
10
        mv -f client client.tmp
10
        mv -f client client.tmp
1
# Example
1
# Example
2
[foo]
2
#[foo]
3
fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
3
#fingerprint = 3e393aeaefb84c7e89e2f547b3a107558fca3a27
4
secfile = openpgp/secret.txt.asc
4
#secfile = openpgp/secret.txt.asc
5
fqdn = foo.example.org
5
#fqdn = foo.example.org
6
checker = echo %%(fqdn)s >&2; false
6
#checker = echo %%(fqdn)s >&2; false
7
 
7
#
8
[braxen_client]
8
[braxen_client]
9
fingerprint =  7788 2722 5BA7 DE53 9C5A  7CFA 59CF F7CD BD9A 5920
9
fingerprint =  7788 2722 5BA7 DE53 9C5A  7CFA 59CF F7CD BD9A 5920
10
secret =
10
secret =
28
from dbus.mainloop.glib import DBusGMainLoop
28
from dbus.mainloop.glib import DBusGMainLoop
29
import ctypes
29
import ctypes
30
 
30
 
 
 
31
import logging
 
 
32
import logging.handlers
 
 
33
 
 
 
34
# logghandler.setFormatter(logging.Formatter('%(levelname)s %(message)s')
 
 
35
 
 
 
36
logger = logging.Logger('mandos')
 
 
37
logger.addHandler(logging.handlers.SysLogHandler(facility = logging.handlers.SysLogHandler.LOG_DAEMON))
 
 
38
 
31
# This variable is used to optionally bind to a specified interface.
39
# This variable is used to optionally bind to a specified interface.
32
# It is a global variable to fit in with the other variables from the
40
# It is a global variable to fit in with the other variables from the
33
# Avahi server example code.
41
# Avahi server example code.
149
        """Stop this client.
157
        """Stop this client.
150
        The possibility that this client might be restarted is left
158
        The possibility that this client might be restarted is left
151
        open, but not currently used."""
159
        open, but not currently used."""
152
        if debug:
160
        logger.debug(u"Stopping client %s", self.name)
153
            sys.stderr.write(u"Stopping client %s\n" % self.name)
 
 
154
        self.secret = None
161
        self.secret = None
155
        if self.stop_initiator_tag:
162
        if self.stop_initiator_tag:
156
            gobject.source_remove(self.stop_initiator_tag)
163
            gobject.source_remove(self.stop_initiator_tag)
179
        now = datetime.datetime.now()
186
        now = datetime.datetime.now()
180
        if os.WIFEXITED(condition) \
187
        if os.WIFEXITED(condition) \
181
               and (os.WEXITSTATUS(condition) == 0):
188
               and (os.WEXITSTATUS(condition) == 0):
182
            if debug:
189
            logger.debug(u"Checker for %(name)s succeeded",
183
                sys.stderr.write(u"Checker for %(name)s succeeded\n"
190
                         vars(self))
184
                                 % vars(self))
 
 
185
            self.last_seen = now
191
            self.last_seen = now
186
            gobject.source_remove(self.stop_initiator_tag)
192
            gobject.source_remove(self.stop_initiator_tag)
187
            self.stop_initiator_tag = gobject.timeout_add\
193
            self.stop_initiator_tag = gobject.timeout_add\
188
                                      (self._timeout_milliseconds,
194
                                      (self._timeout_milliseconds,
189
                                       self.stop)
195
                                       self.stop)
190
        elif debug:
196
        if not os.WIFEXITED(condition):
191
            if not os.WIFEXITED(condition):
197
            logger.warning(u"Checker for %(name)s crashed?",
192
                sys.stderr.write(u"Checker for %(name)s crashed?\n"
198
                           vars(self))
193
                                 % vars(self))
199
        else:
194
            else:
200
            logger.debug(u"Checker for %(name)s failed",
195
                sys.stderr.write(u"Checker for %(name)s failed\n"
201
                         vars(self))
196
                                 % vars(self))
202
            self.checker = None
197
        self.checker = None
 
 
198
        self.checker_callback_tag = None
203
        self.checker_callback_tag = None
199
    def start_checker(self):
204
    def start_checker(self):
200
        """Start a new checker subprocess if one is not running.
205
        """Start a new checker subprocess if one is not running.
201
        If a checker already exists, leave it running and do
206
        If a checker already exists, leave it running and do
202
        nothing."""
207
        nothing."""
203
        if self.checker is None:
208
        if self.checker is None:
204
            if debug:
209
            logger.debug(u"Starting checker for %s",
205
                sys.stderr.write(u"Starting checker for %s\n"
210
                         self.name)
206
                                 % self.name)
 
 
207
            try:
211
            try:
208
                command = self.check_command % self.fqdn
212
                command = self.check_command % self.fqdn
209
            except TypeError:
213
            except TypeError:
210
                escaped_attrs = dict((key, re.escape(str(val)))
214
                escaped_attrs = dict((key, re.escape(str(val)))
211
                                     for key, val in
215
                                     for key, val in
212
                                     vars(self).iteritems())
216
                                     vars(self).iteritems())
213
                command = self.check_command % escaped_attrs
217
                try:
 
 
218
                    command = self.check_command % escaped_attrs
 
 
219
                except TypeError, error:
 
 
220
                    logger.critical(u'Could not format string "%s": %s',
 
 
221
                                    self.check_command, error)
 
 
222
                    return True # Try again later
214
            try:
223
            try:
215
                self.checker = subprocess.\
224
                self.checker = subprocess.\
216
                               Popen(command,
225
                               Popen(command,
222
                                                            self.\
231
                                                            self.\
223
                                                            checker_callback)
232
                                                            checker_callback)
224
            except subprocess.OSError, error:
233
            except subprocess.OSError, error:
225
                sys.stderr.write(u"Failed to start subprocess: %s\n"
234
                logger.error(u"Failed to start subprocess: %s",
226
                                 % error)
235
                             error)
227
        # Re-run this periodically if run by gobject.timeout_add
236
        # Re-run this periodically if run by gobject.timeout_add
228
        return True
237
        return True
229
    def stop_checker(self):
238
    def stop_checker(self):
298
    Note: This will run in its own forked process."""
307
    Note: This will run in its own forked process."""
299
    
308
    
300
    def handle(self):
309
    def handle(self):
301
        if debug:
310
        logger.debug(u"TCP connection from: %s",
302
            sys.stderr.write(u"TCP request came\n")
311
                     unicode(self.client_address))
303
            sys.stderr.write(u"Request: %s\n" % self.request)
 
 
304
            sys.stderr.write(u"Client Address: %s\n"
 
 
305
                             % unicode(self.client_address))
 
 
306
            sys.stderr.write(u"Server: %s\n" % self.server)
 
 
307
        session = gnutls.connection.ClientSession(self.request,
312
        session = gnutls.connection.ClientSession(self.request,
308
                                                  gnutls.connection.\
313
                                                  gnutls.connection.\
309
                                                  X509Credentials())
314
                                                  X509Credentials())
319
        try:
324
        try:
320
            session.handshake()
325
            session.handshake()
321
        except gnutls.errors.GNUTLSError, error:
326
        except gnutls.errors.GNUTLSError, error:
322
            if debug:
327
            logger.debug(u"Handshake failed: %s", error)
323
                sys.stderr.write(u"Handshake failed: %s\n" % error)
 
 
324
            # Do not run session.bye() here: the session is not
328
            # Do not run session.bye() here: the session is not
325
            # established.  Just abandon the request.
329
            # established.  Just abandon the request.
326
            return
330
            return
327
        try:
331
        try:
328
            fpr = fingerprint(peer_certificate(session))
332
            fpr = fingerprint(peer_certificate(session))
329
        except (TypeError, gnutls.errors.GNUTLSError), error:
333
        except (TypeError, gnutls.errors.GNUTLSError), error:
330
            if debug:
334
            logger.debug(u"Bad certificate: %s", error)
331
                sys.stderr.write(u"Bad certificate: %s\n" % error)
 
 
332
            session.bye()
335
            session.bye()
333
            return
336
            return
334
        if debug:
337
        logger.debug(u"Fingerprint: %s", fpr)
335
            sys.stderr.write(u"Fingerprint: %s\n" % fpr)
 
 
336
        client = None
338
        client = None
337
        for c in clients:
339
        for c in clients:
338
            if c.fingerprint == fpr:
340
            if c.fingerprint == fpr:
342
        # that the client timed out while establishing the GnuTLS
344
        # that the client timed out while establishing the GnuTLS
343
        # session.
345
        # session.
344
        if (not client) or (not client.still_valid()):
346
        if (not client) or (not client.still_valid()):
345
            if debug:
347
            if client:
346
                if client:
348
                logger.debug(u"Client %(name)s is invalid",
347
                    sys.stderr.write(u"Client %(name)s is invalid\n"
349
                             vars(client))
348
                                     % vars(client))
350
            else:
349
                else:
351
                logger.debug(u"Client not found for fingerprint: %s",
350
                    sys.stderr.write(u"Client not found for "
352
                             fpr)
351
                                     u"fingerprint: %s\n" % fpr)
 
 
352
            session.bye()
353
            session.bye()
353
            return
354
            return
354
        sent_size = 0
355
        sent_size = 0
355
        while sent_size < len(client.secret):
356
        while sent_size < len(client.secret):
356
            sent = session.send(client.secret[sent_size:])
357
            sent = session.send(client.secret[sent_size:])
357
            if debug:
358
            logger.debug(u"Sent: %d, remaining: %d",
358
                sys.stderr.write(u"Sent: %d, remaining: %d\n"
359
                         sent, len(client.secret)
359
                                 % (sent, len(client.secret)
360
                         - (sent_size + sent))
360
                                    - (sent_size + sent)))
 
 
361
            sent_size += sent
361
            sent_size += sent
362
        session.bye()
362
        session.bye()
363
 
363
 
391
                                       self.options.interface)
391
                                       self.options.interface)
392
            except socket.error, error:
392
            except socket.error, error:
393
                if error[0] == errno.EPERM:
393
                if error[0] == errno.EPERM:
394
                    sys.stderr.write(u"Warning: No permission to" \
394
                    logger.warning(u"No permission to"
395
                                     u" bind to interface %s\n"
395
                                   u" bind to interface %s",
396
                                     % self.options.interface)
396
                                   self.options.interface)
397
                else:
397
                else:
398
                    raise error
398
                    raise error
399
        # Only bind(2) the socket if we really need to.
399
        # Only bind(2) the socket if we really need to.
453
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
453
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
454
        group.connect_to_signal('StateChanged',
454
        group.connect_to_signal('StateChanged',
455
                                entry_group_state_changed)
455
                                entry_group_state_changed)
456
    if debug:
456
    logger.debug(u"Adding service '%s' of type '%s' ...",
457
        sys.stderr.write(u"Adding service '%s' of type '%s' ...\n"
457
                 serviceName, serviceType)
458
                         % (serviceName, serviceType))
 
 
459
    
458
    
460
    group.AddService(
459
    group.AddService(
461
            serviceInterface,           # interface
460
            serviceInterface,           # interface
479
def server_state_changed(state):
478
def server_state_changed(state):
480
    """From the Avahi server example code"""
479
    """From the Avahi server example code"""
481
    if state == avahi.SERVER_COLLISION:
480
    if state == avahi.SERVER_COLLISION:
482
        sys.stderr.write(u"WARNING: Server name collision\n")
481
        logger.warning(u"Server name collision")
483
        remove_service()
482
        remove_service()
484
    elif state == avahi.SERVER_RUNNING:
483
    elif state == avahi.SERVER_RUNNING:
485
        add_service()
484
        add_service()
489
    """From the Avahi server example code"""
488
    """From the Avahi server example code"""
490
    global serviceName, server, rename_count
489
    global serviceName, server, rename_count
491
    
490
    
492
    if debug:
491
    logger.debug(u"state change: %i", state)
493
        sys.stderr.write(u"state change: %i\n" % state)
 
 
494
    
492
    
495
    if state == avahi.ENTRY_GROUP_ESTABLISHED:
493
    if state == avahi.ENTRY_GROUP_ESTABLISHED:
496
        if debug:
494
        logger.debug(u"Service established.")
497
            sys.stderr.write(u"Service established.\n")
 
 
498
    elif state == avahi.ENTRY_GROUP_COLLISION:
495
    elif state == avahi.ENTRY_GROUP_COLLISION:
499
        
496
        
500
        rename_count = rename_count - 1
497
        rename_count = rename_count - 1
501
        if rename_count > 0:
498
        if rename_count > 0:
502
            name = server.GetAlternativeServiceName(name)
499
            name = server.GetAlternativeServiceName(name)
503
            sys.stderr.write(u"WARNING: Service name collision, "
500
            logger.warning(u"Service name collision, "
504
                             u"changing name to '%s' ...\n" % name)
501
                           u"changing name to '%s' ...", name)
505
            remove_service()
502
            remove_service()
506
            add_service()
503
            add_service()
507
            
504
            
508
        else:
505
        else:
509
            sys.stderr.write(u"ERROR: No suitable service name found "
506
            logger.error(u"No suitable service name found "
510
                             u"after %i retries, exiting.\n"
507
                         u"after %i retries, exiting.",
511
                             % n_rename)
508
                         n_rename)
512
            main_loop.quit()
509
            main_loop.quit()
513
    elif state == avahi.ENTRY_GROUP_FAILURE:
510
    elif state == avahi.ENTRY_GROUP_FAILURE:
514
        sys.stderr.write(u"Error in group state changed %s\n"
511
        logger.error(u"Error in group state changed %s",
515
                         % unicode(error))
512
                     unicode(error))
516
        main_loop.quit()
513
        main_loop.quit()
517
        return
514
        return
518
 
515
 
603
    def remove_from_clients(client):
600
    def remove_from_clients(client):
604
        clients.remove(client)
601
        clients.remove(client)
605
        if not clients:
602
        if not clients:
606
            if debug:
603
            logger.debug(u"No clients left, exiting")
607
                sys.stderr.write(u"No clients left, exiting\n")
 
 
608
            main_loop.quit()
604
            main_loop.quit()
609
    
605
    
610
    clients.update(Set(Client(name=section, options=options,
606
    clients.update(Set(Client(name=section, options=options,
621
                                clients=clients)
617
                                clients=clients)
622
    # Find out what random port we got
618
    # Find out what random port we got
623
    servicePort = tcp_server.socket.getsockname()[1]
619
    servicePort = tcp_server.socket.getsockname()[1]
624
    if debug:
620
    logger.debug(u"Now listening on port %d", servicePort)
625
        sys.stderr.write(u"Now listening on port %d\n" % servicePort)
 
 
626
    
621
    
627
    if options.interface is not None:
622
    if options.interface is not None:
628
        serviceInterface = if_nametoindex(options.interface)
623
        serviceInterface = if_nametoindex(options.interface)

Loggerhead is a web-based interface for Bazaar branches