/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

* network-hooks.d: New directory.
* network-hooks.d/bridge: New example hook.
* network-hooks.d/bridge.conf: Config file for bridge example hook.

Show diffs side-by-side

added added

removed removed

Lines of Context:
63
63
import cPickle as pickle
64
64
import multiprocessing
65
65
import types
66
 
import hashlib
67
66
 
68
67
import dbus
69
68
import dbus.service
74
73
import ctypes.util
75
74
import xml.dom.minidom
76
75
import inspect
77
 
import Crypto.Cipher.AES
78
76
 
79
77
try:
80
78
    SO_BINDTODEVICE = socket.SO_BINDTODEVICE
87
85
 
88
86
version = "1.4.1"
89
87
 
90
 
logger = logging.getLogger()
91
 
stored_state_path = "/var/lib/mandos/clients.pickle"
92
 
 
 
88
#logger = logging.getLogger('mandos')
 
89
logger = logging.Logger('mandos')
93
90
syslogger = (logging.handlers.SysLogHandler
94
91
             (facility = logging.handlers.SysLogHandler.LOG_DAEMON,
95
92
              address = str("/dev/log")))
99
96
logger.addHandler(syslogger)
100
97
 
101
98
console = logging.StreamHandler()
102
 
console.setFormatter(logging.Formatter('%(asctime)s %(name)s'
103
 
                                       ' [%(process)d]:'
 
99
console.setFormatter(logging.Formatter('%(name)s [%(process)d]:'
104
100
                                       ' %(levelname)s:'
105
101
                                       ' %(message)s'))
106
102
logger.addHandler(console)
107
103
 
108
 
 
109
104
class AvahiError(Exception):
110
105
    def __init__(self, value, *args, **kwargs):
111
106
        self.value = value
169
164
                            .GetAlternativeServiceName(self.name))
170
165
        logger.info("Changing Zeroconf service name to %r ...",
171
166
                    self.name)
 
167
        syslogger.setFormatter(logging.Formatter
 
168
                               ('Mandos (%s) [%%(process)d]:'
 
169
                                ' %%(levelname)s: %%(message)s'
 
170
                                % self.name))
172
171
        self.remove()
173
172
        try:
174
173
            self.add()
194
193
                avahi.DBUS_INTERFACE_ENTRY_GROUP)
195
194
        self.entry_group_state_changed_match = (
196
195
            self.group.connect_to_signal(
197
 
                'StateChanged', self.entry_group_state_changed))
 
196
                'StateChanged', self .entry_group_state_changed))
198
197
        logger.debug("Adding Zeroconf service '%s' of type '%s' ...",
199
198
                     self.name, self.type)
200
199
        self.group.AddService(
266
265
                                 self.server_state_changed)
267
266
        self.server_state_changed(self.server.GetState())
268
267
 
269
 
class AvahiServiceToSyslog(AvahiService):
270
 
    def rename(self):
271
 
        """Add the new name to the syslog messages"""
272
 
        ret = AvahiService.rename(self)
273
 
        syslogger.setFormatter(logging.Formatter
274
 
                               ('Mandos (%s) [%%(process)d]:'
275
 
                                ' %%(levelname)s: %%(message)s'
276
 
                                % self.name))
277
 
        return ret
278
268
 
279
269
def _timedelta_to_milliseconds(td):
280
270
    "Convert a datetime.timedelta() to milliseconds"
299
289
                     instance %(name)s can be used in the command.
300
290
    checker_initiator_tag: a gobject event source tag, or None
301
291
    created:    datetime.datetime(); (UTC) object creation
302
 
    client_structure: Object describing what attributes a client has
303
 
                      and is used for storing the client at exit
304
292
    current_checker_command: string; current running checker_command
 
293
    disable_hook:  If set, called by disable() as disable_hook(self)
305
294
    disable_initiator_tag: a gobject event source tag, or None
306
295
    enabled:    bool()
307
296
    fingerprint: string (40 or 32 hexadecimal digits); used to
310
299
    interval:   datetime.timedelta(); How often to start a new checker
311
300
    last_approval_request: datetime.datetime(); (UTC) or None
312
301
    last_checked_ok: datetime.datetime(); (UTC) or None
313
 
    last_checker_status: integer between 0 and 255 reflecting exit status
314
 
                         of last checker. -1 reflect crashed checker,
315
 
                         or None.
316
302
    last_enabled: datetime.datetime(); (UTC)
317
303
    name:       string; from the config file, used in log messages and
318
304
                        D-Bus identifiers
345
331
    def approval_delay_milliseconds(self):
346
332
        return _timedelta_to_milliseconds(self.approval_delay)
347
333
    
348
 
    def __init__(self, name = None, config=None):
 
334
    def __init__(self, name = None, disable_hook=None, config=None):
349
335
        """Note: the 'checker' key in 'config' sets the
350
336
        'checker_command' attribute and *not* the 'checker'
351
337
        attribute."""
371
357
                            % self.name)
372
358
        self.host = config.get("host", "")
373
359
        self.created = datetime.datetime.utcnow()
374
 
        self.enabled = True
 
360
        self.enabled = False
375
361
        self.last_approval_request = None
376
 
        self.last_enabled = datetime.datetime.utcnow()
 
362
        self.last_enabled = None
377
363
        self.last_checked_ok = None
378
 
        self.last_checker_status = None
379
364
        self.timeout = string_to_delta(config["timeout"])
380
365
        self.extended_timeout = string_to_delta(config
381
366
                                                ["extended_timeout"])
382
367
        self.interval = string_to_delta(config["interval"])
 
368
        self.disable_hook = disable_hook
383
369
        self.checker = None
384
370
        self.checker_initiator_tag = None
385
371
        self.disable_initiator_tag = None
386
 
        self.expires = datetime.datetime.utcnow() + self.timeout
 
372
        self.expires = None
387
373
        self.checker_callback_tag = None
388
374
        self.checker_command = config["checker"]
389
375
        self.current_checker_command = None
 
376
        self.last_connect = None
390
377
        self._approved = None
391
378
        self.approved_by_default = config.get("approved_by_default",
392
379
                                              True)
398
385
        self.changedstate = (multiprocessing_manager
399
386
                             .Condition(multiprocessing_manager
400
387
                                        .Lock()))
401
 
        self.client_structure = [attr for attr in self.__dict__.iterkeys() if not attr.startswith("_")]
402
 
        self.client_structure.append("client_structure")
403
 
 
404
 
 
405
 
        for name, t in inspect.getmembers(type(self),
406
 
                                          lambda obj: isinstance(obj, property)):
407
 
            if not name.startswith("_"):
408
 
                self.client_structure.append(name)
409
388
    
410
 
    # Send notice to process children that client state has changed
411
389
    def send_changedstate(self):
412
 
        with self.changedstate:
413
 
            self.changedstate.notify_all()
 
390
        self.changedstate.acquire()
 
391
        self.changedstate.notify_all()
 
392
        self.changedstate.release()
414
393
    
415
394
    def enable(self):
416
395
        """Start this client's checker and timeout hooks"""
418
397
            # Already enabled
419
398
            return
420
399
        self.send_changedstate()
 
400
        # Schedule a new checker to be started an 'interval' from now,
 
401
        # and every interval from then on.
 
402
        self.checker_initiator_tag = (gobject.timeout_add
 
403
                                      (self.interval_milliseconds(),
 
404
                                       self.start_checker))
 
405
        # Schedule a disable() when 'timeout' has passed
421
406
        self.expires = datetime.datetime.utcnow() + self.timeout
 
407
        self.disable_initiator_tag = (gobject.timeout_add
 
408
                                   (self.timeout_milliseconds(),
 
409
                                    self.disable))
422
410
        self.enabled = True
423
411
        self.last_enabled = datetime.datetime.utcnow()
424
 
        self.init_checker()
 
412
        # Also start a new checker *right now*.
 
413
        self.start_checker()
425
414
    
426
415
    def disable(self, quiet=True):
427
416
        """Disable this client."""
439
428
            gobject.source_remove(self.checker_initiator_tag)
440
429
            self.checker_initiator_tag = None
441
430
        self.stop_checker()
 
431
        if self.disable_hook:
 
432
            self.disable_hook(self)
442
433
        self.enabled = False
443
434
        # Do not run this again if called by a gobject.timeout_add
444
435
        return False
445
436
    
446
437
    def __del__(self):
 
438
        self.disable_hook = None
447
439
        self.disable()
448
 
 
449
 
    def init_checker(self):
450
 
        # Schedule a new checker to be started an 'interval' from now,
451
 
        # and every interval from then on.
452
 
        self.checker_initiator_tag = (gobject.timeout_add
453
 
                                      (self.interval_milliseconds(),
454
 
                                       self.start_checker))
455
 
        # Schedule a disable() when 'timeout' has passed
456
 
        self.disable_initiator_tag = (gobject.timeout_add
457
 
                                   (self.timeout_milliseconds(),
458
 
                                    self.disable))
459
 
        # Also start a new checker *right now*.
460
 
        self.start_checker()
461
 
 
462
 
        
 
440
    
463
441
    def checker_callback(self, pid, condition, command):
464
442
        """The checker has completed, so take appropriate actions."""
465
443
        self.checker_callback_tag = None
466
444
        self.checker = None
467
445
        if os.WIFEXITED(condition):
468
 
            self.last_checker_status =  os.WEXITSTATUS(condition)
469
 
            if self.last_checker_status == 0:
 
446
            exitstatus = os.WEXITSTATUS(condition)
 
447
            if exitstatus == 0:
470
448
                logger.info("Checker for %(name)s succeeded",
471
449
                            vars(self))
472
450
                self.checked_ok()
474
452
                logger.info("Checker for %(name)s failed",
475
453
                            vars(self))
476
454
        else:
477
 
            self.last_checker_status = -1
478
455
            logger.warning("Checker for %(name)s crashed?",
479
456
                           vars(self))
480
457
    
591
568
                raise
592
569
        self.checker = None
593
570
 
594
 
    # Encrypts a client secret and stores it in a varible encrypted_secret
595
 
    def encrypt_secret(self, key):
596
 
        # Encryption-key need to be of a specific size, so we hash inputed key
597
 
        hasheng = hashlib.sha256()
598
 
        hasheng.update(key)
599
 
        encryptionkey = hasheng.digest()
600
 
 
601
 
        # Create validation hash so we know at decryption if it was sucessful
602
 
        hasheng = hashlib.sha256()
603
 
        hasheng.update(self.secret)
604
 
        validationhash = hasheng.digest()
605
 
 
606
 
        # Encrypt secret
607
 
        iv = os.urandom(Crypto.Cipher.AES.block_size)
608
 
        ciphereng = Crypto.Cipher.AES.new(encryptionkey,
609
 
                                        Crypto.Cipher.AES.MODE_CFB, iv)
610
 
        ciphertext = ciphereng.encrypt(validationhash+self.secret)
611
 
        self.encrypted_secret = (ciphertext, iv)
612
 
 
613
 
    # Decrypt a encrypted client secret
614
 
    def decrypt_secret(self, key):
615
 
        # Decryption-key need to be of a specific size, so we hash inputed key
616
 
        hasheng = hashlib.sha256()
617
 
        hasheng.update(key)
618
 
        encryptionkey = hasheng.digest()
619
 
 
620
 
        # Decrypt encrypted secret
621
 
        ciphertext, iv = self.encrypted_secret
622
 
        ciphereng = Crypto.Cipher.AES.new(encryptionkey,
623
 
                                        Crypto.Cipher.AES.MODE_CFB, iv)
624
 
        plain = ciphereng.decrypt(ciphertext)
625
 
 
626
 
        # Validate decrypted secret to know if it was succesful
627
 
        hasheng = hashlib.sha256()
628
 
        validationhash = plain[:hasheng.digest_size]
629
 
        secret = plain[hasheng.digest_size:]
630
 
        hasheng.update(secret)
631
 
 
632
 
        # if validation fails, we use key as new secret. Otherwhise, we use
633
 
        # the decrypted secret
634
 
        if hasheng.digest() == validationhash:
635
 
            self.secret = secret
636
 
        else:
637
 
            self.secret = key
638
 
        del self.encrypted_secret
639
 
 
640
571
 
641
572
def dbus_service_property(dbus_interface, signature="v",
642
573
                          access="readwrite", byte_arrays=False):
943
874
    # dbus.service.Object doesn't use super(), so we can't either.
944
875
    
945
876
    def __init__(self, bus = None, *args, **kwargs):
 
877
        self._approvals_pending = 0
946
878
        self.bus = bus
947
879
        Client.__init__(self, *args, **kwargs)
948
 
 
949
 
        self._approvals_pending = 0
950
880
        # Only now, when this client is initialized, can it show up on
951
881
        # the D-Bus
952
882
        client_object_name = unicode(self.name).translate(
1694
1624
        self.enabled = False
1695
1625
        self.clients = clients
1696
1626
        if self.clients is None:
1697
 
            self.clients = {}
 
1627
            self.clients = set()
1698
1628
        self.use_dbus = use_dbus
1699
1629
        self.gnutls_priority = gnutls_priority
1700
1630
        IPv6_TCPServer.__init__(self, server_address,
1747
1677
            fpr = request[1]
1748
1678
            address = request[2]
1749
1679
            
1750
 
            for c in self.clients.itervalues():
 
1680
            for c in self.clients:
1751
1681
                if c.fingerprint == fpr:
1752
1682
                    client = c
1753
1683
                    break
1921
1851
                        " system bus interface")
1922
1852
    parser.add_argument("--no-ipv6", action="store_false",
1923
1853
                        dest="use_ipv6", help="Do not use IPv6")
1924
 
    parser.add_argument("--no-restore", action="store_false",
1925
 
                        dest="restore", help="Do not restore stored state",
1926
 
                        default=True)
1927
 
 
1928
1854
    options = parser.parse_args()
1929
1855
    
1930
1856
    if options.check:
1965
1891
    # options, if set.
1966
1892
    for option in ("interface", "address", "port", "debug",
1967
1893
                   "priority", "servicename", "configdir",
1968
 
                   "use_dbus", "use_ipv6", "debuglevel", "restore"):
 
1894
                   "use_dbus", "use_ipv6", "debuglevel"):
1969
1895
        value = getattr(options, option)
1970
1896
        if value is not None:
1971
1897
            server_settings[option] = value
2044
1970
            raise error
2045
1971
    
2046
1972
    if not debug and not debuglevel:
2047
 
        logger.setLevel(logging.WARNING)
 
1973
        syslogger.setLevel(logging.WARNING)
 
1974
        console.setLevel(logging.WARNING)
2048
1975
    if debuglevel:
2049
1976
        level = getattr(logging, debuglevel.upper())
2050
 
        logger.setLevel(level)
 
1977
        syslogger.setLevel(level)
 
1978
        console.setLevel(level)
2051
1979
    
2052
1980
    if debug:
2053
 
        logger.setLevel(logging.DEBUG)
2054
1981
        # Enable all possible GnuTLS debugging
2055
1982
        
2056
1983
        # "Use a log level over 10 to enable all debugging options."
2097
2024
            server_settings["use_dbus"] = False
2098
2025
            tcp_server.use_dbus = False
2099
2026
    protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
2100
 
    service = AvahiServiceToSyslog(name =
2101
 
                                   server_settings["servicename"],
2102
 
                                   servicetype = "_mandos._tcp",
2103
 
                                   protocol = protocol, bus = bus)
 
2027
    service = AvahiService(name = server_settings["servicename"],
 
2028
                           servicetype = "_mandos._tcp",
 
2029
                           protocol = protocol, bus = bus)
2104
2030
    if server_settings["interface"]:
2105
2031
        service.interface = (if_nametoindex
2106
2032
                             (str(server_settings["interface"])))
2112
2038
    if use_dbus:
2113
2039
        client_class = functools.partial(ClientDBusTransitional,
2114
2040
                                         bus = bus)
2115
 
    
2116
 
    special_settings = {
2117
 
        # Some settings need to be accessd by special methods;
2118
 
        # booleans need .getboolean(), etc.  Here is a list of them:
2119
 
        "approved_by_default":
2120
 
            lambda section:
2121
 
            client_config.getboolean(section, "approved_by_default"),
2122
 
        }
2123
 
    # Construct a new dict of client settings of this form:
2124
 
    # { client_name: {setting_name: value, ...}, ...}
2125
 
    # with exceptions for any special settings as defined above
2126
 
    client_settings = dict((clientname,
2127
 
                           dict((setting,
2128
 
                                 (value if setting not in special_settings
2129
 
                                  else special_settings[setting](clientname)))
2130
 
                                for setting, value in client_config.items(clientname)))
2131
 
                          for clientname in client_config.sections())
2132
 
    
2133
 
    old_client_settings = {}
2134
 
    clients_data = []
2135
 
 
2136
 
    # Get client data and settings from last running state. 
2137
 
    if server_settings["restore"]:
2138
 
        try:
2139
 
            with open(stored_state_path, "rb") as stored_state:
2140
 
                clients_data, old_client_settings = pickle.load(stored_state)
2141
 
            os.remove(stored_state_path)
2142
 
        except IOError as e:
2143
 
            logger.warning("Could not load persistant state: {0}".format(e))
2144
 
            if e.errno != errno.ENOENT:
2145
 
                raise
2146
 
 
2147
 
    for client in clients_data:
2148
 
        client_name = client["name"]
2149
 
        
2150
 
        # Decide which value to use after restoring saved state.
2151
 
        # We have three different values: Old config file,
2152
 
        # new config file, and saved state.
2153
 
        # New config value takes precedence if it differs from old
2154
 
        # config value, otherwise use saved state.
2155
 
        for name, value in client_settings[client_name].items():
 
2041
    def client_config_items(config, section):
 
2042
        special_settings = {
 
2043
            "approved_by_default":
 
2044
                lambda: config.getboolean(section,
 
2045
                                          "approved_by_default"),
 
2046
            }
 
2047
        for name, value in config.items(section):
2156
2048
            try:
2157
 
                # For each value in new config, check if it differs
2158
 
                # from the old config value (Except for the "secret"
2159
 
                # attribute)
2160
 
                if name != "secret" and value != old_client_settings[client_name][name]:
2161
 
                    setattr(client, name, value)
 
2049
                yield (name, special_settings[name]())
2162
2050
            except KeyError:
2163
 
                pass
2164
 
 
2165
 
        # Clients who has passed its expire date, can still be enabled if its
2166
 
        # last checker was sucessful. Clients who checkers failed before we
2167
 
        # stored it state is asumed to had failed checker during downtime.
2168
 
        if client["enabled"] and client["last_checked_ok"]:
2169
 
            if ((datetime.datetime.utcnow() - client["last_checked_ok"])
2170
 
                > client["interval"]):
2171
 
                if client["last_checker_status"] != 0:
2172
 
                    client["enabled"] = False
2173
 
                else:
2174
 
                    client["expires"] = datetime.datetime.utcnow() + client["timeout"]
2175
 
 
2176
 
        client["changedstate"] = (multiprocessing_manager
2177
 
                                  .Condition(multiprocessing_manager
2178
 
                                             .Lock()))
2179
 
        if use_dbus:
2180
 
            new_client = ClientDBusTransitional.__new__(ClientDBusTransitional)
2181
 
            tcp_server.clients[client_name] = new_client
2182
 
            new_client.bus = bus
2183
 
            for name, value in client.iteritems():
2184
 
                setattr(new_client, name, value)
2185
 
            client_object_name = unicode(client_name).translate(
2186
 
                {ord("."): ord("_"),
2187
 
                 ord("-"): ord("_")})
2188
 
            new_client.dbus_object_path = (dbus.ObjectPath
2189
 
                                     ("/clients/" + client_object_name))
2190
 
            DBusObjectWithProperties.__init__(new_client,
2191
 
                                              new_client.bus,
2192
 
                                              new_client.dbus_object_path)
2193
 
        else:
2194
 
            tcp_server.clients[client_name] = Client.__new__(Client)
2195
 
            for name, value in client.iteritems():
2196
 
                setattr(tcp_server.clients[client_name], name, value)
2197
 
                
2198
 
        tcp_server.clients[client_name].decrypt_secret(
2199
 
            client_settings[client_name]["secret"])            
2200
 
        
2201
 
    # Create/remove clients based on new changes made to config
2202
 
    for clientname in set(old_client_settings) - set(client_settings):
2203
 
        del tcp_server.clients[clientname]
2204
 
    for clientname in set(client_settings) - set(old_client_settings):
2205
 
        tcp_server.clients[clientname] = (client_class(name = clientname,
2206
 
                                                       config =
2207
 
                                                       client_settings
2208
 
                                                       [clientname]))
 
2051
                yield (name, value)
2209
2052
    
2210
 
 
 
2053
    tcp_server.clients.update(set(
 
2054
            client_class(name = section,
 
2055
                         config= dict(client_config_items(
 
2056
                        client_config, section)))
 
2057
            for section in client_config.sections()))
2211
2058
    if not tcp_server.clients:
2212
2059
        logger.warning("No clients defined")
2213
2060
        
2256
2103
            def GetAllClients(self):
2257
2104
                "D-Bus method"
2258
2105
                return dbus.Array(c.dbus_object_path
2259
 
                                  for c in
2260
 
                                  tcp_server.clients.itervalues())
 
2106
                                  for c in tcp_server.clients)
2261
2107
            
2262
2108
            @dbus.service.method(_interface,
2263
2109
                                 out_signature="a{oa{sv}}")
2265
2111
                "D-Bus method"
2266
2112
                return dbus.Dictionary(
2267
2113
                    ((c.dbus_object_path, c.GetAll(""))
2268
 
                     for c in tcp_server.clients.itervalues()),
 
2114
                     for c in tcp_server.clients),
2269
2115
                    signature="oa{sv}")
2270
2116
            
2271
2117
            @dbus.service.method(_interface, in_signature="o")
2272
2118
            def RemoveClient(self, object_path):
2273
2119
                "D-Bus method"
2274
 
                for c in tcp_server.clients.itervalues():
 
2120
                for c in tcp_server.clients:
2275
2121
                    if c.dbus_object_path == object_path:
2276
 
                        del tcp_server.clients[c.name]
 
2122
                        tcp_server.clients.remove(c)
2277
2123
                        c.remove_from_connection()
2278
2124
                        # Don't signal anything except ClientRemoved
2279
2125
                        c.disable(quiet=True)
2293
2139
        service.cleanup()
2294
2140
        
2295
2141
        multiprocessing.active_children()
2296
 
        if not (tcp_server.clients or client_settings):
2297
 
            return
2298
 
 
2299
 
        # Store client before exiting. Secrets are encrypted with key based
2300
 
        # on what config file has. If config file is removed/edited, old
2301
 
        # secret will thus be unrecovable.
2302
 
        clients = []
2303
 
        for client in tcp_server.clients.itervalues():
2304
 
            client.encrypt_secret(client_settings[client.name]["secret"])
2305
 
 
2306
 
            client_dict = {}
2307
 
 
2308
 
            # A list of attributes that will not be stored when shuting down.
2309
 
            exclude = set(("bus", "changedstate", "secret"))            
2310
 
            for name, typ in inspect.getmembers(dbus.service.Object):
2311
 
                exclude.add(name)
2312
 
                
2313
 
            client_dict["encrypted_secret"] = client.encrypted_secret
2314
 
            for attr in client.client_structure:
2315
 
                if attr not in exclude:
2316
 
                    client_dict[attr] = getattr(client, attr)
2317
 
 
2318
 
            clients.append(client_dict) 
2319
 
            del client_settings[client.name]["secret"]
2320
 
            
2321
 
        try:
2322
 
            with os.fdopen(os.open(stored_state_path, os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0600), "wb") as stored_state:
2323
 
                pickle.dump((clients, client_settings), stored_state)
2324
 
        except IOError as e:
2325
 
            logger.warning("Could not save persistant state: {0}".format(e))
2326
 
            if e.errno != errno.ENOENT:
2327
 
                raise
2328
 
 
2329
 
        # Delete all clients, and settings from config
2330
2142
        while tcp_server.clients:
2331
 
            name, client = tcp_server.clients.popitem()
 
2143
            client = tcp_server.clients.pop()
2332
2144
            if use_dbus:
2333
2145
                client.remove_from_connection()
 
2146
            client.disable_hook = None
2334
2147
            # Don't signal anything except ClientRemoved
2335
2148
            client.disable(quiet=True)
2336
2149
            if use_dbus:
2338
2151
                mandos_dbus_service.ClientRemoved(client
2339
2152
                                                  .dbus_object_path,
2340
2153
                                                  client.name)
2341
 
        client_settings.clear()
2342
2154
    
2343
2155
    atexit.register(cleanup)
2344
2156
    
2345
 
    for client in tcp_server.clients.itervalues():
 
2157
    for client in tcp_server.clients:
2346
2158
        if use_dbus:
2347
2159
            # Emit D-Bus signal
2348
2160
            mandos_dbus_service.ClientAdded(client.dbus_object_path)
2349
 
        # Need to initiate checking of clients
2350
 
        if client.enabled:
2351
 
            client.init_checker()
2352
 
 
 
2161
        client.enable()
2353
2162
    
2354
2163
    tcp_server.enable()
2355
2164
    tcp_server.server_activate()