/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 server.py

  • Committer: Björn Påhlsson
  • Date: 2008-07-20 02:52:20 UTC
  • 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

Show diffs side-by-side

added added

removed removed

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