/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:00:35 UTC
  • Revision ID: teddy@fukt.bsnet.se-20090416010035-y7ta6ra2da4gf6mp
Minor code cleanup; one minor bug fix.

* initramfs-tools-hook: Bug fix: Use the primary group of the first
                        suitable user found, do not look for a
                        group separately.
* mandos: Unconditionally import "struct" and "fcntl".  Use unicode
          strings everywhere possible.
  (Client._datetime_to_milliseconds): New static method.
  (Client.timeout_milliseconds, Client.interval_milliseconds): Use
                                                               above
                                                               method.
  (ClientDBus.CheckedOK,
  ClientDBus.Enable, ClientDBus.StopChecker): Define normally.
  (if_nametoindex): Document non-acceptance of unicode strings.  All
                    callers adjusted.  Do not import "struct" or
                    "fcntl".  Log warning message if if_nametoindex
                    cannot be found using ctypes modules.
  (main): Bug fix: Do not look for user named "nogroup".

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