/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: 2009-04-16 01:15:14 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090416011514-jr7gwcqbf0s422i3
* mandos (main): Use builtin "set" type instead of "sets.Set".

Show diffs side-by-side

added added

removed removed

Lines of Context:
6
6
# This program is partly derived from an example program for an Avahi
7
7
# service publisher, downloaded from
8
8
# <http://avahi.org/wiki/PythonPublishExample>.  This includes the
9
 
# methods "add", "remove", "server_state_changed",
10
 
# "entry_group_state_changed", "cleanup", and "activate" in the
11
 
# "AvahiService" class, and some lines in "main".
 
9
# methods "add" and "remove" in the "AvahiService" class, the
 
10
# "server_state_changed" and "entry_group_state_changed" functions,
 
11
# and some lines in "main".
12
12
13
13
# Everything else is
14
14
# Copyright © 2008,2009 Teddy Hogeborn
33
33
 
34
34
from __future__ import division, with_statement, absolute_import
35
35
 
36
 
import SocketServer as socketserver
 
36
import SocketServer
37
37
import socket
38
38
import optparse
39
39
import datetime
44
44
import gnutls.library.functions
45
45
import gnutls.library.constants
46
46
import gnutls.library.types
47
 
import ConfigParser as configparser
 
47
import ConfigParser
48
48
import sys
49
49
import re
50
50
import os
58
58
from contextlib import closing
59
59
import struct
60
60
import fcntl
61
 
import functools
62
61
 
63
62
import dbus
64
63
import dbus.service
74
73
    try:
75
74
        from IN import SO_BINDTODEVICE
76
75
    except ImportError:
77
 
        SO_BINDTODEVICE = None
 
76
        # From /usr/include/asm/socket.h
 
77
        SO_BINDTODEVICE = 25
78
78
 
79
79
 
80
80
version = "1.0.8"
124
124
    max_renames: integer; maximum number of renames
125
125
    rename_count: integer; counter so we only rename after collisions
126
126
                  a sensible number of times
127
 
    group: D-Bus Entry Group
128
 
    server: D-Bus Server
129
 
    bus: dbus.SystemBus()
130
127
    """
131
128
    def __init__(self, interface = avahi.IF_UNSPEC, name = None,
132
129
                 servicetype = None, port = None, TXT = None,
133
130
                 domain = u"", host = u"", max_renames = 32768,
134
 
                 protocol = avahi.PROTO_UNSPEC, bus = None):
 
131
                 protocol = avahi.PROTO_UNSPEC):
135
132
        self.interface = interface
136
133
        self.name = name
137
134
        self.type = servicetype
142
139
        self.rename_count = 0
143
140
        self.max_renames = max_renames
144
141
        self.protocol = protocol
145
 
        self.group = None       # our entry group
146
 
        self.server = None
147
 
        self.bus = bus
148
142
    def rename(self):
149
143
        """Derived from the Avahi example code"""
150
144
        if self.rename_count >= self.max_renames:
152
146
                            u" after %i retries, exiting.",
153
147
                            self.rename_count)
154
148
            raise AvahiServiceError(u"Too many renames")
155
 
        self.name = self.server.GetAlternativeServiceName(self.name)
 
149
        self.name = server.GetAlternativeServiceName(self.name)
156
150
        logger.info(u"Changing Zeroconf service name to %r ...",
157
 
                    unicode(self.name))
 
151
                    self.name)
158
152
        syslogger.setFormatter(logging.Formatter
159
153
                               (u'Mandos (%s) [%%(process)d]:'
160
154
                                u' %%(levelname)s: %%(message)s'
164
158
        self.rename_count += 1
165
159
    def remove(self):
166
160
        """Derived from the Avahi example code"""
167
 
        if self.group is not None:
168
 
            self.group.Reset()
 
161
        if group is not None:
 
162
            group.Reset()
169
163
    def add(self):
170
164
        """Derived from the Avahi example code"""
171
 
        if self.group is None:
172
 
            self.group = dbus.Interface(
173
 
                self.bus.get_object(avahi.DBUS_NAME,
174
 
                                    self.server.EntryGroupNew()),
175
 
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
176
 
            self.group.connect_to_signal('StateChanged',
177
 
                                         self.entry_group_state_changed)
 
165
        global group
 
166
        if group is None:
 
167
            group = dbus.Interface(bus.get_object
 
168
                                   (avahi.DBUS_NAME,
 
169
                                    server.EntryGroupNew()),
 
170
                                   avahi.DBUS_INTERFACE_ENTRY_GROUP)
 
171
            group.connect_to_signal('StateChanged',
 
172
                                    entry_group_state_changed)
178
173
        logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
179
 
                     self.name, self.type)
180
 
        self.group.AddService(
181
 
            self.interface,
182
 
            self.protocol,
183
 
            dbus.UInt32(0),     # flags
184
 
            self.name, self.type,
185
 
            self.domain, self.host,
186
 
            dbus.UInt16(self.port),
187
 
            avahi.string_array_to_txt_array(self.TXT))
188
 
        self.group.Commit()
189
 
    def entry_group_state_changed(self, state, error):
190
 
        """Derived from the Avahi example code"""
191
 
        logger.debug(u"Avahi state change: %i", state)
192
 
        
193
 
        if state == avahi.ENTRY_GROUP_ESTABLISHED:
194
 
            logger.debug(u"Zeroconf service established.")
195
 
        elif state == avahi.ENTRY_GROUP_COLLISION:
196
 
            logger.warning(u"Zeroconf service name collision.")
197
 
            self.rename()
198
 
        elif state == avahi.ENTRY_GROUP_FAILURE:
199
 
            logger.critical(u"Avahi: Error in group state changed %s",
200
 
                            unicode(error))
201
 
            raise AvahiGroupError(u"State changed: %s"
202
 
                                  % unicode(error))
203
 
    def cleanup(self):
204
 
        """Derived from the Avahi example code"""
205
 
        if self.group is not None:
206
 
            self.group.Free()
207
 
            self.group = None
208
 
    def server_state_changed(self, state):
209
 
        """Derived from the Avahi example code"""
210
 
        if state == avahi.SERVER_COLLISION:
211
 
            logger.error(u"Zeroconf server name collision")
212
 
            self.remove()
213
 
        elif state == avahi.SERVER_RUNNING:
214
 
            self.add()
215
 
    def activate(self):
216
 
        """Derived from the Avahi example code"""
217
 
        if self.server is None:
218
 
            self.server = dbus.Interface(
219
 
                self.bus.get_object(avahi.DBUS_NAME,
220
 
                                    avahi.DBUS_PATH_SERVER),
221
 
                avahi.DBUS_INTERFACE_SERVER)
222
 
        self.server.connect_to_signal(u"StateChanged",
223
 
                                 self.server_state_changed)
224
 
        self.server_state_changed(self.server.GetState())
 
174
                     service.name, service.type)
 
175
        group.AddService(
 
176
                self.interface,         # interface
 
177
                self.protocol,          # protocol
 
178
                dbus.UInt32(0),         # flags
 
179
                self.name, self.type,
 
180
                self.domain, self.host,
 
181
                dbus.UInt16(self.port),
 
182
                avahi.string_array_to_txt_array(self.TXT))
 
183
        group.Commit()
 
184
 
 
185
# From the Avahi example code:
 
186
group = None                            # our entry group
 
187
# End of Avahi example code
 
188
 
 
189
 
 
190
def _datetime_to_dbus(dt, variant_level=0):
 
191
    """Convert a UTC datetime.datetime() to a D-Bus type."""
 
192
    return dbus.String(dt.isoformat(), variant_level=variant_level)
225
193
 
226
194
 
227
195
class Client(object):
312
280
    
313
281
    def enable(self):
314
282
        """Start this client's checker and timeout hooks"""
315
 
        if getattr(self, u"enabled", False):
316
 
            # Already enabled
317
 
            return
318
283
        self.last_enabled = datetime.datetime.utcnow()
319
284
        # Schedule a new checker to be started an 'interval' from now,
320
285
        # and every interval from then on.
481
446
    """A Client class using D-Bus
482
447
    
483
448
    Attributes:
484
 
    dbus_object_path: dbus.ObjectPath
485
 
    bus: dbus.SystemBus()
 
449
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
486
450
    """
487
451
    # dbus.service.Object doesn't use super(), so we can't either.
488
452
    
489
 
    def __init__(self, bus = None, *args, **kwargs):
490
 
        self.bus = bus
 
453
    def __init__(self, *args, **kwargs):
491
454
        Client.__init__(self, *args, **kwargs)
492
455
        # Only now, when this client is initialized, can it show up on
493
456
        # the D-Bus
494
457
        self.dbus_object_path = (dbus.ObjectPath
495
458
                                 (u"/clients/"
496
459
                                  + self.name.replace(u".", u"_")))
497
 
        dbus.service.Object.__init__(self, self.bus,
 
460
        dbus.service.Object.__init__(self, bus,
498
461
                                     self.dbus_object_path)
499
 
    
500
 
    @staticmethod
501
 
    def _datetime_to_dbus(dt, variant_level=0):
502
 
        """Convert a UTC datetime.datetime() to a D-Bus type."""
503
 
        return dbus.String(dt.isoformat(),
504
 
                           variant_level=variant_level)
505
 
    
506
462
    def enable(self):
507
463
        oldstate = getattr(self, u"enabled", False)
508
464
        r = Client.enable(self)
510
466
            # Emit D-Bus signals
511
467
            self.PropertyChanged(dbus.String(u"enabled"),
512
468
                                 dbus.Boolean(True, variant_level=1))
513
 
            self.PropertyChanged(
514
 
                dbus.String(u"last_enabled"),
515
 
                self._datetime_to_dbus(self.last_enabled,
516
 
                                       variant_level=1))
 
469
            self.PropertyChanged(dbus.String(u"last_enabled"),
 
470
                                 (_datetime_to_dbus(self.last_enabled,
 
471
                                                    variant_level=1)))
517
472
        return r
518
473
    
519
474
    def disable(self, signal = True):
561
516
        # Emit D-Bus signal
562
517
        self.PropertyChanged(
563
518
            dbus.String(u"last_checked_ok"),
564
 
            (self._datetime_to_dbus(self.last_checked_ok,
565
 
                                    variant_level=1)))
 
519
            (_datetime_to_dbus(self.last_checked_ok,
 
520
                               variant_level=1)))
566
521
        return r
567
522
    
568
523
    def start_checker(self, *args, **kwargs):
623
578
                dbus.String(u"host"):
624
579
                    dbus.String(self.host, variant_level=1),
625
580
                dbus.String(u"created"):
626
 
                    self._datetime_to_dbus(self.created,
627
 
                                           variant_level=1),
 
581
                    _datetime_to_dbus(self.created, variant_level=1),
628
582
                dbus.String(u"last_enabled"):
629
 
                    (self._datetime_to_dbus(self.last_enabled,
630
 
                                            variant_level=1)
 
583
                    (_datetime_to_dbus(self.last_enabled,
 
584
                                       variant_level=1)
631
585
                     if self.last_enabled is not None
632
586
                     else dbus.Boolean(False, variant_level=1)),
633
587
                dbus.String(u"enabled"):
634
588
                    dbus.Boolean(self.enabled, variant_level=1),
635
589
                dbus.String(u"last_checked_ok"):
636
 
                    (self._datetime_to_dbus(self.last_checked_ok,
637
 
                                            variant_level=1)
 
590
                    (_datetime_to_dbus(self.last_checked_ok,
 
591
                                       variant_level=1)
638
592
                     if self.last_checked_ok is not None
639
593
                     else dbus.Boolean (False, variant_level=1)),
640
594
                dbus.String(u"timeout"):
747
701
    del _interface
748
702
 
749
703
 
750
 
class ClientHandler(socketserver.BaseRequestHandler, object):
 
704
class ClientHandler(SocketServer.BaseRequestHandler, object):
751
705
    """A class to handle client connections.
752
706
    
753
707
    Instantiated once for each connection to handle it.
895
849
        return hex_fpr
896
850
 
897
851
 
898
 
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
899
 
    """Like socketserver.ForkingMixIn, but also pass a pipe."""
 
852
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
 
853
    """Like SocketServer.ForkingMixIn, but also pass a pipe.
 
854
    
 
855
    Assumes a gobject.MainLoop event loop.
 
856
    """
900
857
    def process_request(self, request, client_address):
901
858
        """Overrides and wraps the original process_request().
902
859
        
906
863
        super(ForkingMixInWithPipe,
907
864
              self).process_request(request, client_address)
908
865
        os.close(self.pipe[1])  # close write end
909
 
        self.add_pipe(self.pipe[0])
910
 
    def add_pipe(self, pipe):
 
866
        # Call "handle_ipc" for both data and EOF events
 
867
        gobject.io_add_watch(self.pipe[0],
 
868
                             gobject.IO_IN | gobject.IO_HUP,
 
869
                             self.handle_ipc)
 
870
    def handle_ipc(source, condition):
911
871
        """Dummy function; override as necessary"""
912
 
        os.close(pipe)
 
872
        os.close(source)
 
873
        return False
913
874
 
914
875
 
915
876
class IPv6_TCPServer(ForkingMixInWithPipe,
916
 
                     socketserver.TCPServer, object):
 
877
                     SocketServer.TCPServer, object):
917
878
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
918
879
    
919
880
    Attributes:
920
881
        enabled:        Boolean; whether this server is activated yet
921
882
        interface:      None or a network interface name (string)
922
883
        use_ipv6:       Boolean; to use IPv6 or not
 
884
        ----
 
885
        clients:        set of Client objects
 
886
        gnutls_priority GnuTLS priority string
 
887
        use_dbus:       Boolean; to emit D-Bus signals or not
923
888
    """
924
889
    def __init__(self, server_address, RequestHandlerClass,
925
 
                 interface=None, use_ipv6=True):
 
890
                 interface=None, use_ipv6=True, clients=None,
 
891
                 gnutls_priority=None, use_dbus=True):
 
892
        self.enabled = False
926
893
        self.interface = interface
927
894
        if use_ipv6:
928
895
            self.address_family = socket.AF_INET6
929
 
        socketserver.TCPServer.__init__(self, server_address,
 
896
        self.clients = clients
 
897
        self.use_dbus = use_dbus
 
898
        self.gnutls_priority = gnutls_priority
 
899
        SocketServer.TCPServer.__init__(self, server_address,
930
900
                                        RequestHandlerClass)
931
901
    def server_bind(self):
932
902
        """This overrides the normal server_bind() function
933
903
        to bind to an interface if one was specified, and also NOT to
934
904
        bind to an address or port if they were not specified."""
935
905
        if self.interface is not None:
936
 
            if SO_BINDTODEVICE is None:
937
 
                logger.error(u"SO_BINDTODEVICE does not exist;"
938
 
                             u" cannot bind to interface %s",
939
 
                             self.interface)
940
 
            else:
941
 
                try:
942
 
                    self.socket.setsockopt(socket.SOL_SOCKET,
943
 
                                           SO_BINDTODEVICE,
944
 
                                           str(self.interface
945
 
                                               + u'\0'))
946
 
                except socket.error, error:
947
 
                    if error[0] == errno.EPERM:
948
 
                        logger.error(u"No permission to"
949
 
                                     u" bind to interface %s",
950
 
                                     self.interface)
951
 
                    elif error[0] == errno.ENOPROTOOPT:
952
 
                        logger.error(u"SO_BINDTODEVICE not available;"
953
 
                                     u" cannot bind to interface %s",
954
 
                                     self.interface)
955
 
                    else:
956
 
                        raise
 
906
            try:
 
907
                self.socket.setsockopt(socket.SOL_SOCKET,
 
908
                                       SO_BINDTODEVICE,
 
909
                                       str(self.interface + u'\0'))
 
910
            except socket.error, error:
 
911
                if error[0] == errno.EPERM:
 
912
                    logger.error(u"No permission to"
 
913
                                 u" bind to interface %s",
 
914
                                 self.interface)
 
915
                else:
 
916
                    raise
957
917
        # Only bind(2) the socket if we really need to.
958
918
        if self.server_address[0] or self.server_address[1]:
959
919
            if not self.server_address[0]:
972
932
#                                            0, # flowinfo
973
933
#                                            if_nametoindex
974
934
#                                            (self.interface))
975
 
            return socketserver.TCPServer.server_bind(self)
976
 
 
977
 
 
978
 
class MandosServer(IPv6_TCPServer):
979
 
    """Mandos server.
980
 
    
981
 
    Attributes:
982
 
        clients:        set of Client objects
983
 
        gnutls_priority GnuTLS priority string
984
 
        use_dbus:       Boolean; to emit D-Bus signals or not
985
 
        clients:        set of Client objects
986
 
        gnutls_priority GnuTLS priority string
987
 
        use_dbus:       Boolean; to emit D-Bus signals or not
988
 
    
989
 
    Assumes a gobject.MainLoop event loop.
990
 
    """
991
 
    def __init__(self, server_address, RequestHandlerClass,
992
 
                 interface=None, use_ipv6=True, clients=None,
993
 
                 gnutls_priority=None, use_dbus=True):
994
 
        self.enabled = False
995
 
        self.clients = clients
996
 
        if self.clients is None:
997
 
            self.clients = set()
998
 
        self.use_dbus = use_dbus
999
 
        self.gnutls_priority = gnutls_priority
1000
 
        IPv6_TCPServer.__init__(self, server_address,
1001
 
                                RequestHandlerClass,
1002
 
                                interface = interface,
1003
 
                                use_ipv6 = use_ipv6)
 
935
            return SocketServer.TCPServer.server_bind(self)
1004
936
    def server_activate(self):
1005
937
        if self.enabled:
1006
 
            return socketserver.TCPServer.server_activate(self)
 
938
            return SocketServer.TCPServer.server_activate(self)
1007
939
    def enable(self):
1008
940
        self.enabled = True
1009
 
    def add_pipe(self, pipe):
1010
 
        # Call "handle_ipc" for both data and EOF events
1011
 
        gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
1012
 
                             self.handle_ipc)
1013
941
    def handle_ipc(self, source, condition, file_objects={}):
1014
942
        condition_names = {
1015
943
            gobject.IO_IN: u"IN",   # There is data to read.
1121
1049
    return timevalue
1122
1050
 
1123
1051
 
 
1052
def server_state_changed(state):
 
1053
    """Derived from the Avahi example code"""
 
1054
    if state == avahi.SERVER_COLLISION:
 
1055
        logger.error(u"Zeroconf server name collision")
 
1056
        service.remove()
 
1057
    elif state == avahi.SERVER_RUNNING:
 
1058
        service.add()
 
1059
 
 
1060
 
 
1061
def entry_group_state_changed(state, error):
 
1062
    """Derived from the Avahi example code"""
 
1063
    logger.debug(u"Avahi state change: %i", state)
 
1064
    
 
1065
    if state == avahi.ENTRY_GROUP_ESTABLISHED:
 
1066
        logger.debug(u"Zeroconf service established.")
 
1067
    elif state == avahi.ENTRY_GROUP_COLLISION:
 
1068
        logger.warning(u"Zeroconf service name collision.")
 
1069
        service.rename()
 
1070
    elif state == avahi.ENTRY_GROUP_FAILURE:
 
1071
        logger.critical(u"Avahi: Error in group state changed %s",
 
1072
                        unicode(error))
 
1073
        raise AvahiGroupError(u"State changed: %s" % unicode(error))
 
1074
 
1124
1075
def if_nametoindex(interface):
1125
1076
    """Call the C function if_nametoindex(), or equivalent
1126
1077
    
1219
1170
                        }
1220
1171
    
1221
1172
    # Parse config file for server-global settings
1222
 
    server_config = configparser.SafeConfigParser(server_defaults)
 
1173
    server_config = ConfigParser.SafeConfigParser(server_defaults)
1223
1174
    del server_defaults
1224
1175
    server_config.read(os.path.join(options.configdir,
1225
1176
                                    u"mandos.conf"))
1272
1223
                        u"checker": u"fping -q -- %%(host)s",
1273
1224
                        u"host": u"",
1274
1225
                        }
1275
 
    client_config = configparser.SafeConfigParser(client_defaults)
 
1226
    client_config = ConfigParser.SafeConfigParser(client_defaults)
1276
1227
    client_config.read(os.path.join(server_settings[u"configdir"],
1277
1228
                                    u"clients.conf"))
1278
1229
    
1279
1230
    global mandos_dbus_service
1280
1231
    mandos_dbus_service = None
1281
1232
    
1282
 
    tcp_server = MandosServer((server_settings[u"address"],
1283
 
                               server_settings[u"port"]),
1284
 
                              ClientHandler,
1285
 
                              interface=server_settings[u"interface"],
1286
 
                              use_ipv6=use_ipv6,
1287
 
                              gnutls_priority=
1288
 
                              server_settings[u"priority"],
1289
 
                              use_dbus=use_dbus)
 
1233
    clients = set()
 
1234
    tcp_server = IPv6_TCPServer((server_settings[u"address"],
 
1235
                                 server_settings[u"port"]),
 
1236
                                ClientHandler,
 
1237
                                interface=
 
1238
                                server_settings[u"interface"],
 
1239
                                use_ipv6=use_ipv6,
 
1240
                                clients=clients,
 
1241
                                gnutls_priority=
 
1242
                                server_settings[u"priority"],
 
1243
                                use_dbus=use_dbus)
1290
1244
    pidfilename = u"/var/run/mandos.pid"
1291
1245
    try:
1292
1246
        pidfile = open(pidfilename, u"w")
1327
1281
        (gnutls.library.functions
1328
1282
         .gnutls_global_set_log_function(debug_gnutls))
1329
1283
    
 
1284
    global service
 
1285
    protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
 
1286
    service = AvahiService(name = server_settings[u"servicename"],
 
1287
                           servicetype = u"_mandos._tcp",
 
1288
                           protocol = protocol)
 
1289
    if server_settings["interface"]:
 
1290
        service.interface = (if_nametoindex
 
1291
                             (str(server_settings[u"interface"])))
 
1292
    
1330
1293
    global main_loop
 
1294
    global bus
 
1295
    global server
1331
1296
    # From the Avahi example code
1332
1297
    DBusGMainLoop(set_as_default=True )
1333
1298
    main_loop = gobject.MainLoop()
1334
1299
    bus = dbus.SystemBus()
 
1300
    server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
 
1301
                                           avahi.DBUS_PATH_SERVER),
 
1302
                            avahi.DBUS_INTERFACE_SERVER)
1335
1303
    # End of Avahi example code
1336
1304
    if use_dbus:
1337
1305
        bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1338
 
    protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1339
 
    service = AvahiService(name = server_settings[u"servicename"],
1340
 
                           servicetype = u"_mandos._tcp",
1341
 
                           protocol = protocol, bus = bus)
1342
 
    if server_settings["interface"]:
1343
 
        service.interface = (if_nametoindex
1344
 
                             (str(server_settings[u"interface"])))
1345
1306
    
1346
1307
    client_class = Client
1347
1308
    if use_dbus:
1348
 
        client_class = functools.partial(ClientDBus, bus = bus)
1349
 
    tcp_server.clients.update(set(
 
1309
        client_class = ClientDBus
 
1310
    clients.update(set(
1350
1311
            client_class(name = section,
1351
1312
                         config= dict(client_config.items(section)))
1352
1313
            for section in client_config.sections()))
1353
 
    if not tcp_server.clients:
 
1314
    if not clients:
1354
1315
        logger.warning(u"No clients defined")
1355
1316
    
1356
1317
    if debug:
1380
1341
    
1381
1342
    def cleanup():
1382
1343
        "Cleanup function; run on exit"
1383
 
        service.cleanup()
 
1344
        global group
 
1345
        # From the Avahi example code
 
1346
        if not group is None:
 
1347
            group.Free()
 
1348
            group = None
 
1349
        # End of Avahi example code
1384
1350
        
1385
 
        while tcp_server.clients:
1386
 
            client = tcp_server.clients.pop()
 
1351
        while clients:
 
1352
            client = clients.pop()
1387
1353
            client.disable_hook = None
1388
1354
            client.disable()
1389
1355
    
1419
1385
            @dbus.service.method(_interface, out_signature=u"ao")
1420
1386
            def GetAllClients(self):
1421
1387
                "D-Bus method"
1422
 
                return dbus.Array(c.dbus_object_path
1423
 
                                  for c in tcp_server.clients)
 
1388
                return dbus.Array(c.dbus_object_path for c in clients)
1424
1389
            
1425
1390
            @dbus.service.method(_interface,
1426
1391
                                 out_signature=u"a{oa{sv}}")
1428
1393
                "D-Bus method"
1429
1394
                return dbus.Dictionary(
1430
1395
                    ((c.dbus_object_path, c.GetAllProperties())
1431
 
                     for c in tcp_server.clients),
 
1396
                     for c in clients),
1432
1397
                    signature=u"oa{sv}")
1433
1398
            
1434
1399
            @dbus.service.method(_interface, in_signature=u"o")
1435
1400
            def RemoveClient(self, object_path):
1436
1401
                "D-Bus method"
1437
 
                for c in tcp_server.clients:
 
1402
                for c in clients:
1438
1403
                    if c.dbus_object_path == object_path:
1439
 
                        tcp_server.clients.remove(c)
 
1404
                        clients.remove(c)
1440
1405
                        c.remove_from_connection()
1441
1406
                        # Don't signal anything except ClientRemoved
1442
1407
                        c.disable(signal=False)
1449
1414
        
1450
1415
        mandos_dbus_service = MandosDBusService()
1451
1416
    
1452
 
    for client in tcp_server.clients:
 
1417
    for client in clients:
1453
1418
        if use_dbus:
1454
1419
            # Emit D-Bus signal
1455
1420
            mandos_dbus_service.ClientAdded(client.dbus_object_path,
1473
1438
    
1474
1439
    try:
1475
1440
        # From the Avahi example code
 
1441
        server.connect_to_signal(u"StateChanged", server_state_changed)
1476
1442
        try:
1477
 
            service.activate()
 
1443
            server_state_changed(server.GetState())
1478
1444
        except dbus.exceptions.DBusException, error:
1479
1445
            logger.critical(u"DBusException: %s", error)
1480
1446
            sys.exit(1)