/mandos/release

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/release

« back to all changes in this revision

Viewing changes to mandos

* TODO: Updated.

Show diffs side-by-side

added added

removed removed

Lines of Context:
74
74
    try:
75
75
        from IN import SO_BINDTODEVICE
76
76
    except ImportError:
77
 
        # From /usr/include/asm/socket.h
78
 
        SO_BINDTODEVICE = 25
79
 
 
80
 
 
81
 
version = "1.0.8"
 
77
        SO_BINDTODEVICE = None
 
78
 
 
79
 
 
80
version = "1.0.11"
82
81
 
83
82
logger = logging.Logger(u'mandos')
84
83
syslogger = (logging.handlers.SysLogHandler
127
126
                  a sensible number of times
128
127
    group: D-Bus Entry Group
129
128
    server: D-Bus Server
 
129
    bus: dbus.SystemBus()
130
130
    """
131
131
    def __init__(self, interface = avahi.IF_UNSPEC, name = None,
132
132
                 servicetype = None, port = None, TXT = None,
312
312
    
313
313
    def enable(self):
314
314
        """Start this client's checker and timeout hooks"""
 
315
        if getattr(self, u"enabled", False):
 
316
            # Already enabled
 
317
            return
315
318
        self.last_enabled = datetime.datetime.utcnow()
316
319
        # Schedule a new checker to be started an 'interval' from now,
317
320
        # and every interval from then on.
478
481
    """A Client class using D-Bus
479
482
    
480
483
    Attributes:
481
 
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
 
484
    dbus_object_path: dbus.ObjectPath
 
485
    bus: dbus.SystemBus()
482
486
    """
483
487
    # dbus.service.Object doesn't use super(), so we can't either.
484
488
    
807
811
                    client = c
808
812
                    break
809
813
            else:
810
 
                ipc.write(u"NOTFOUND %s\n" % fpr)
 
814
                ipc.write(u"NOTFOUND %s %s\n"
 
815
                          % (fpr, unicode(self.client_address)))
811
816
                session.bye()
812
817
                return
813
818
            # Have to check if client.still_valid(), since it is
892
897
 
893
898
 
894
899
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
895
 
    """Like socketserver.ForkingMixIn, but also pass a pipe.
896
 
    
897
 
    Assumes a gobject.MainLoop event loop.
898
 
    """
 
900
    """Like socketserver.ForkingMixIn, but also pass a pipe."""
899
901
    def process_request(self, request, client_address):
900
902
        """Overrides and wraps the original process_request().
901
903
        
902
 
        This function creates a new pipe in self.pipe 
 
904
        This function creates a new pipe in self.pipe
903
905
        """
904
906
        self.pipe = os.pipe()
905
907
        super(ForkingMixInWithPipe,
906
908
              self).process_request(request, client_address)
907
909
        os.close(self.pipe[1])  # close write end
908
 
        # Call "handle_ipc" for both data and EOF events
909
 
        gobject.io_add_watch(self.pipe[0],
910
 
                             gobject.IO_IN | gobject.IO_HUP,
911
 
                             self.handle_ipc)
912
 
    def handle_ipc(source, condition):
 
910
        self.add_pipe(self.pipe[0])
 
911
    def add_pipe(self, pipe):
913
912
        """Dummy function; override as necessary"""
914
 
        os.close(source)
915
 
        return False
 
913
        os.close(pipe)
916
914
 
917
915
 
918
916
class IPv6_TCPServer(ForkingMixInWithPipe,
923
921
        enabled:        Boolean; whether this server is activated yet
924
922
        interface:      None or a network interface name (string)
925
923
        use_ipv6:       Boolean; to use IPv6 or not
926
 
        ----
927
 
        clients:        set of Client objects
928
 
        gnutls_priority GnuTLS priority string
929
 
        use_dbus:       Boolean; to emit D-Bus signals or not
930
924
    """
931
925
    def __init__(self, server_address, RequestHandlerClass,
932
 
                 interface=None, use_ipv6=True, clients=None,
933
 
                 gnutls_priority=None, use_dbus=True):
934
 
        self.enabled = False
 
926
                 interface=None, use_ipv6=True):
935
927
        self.interface = interface
936
928
        if use_ipv6:
937
929
            self.address_family = socket.AF_INET6
938
 
        self.clients = clients
939
 
        self.use_dbus = use_dbus
940
 
        self.gnutls_priority = gnutls_priority
941
930
        socketserver.TCPServer.__init__(self, server_address,
942
931
                                        RequestHandlerClass)
943
932
    def server_bind(self):
945
934
        to bind to an interface if one was specified, and also NOT to
946
935
        bind to an address or port if they were not specified."""
947
936
        if self.interface is not None:
948
 
            try:
949
 
                self.socket.setsockopt(socket.SOL_SOCKET,
950
 
                                       SO_BINDTODEVICE,
951
 
                                       str(self.interface + u'\0'))
952
 
            except socket.error, error:
953
 
                if error[0] == errno.EPERM:
954
 
                    logger.error(u"No permission to"
955
 
                                 u" bind to interface %s",
956
 
                                 self.interface)
957
 
                else:
958
 
                    raise
 
937
            if SO_BINDTODEVICE is None:
 
938
                logger.error(u"SO_BINDTODEVICE does not exist;"
 
939
                             u" cannot bind to interface %s",
 
940
                             self.interface)
 
941
            else:
 
942
                try:
 
943
                    self.socket.setsockopt(socket.SOL_SOCKET,
 
944
                                           SO_BINDTODEVICE,
 
945
                                           str(self.interface
 
946
                                               + u'\0'))
 
947
                except socket.error, error:
 
948
                    if error[0] == errno.EPERM:
 
949
                        logger.error(u"No permission to"
 
950
                                     u" bind to interface %s",
 
951
                                     self.interface)
 
952
                    elif error[0] == errno.ENOPROTOOPT:
 
953
                        logger.error(u"SO_BINDTODEVICE not available;"
 
954
                                     u" cannot bind to interface %s",
 
955
                                     self.interface)
 
956
                    else:
 
957
                        raise
959
958
        # Only bind(2) the socket if we really need to.
960
959
        if self.server_address[0] or self.server_address[1]:
961
960
            if not self.server_address[0]:
975
974
#                                            if_nametoindex
976
975
#                                            (self.interface))
977
976
            return socketserver.TCPServer.server_bind(self)
 
977
 
 
978
 
 
979
class MandosServer(IPv6_TCPServer):
 
980
    """Mandos server.
 
981
    
 
982
    Attributes:
 
983
        clients:        set of Client objects
 
984
        gnutls_priority GnuTLS priority string
 
985
        use_dbus:       Boolean; to emit D-Bus signals or not
 
986
        clients:        set of Client objects
 
987
        gnutls_priority GnuTLS priority string
 
988
        use_dbus:       Boolean; to emit D-Bus signals or not
 
989
    
 
990
    Assumes a gobject.MainLoop event loop.
 
991
    """
 
992
    def __init__(self, server_address, RequestHandlerClass,
 
993
                 interface=None, use_ipv6=True, clients=None,
 
994
                 gnutls_priority=None, use_dbus=True):
 
995
        self.enabled = False
 
996
        self.clients = clients
 
997
        if self.clients is None:
 
998
            self.clients = set()
 
999
        self.use_dbus = use_dbus
 
1000
        self.gnutls_priority = gnutls_priority
 
1001
        IPv6_TCPServer.__init__(self, server_address,
 
1002
                                RequestHandlerClass,
 
1003
                                interface = interface,
 
1004
                                use_ipv6 = use_ipv6)
978
1005
    def server_activate(self):
979
1006
        if self.enabled:
980
1007
            return socketserver.TCPServer.server_activate(self)
981
1008
    def enable(self):
982
1009
        self.enabled = True
 
1010
    def add_pipe(self, pipe):
 
1011
        # Call "handle_ipc" for both data and EOF events
 
1012
        gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
 
1013
                             self.handle_ipc)
983
1014
    def handle_ipc(self, source, condition, file_objects={}):
984
1015
        condition_names = {
985
1016
            gobject.IO_IN: u"IN",   # There is data to read.
1249
1280
    global mandos_dbus_service
1250
1281
    mandos_dbus_service = None
1251
1282
    
1252
 
    clients = set()
1253
 
    tcp_server = IPv6_TCPServer((server_settings[u"address"],
1254
 
                                 server_settings[u"port"]),
1255
 
                                ClientHandler,
1256
 
                                interface=
1257
 
                                server_settings[u"interface"],
1258
 
                                use_ipv6=use_ipv6,
1259
 
                                clients=clients,
1260
 
                                gnutls_priority=
1261
 
                                server_settings[u"priority"],
1262
 
                                use_dbus=use_dbus)
 
1283
    tcp_server = MandosServer((server_settings[u"address"],
 
1284
                               server_settings[u"port"]),
 
1285
                              ClientHandler,
 
1286
                              interface=server_settings[u"interface"],
 
1287
                              use_ipv6=use_ipv6,
 
1288
                              gnutls_priority=
 
1289
                              server_settings[u"priority"],
 
1290
                              use_dbus=use_dbus)
1263
1291
    pidfilename = u"/var/run/mandos.pid"
1264
1292
    try:
1265
1293
        pidfile = open(pidfilename, u"w")
1319
1347
    client_class = Client
1320
1348
    if use_dbus:
1321
1349
        client_class = functools.partial(ClientDBus, bus = bus)
1322
 
    clients.update(set(
 
1350
    tcp_server.clients.update(set(
1323
1351
            client_class(name = section,
1324
1352
                         config= dict(client_config.items(section)))
1325
1353
            for section in client_config.sections()))
1326
 
    if not clients:
 
1354
    if not tcp_server.clients:
1327
1355
        logger.warning(u"No clients defined")
1328
1356
    
1329
1357
    if debug:
1355
1383
        "Cleanup function; run on exit"
1356
1384
        service.cleanup()
1357
1385
        
1358
 
        while clients:
1359
 
            client = clients.pop()
 
1386
        while tcp_server.clients:
 
1387
            client = tcp_server.clients.pop()
1360
1388
            client.disable_hook = None
1361
1389
            client.disable()
1362
1390
    
1392
1420
            @dbus.service.method(_interface, out_signature=u"ao")
1393
1421
            def GetAllClients(self):
1394
1422
                "D-Bus method"
1395
 
                return dbus.Array(c.dbus_object_path for c in clients)
 
1423
                return dbus.Array(c.dbus_object_path
 
1424
                                  for c in tcp_server.clients)
1396
1425
            
1397
1426
            @dbus.service.method(_interface,
1398
1427
                                 out_signature=u"a{oa{sv}}")
1400
1429
                "D-Bus method"
1401
1430
                return dbus.Dictionary(
1402
1431
                    ((c.dbus_object_path, c.GetAllProperties())
1403
 
                     for c in clients),
 
1432
                     for c in tcp_server.clients),
1404
1433
                    signature=u"oa{sv}")
1405
1434
            
1406
1435
            @dbus.service.method(_interface, in_signature=u"o")
1407
1436
            def RemoveClient(self, object_path):
1408
1437
                "D-Bus method"
1409
 
                for c in clients:
 
1438
                for c in tcp_server.clients:
1410
1439
                    if c.dbus_object_path == object_path:
1411
 
                        clients.remove(c)
 
1440
                        tcp_server.clients.remove(c)
1412
1441
                        c.remove_from_connection()
1413
1442
                        # Don't signal anything except ClientRemoved
1414
1443
                        c.disable(signal=False)
1421
1450
        
1422
1451
        mandos_dbus_service = MandosDBusService()
1423
1452
    
1424
 
    for client in clients:
 
1453
    for client in tcp_server.clients:
1425
1454
        if use_dbus:
1426
1455
            # Emit D-Bus signal
1427
1456
            mandos_dbus_service.ClientAdded(client.dbus_object_path,