/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: 2008-12-21 19:19:25 UTC
  • mfrom: (24.1.116 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081221191925-iw4js3mr8e04p35r
Merge "mandos-list" from belorn.

* Makefile (PROGS): Added "mandos-list".
  (mandos-list): New.

* mandos-list: New; from merge.  Added unicode support.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
# and some lines in "main".
12
12
13
13
# Everything else is
14
 
# Copyright © 2008,2009 Teddy Hogeborn
15
 
# Copyright © 2008,2009 Björn Påhlsson
 
14
# Copyright © 2008 Teddy Hogeborn
 
15
# Copyright © 2008 Björn Påhlsson
16
16
17
17
# This program is free software: you can redistribute it and/or modify
18
18
# it under the terms of the GNU General Public License as published by
35
35
 
36
36
import SocketServer
37
37
import socket
38
 
import optparse
 
38
from optparse import OptionParser
39
39
import datetime
40
40
import errno
41
41
import gnutls.crypto
66
66
import ctypes
67
67
import ctypes.util
68
68
 
69
 
version = "1.0.4"
 
69
version = "1.0.2"
70
70
 
71
71
logger = logging.Logger('mandos')
72
72
syslogger = (logging.handlers.SysLogHandler
82
82
logger.addHandler(console)
83
83
 
84
84
class AvahiError(Exception):
85
 
    def __init__(self, value, *args, **kwargs):
 
85
    def __init__(self, value):
86
86
        self.value = value
87
 
        super(AvahiError, self).__init__(value, *args, **kwargs)
88
 
    def __unicode__(self):
89
 
        return unicode(repr(self.value))
 
87
        super(AvahiError, self).__init__()
 
88
    def __str__(self):
 
89
        return repr(self.value)
90
90
 
91
91
class AvahiServiceError(AvahiError):
92
92
    pass
129
129
            logger.critical(u"No suitable Zeroconf service name found"
130
130
                            u" after %i retries, exiting.",
131
131
                            self.rename_count)
132
 
            raise AvahiServiceError(u"Too many renames")
 
132
            raise AvahiServiceError("Too many renames")
133
133
        self.name = server.GetAlternativeServiceName(self.name)
134
134
        logger.info(u"Changing Zeroconf service name to %r ...",
135
135
                    str(self.name))
201
201
                     client lives.  %() expansions are done at
202
202
                     runtime with vars(self) as dict, so that for
203
203
                     instance %(name)s can be used in the command.
204
 
    use_dbus: bool(); Whether to provide D-Bus interface and signals
205
 
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
 
204
    dbus_object_path: dbus.ObjectPath
 
205
    Private attibutes:
 
206
    _timeout: Real variable for 'timeout'
 
207
    _interval: Real variable for 'interval'
 
208
    _timeout_milliseconds: Used when calling gobject.timeout_add()
 
209
    _interval_milliseconds: - '' -
206
210
    """
207
 
    def timeout_milliseconds(self):
208
 
        "Return the 'timeout' attribute in milliseconds"
209
 
        return ((self.timeout.days * 24 * 60 * 60 * 1000)
210
 
                + (self.timeout.seconds * 1000)
211
 
                + (self.timeout.microseconds // 1000))
212
 
    
213
 
    def interval_milliseconds(self):
214
 
        "Return the 'interval' attribute in milliseconds"
215
 
        return ((self.interval.days * 24 * 60 * 60 * 1000)
216
 
                + (self.interval.seconds * 1000)
217
 
                + (self.interval.microseconds // 1000))
218
 
    
219
 
    def __init__(self, name = None, disable_hook=None, config=None,
220
 
                 use_dbus=True):
 
211
    def _set_timeout(self, timeout):
 
212
        "Setter function for the 'timeout' attribute"
 
213
        self._timeout = timeout
 
214
        self._timeout_milliseconds = ((self.timeout.days
 
215
                                       * 24 * 60 * 60 * 1000)
 
216
                                      + (self.timeout.seconds * 1000)
 
217
                                      + (self.timeout.microseconds
 
218
                                         // 1000))
 
219
        # Emit D-Bus signal
 
220
        self.PropertyChanged(dbus.String(u"timeout"),
 
221
                             (dbus.UInt64(self._timeout_milliseconds,
 
222
                                          variant_level=1)))
 
223
    timeout = property(lambda self: self._timeout, _set_timeout)
 
224
    del _set_timeout
 
225
    
 
226
    def _set_interval(self, interval):
 
227
        "Setter function for the 'interval' attribute"
 
228
        self._interval = interval
 
229
        self._interval_milliseconds = ((self.interval.days
 
230
                                        * 24 * 60 * 60 * 1000)
 
231
                                       + (self.interval.seconds
 
232
                                          * 1000)
 
233
                                       + (self.interval.microseconds
 
234
                                          // 1000))
 
235
        # Emit D-Bus signal
 
236
        self.PropertyChanged(dbus.String(u"interval"),
 
237
                             (dbus.UInt64(self._interval_milliseconds,
 
238
                                          variant_level=1)))
 
239
    interval = property(lambda self: self._interval, _set_interval)
 
240
    del _set_interval
 
241
    
 
242
    def __init__(self, name = None, disable_hook=None, config=None):
221
243
        """Note: the 'checker' key in 'config' sets the
222
244
        'checker_command' attribute and *not* the 'checker'
223
245
        attribute."""
224
 
        self.name = name
 
246
        self.dbus_object_path = (dbus.ObjectPath
 
247
                                 ("/Mandos/clients/"
 
248
                                  + name.replace(".", "_")))
 
249
        dbus.service.Object.__init__(self, bus,
 
250
                                     self.dbus_object_path)
225
251
        if config is None:
226
252
            config = {}
 
253
        self.name = name
227
254
        logger.debug(u"Creating client %r", self.name)
228
 
        self.use_dbus = use_dbus
229
 
        if self.use_dbus:
230
 
            self.dbus_object_path = (dbus.ObjectPath
231
 
                                     ("/Mandos/clients/"
232
 
                                      + self.name.replace(".", "_")))
233
 
            dbus.service.Object.__init__(self, bus,
234
 
                                         self.dbus_object_path)
235
255
        # Uppercase and remove spaces from fingerprint for later
236
256
        # comparison purposes with return value from the fingerprint()
237
257
        # function
268
288
        # Schedule a new checker to be started an 'interval' from now,
269
289
        # and every interval from then on.
270
290
        self.checker_initiator_tag = (gobject.timeout_add
271
 
                                      (self.interval_milliseconds(),
 
291
                                      (self._interval_milliseconds,
272
292
                                       self.start_checker))
273
293
        # Also start a new checker *right now*.
274
294
        self.start_checker()
275
295
        # Schedule a disable() when 'timeout' has passed
276
296
        self.disable_initiator_tag = (gobject.timeout_add
277
 
                                   (self.timeout_milliseconds(),
 
297
                                   (self._timeout_milliseconds,
278
298
                                    self.disable))
279
299
        self.enabled = True
280
 
        if self.use_dbus:
281
 
            # Emit D-Bus signals
282
 
            self.PropertyChanged(dbus.String(u"enabled"),
283
 
                                 dbus.Boolean(True, variant_level=1))
284
 
            self.PropertyChanged(dbus.String(u"last_enabled"),
285
 
                                 (_datetime_to_dbus(self.last_enabled,
286
 
                                                    variant_level=1)))
 
300
        # Emit D-Bus signal
 
301
        self.PropertyChanged(dbus.String(u"enabled"),
 
302
                             dbus.Boolean(True, variant_level=1))
 
303
        self.PropertyChanged(dbus.String(u"last_enabled"),
 
304
                             (_datetime_to_dbus(self.last_enabled,
 
305
                                                variant_level=1)))
287
306
    
288
307
    def disable(self):
289
308
        """Disable this client."""
300
319
        if self.disable_hook:
301
320
            self.disable_hook(self)
302
321
        self.enabled = False
303
 
        if self.use_dbus:
304
 
            # Emit D-Bus signal
305
 
            self.PropertyChanged(dbus.String(u"enabled"),
306
 
                                 dbus.Boolean(False, variant_level=1))
 
322
        # Emit D-Bus signal
 
323
        self.PropertyChanged(dbus.String(u"enabled"),
 
324
                             dbus.Boolean(False, variant_level=1))
307
325
        # Do not run this again if called by a gobject.timeout_add
308
326
        return False
309
327
    
315
333
        """The checker has completed, so take appropriate actions."""
316
334
        self.checker_callback_tag = None
317
335
        self.checker = None
318
 
        if self.use_dbus:
319
 
            # Emit D-Bus signal
320
 
            self.PropertyChanged(dbus.String(u"checker_running"),
321
 
                                 dbus.Boolean(False, variant_level=1))
 
336
        # Emit D-Bus signal
 
337
        self.PropertyChanged(dbus.String(u"checker_running"),
 
338
                             dbus.Boolean(False, variant_level=1))
322
339
        if (os.WIFEXITED(condition)
323
340
            and (os.WEXITSTATUS(condition) == 0)):
324
341
            logger.info(u"Checker for %(name)s succeeded",
325
342
                        vars(self))
326
 
            if self.use_dbus:
327
 
                # Emit D-Bus signal
328
 
                self.CheckerCompleted(dbus.Boolean(True),
329
 
                                      dbus.UInt16(condition),
330
 
                                      dbus.String(command))
 
343
            # Emit D-Bus signal
 
344
            self.CheckerCompleted(dbus.Boolean(True),
 
345
                                  dbus.UInt16(condition),
 
346
                                  dbus.String(command))
331
347
            self.bump_timeout()
332
348
        elif not os.WIFEXITED(condition):
333
349
            logger.warning(u"Checker for %(name)s crashed?",
334
350
                           vars(self))
335
 
            if self.use_dbus:
336
 
                # Emit D-Bus signal
337
 
                self.CheckerCompleted(dbus.Boolean(False),
338
 
                                      dbus.UInt16(condition),
339
 
                                      dbus.String(command))
 
351
            # Emit D-Bus signal
 
352
            self.CheckerCompleted(dbus.Boolean(False),
 
353
                                  dbus.UInt16(condition),
 
354
                                  dbus.String(command))
340
355
        else:
341
356
            logger.info(u"Checker for %(name)s failed",
342
357
                        vars(self))
343
 
            if self.use_dbus:
344
 
                # Emit D-Bus signal
345
 
                self.CheckerCompleted(dbus.Boolean(False),
346
 
                                      dbus.UInt16(condition),
347
 
                                      dbus.String(command))
 
358
            # Emit D-Bus signal
 
359
            self.CheckerCompleted(dbus.Boolean(False),
 
360
                                  dbus.UInt16(condition),
 
361
                                  dbus.String(command))
348
362
    
349
363
    def bump_timeout(self):
350
364
        """Bump up the timeout for this client.
354
368
        self.last_checked_ok = datetime.datetime.utcnow()
355
369
        gobject.source_remove(self.disable_initiator_tag)
356
370
        self.disable_initiator_tag = (gobject.timeout_add
357
 
                                      (self.timeout_milliseconds(),
 
371
                                      (self._timeout_milliseconds,
358
372
                                       self.disable))
359
 
        if self.use_dbus:
360
 
            # Emit D-Bus signal
361
 
            self.PropertyChanged(
362
 
                dbus.String(u"last_checked_ok"),
363
 
                (_datetime_to_dbus(self.last_checked_ok,
364
 
                                   variant_level=1)))
 
373
        self.PropertyChanged(dbus.String(u"last_checked_ok"),
 
374
                             (_datetime_to_dbus(self.last_checked_ok,
 
375
                                                variant_level=1)))
365
376
    
366
377
    def start_checker(self):
367
378
        """Start a new checker subprocess if one is not running.
400
411
                self.checker = subprocess.Popen(command,
401
412
                                                close_fds=True,
402
413
                                                shell=True, cwd="/")
403
 
                if self.use_dbus:
404
 
                    # Emit D-Bus signal
405
 
                    self.CheckerStarted(command)
406
 
                    self.PropertyChanged(
407
 
                        dbus.String("checker_running"),
408
 
                        dbus.Boolean(True, variant_level=1))
 
414
                # Emit D-Bus signal
 
415
                self.CheckerStarted(command)
 
416
                self.PropertyChanged(dbus.String("checker_running"),
 
417
                                     dbus.Boolean(True, variant_level=1))
409
418
                self.checker_callback_tag = (gobject.child_watch_add
410
419
                                             (self.checker.pid,
411
420
                                              self.checker_callback,
433
442
            if error.errno != errno.ESRCH: # No such process
434
443
                raise
435
444
        self.checker = None
436
 
        if self.use_dbus:
437
 
            self.PropertyChanged(dbus.String(u"checker_running"),
438
 
                                 dbus.Boolean(False, variant_level=1))
 
445
        self.PropertyChanged(dbus.String(u"checker_running"),
 
446
                             dbus.Boolean(False, variant_level=1))
439
447
    
440
448
    def still_valid(self):
441
449
        """Has the timeout not yet passed for this client?"""
492
500
                     if self.last_checked_ok is not None
493
501
                     else dbus.Boolean (False, variant_level=1)),
494
502
                dbus.String("timeout"):
495
 
                    dbus.UInt64(self.timeout_milliseconds(),
 
503
                    dbus.UInt64(self._timeout_milliseconds,
496
504
                                variant_level=1),
497
505
                dbus.String("interval"):
498
 
                    dbus.UInt64(self.interval_milliseconds(),
 
506
                    dbus.UInt64(self._interval_milliseconds,
499
507
                                variant_level=1),
500
508
                dbus.String("checker"):
501
509
                    dbus.String(self.checker_command,
521
529
    def SetChecker(self, checker):
522
530
        "D-Bus setter method"
523
531
        self.checker_command = checker
524
 
        # Emit D-Bus signal
525
 
        self.PropertyChanged(dbus.String(u"checker"),
526
 
                             dbus.String(self.checker_command,
527
 
                                         variant_level=1))
528
532
    
529
533
    # SetHost - method
530
534
    @dbus.service.method(_interface, in_signature="s")
531
535
    def SetHost(self, host):
532
536
        "D-Bus setter method"
533
537
        self.host = host
534
 
        # Emit D-Bus signal
535
 
        self.PropertyChanged(dbus.String(u"host"),
536
 
                             dbus.String(self.host, variant_level=1))
537
538
    
538
539
    # SetInterval - method
539
540
    @dbus.service.method(_interface, in_signature="t")
540
541
    def SetInterval(self, milliseconds):
541
 
        self.interval = datetime.timedelta(0, 0, 0, milliseconds)
542
 
        # Emit D-Bus signal
543
 
        self.PropertyChanged(dbus.String(u"interval"),
544
 
                             (dbus.UInt64(self.interval_milliseconds(),
545
 
                                          variant_level=1)))
 
542
        self.interval = datetime.timdeelta(0, 0, 0, milliseconds)
546
543
    
547
544
    # SetSecret - method
548
545
    @dbus.service.method(_interface, in_signature="ay",
555
552
    @dbus.service.method(_interface, in_signature="t")
556
553
    def SetTimeout(self, milliseconds):
557
554
        self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
558
 
        # Emit D-Bus signal
559
 
        self.PropertyChanged(dbus.String(u"timeout"),
560
 
                             (dbus.UInt64(self.timeout_milliseconds(),
561
 
                                          variant_level=1)))
562
555
    
563
556
    # Enable - method
564
557
    Enable = dbus.service.method(_interface)(enable)
840
833
    elif state == avahi.ENTRY_GROUP_FAILURE:
841
834
        logger.critical(u"Avahi: Error in group state changed %s",
842
835
                        unicode(error))
843
 
        raise AvahiGroupError(u"State changed: %s" % unicode(error))
 
836
        raise AvahiGroupError("State changed: %s", str(error))
844
837
 
845
838
def if_nametoindex(interface):
846
839
    """Call the C function if_nametoindex(), or equivalent"""
889
882
 
890
883
 
891
884
def main():
892
 
    parser = optparse.OptionParser(version = "%%prog %s" % version)
 
885
    parser = OptionParser(version = "%%prog %s" % version)
893
886
    parser.add_option("-i", "--interface", type="string",
894
887
                      metavar="IF", help="Bind to interface IF")
895
888
    parser.add_option("-a", "--address", type="string",
896
889
                      help="Address to listen for requests on")
897
890
    parser.add_option("-p", "--port", type="int",
898
891
                      help="Port number to receive requests on")
899
 
    parser.add_option("--check", action="store_true",
 
892
    parser.add_option("--check", action="store_true", default=False,
900
893
                      help="Run self-test")
901
894
    parser.add_option("--debug", action="store_true",
902
895
                      help="Debug mode; run in foreground and log to"
909
902
                      default="/etc/mandos", metavar="DIR",
910
903
                      help="Directory to search for configuration"
911
904
                      " files")
912
 
    parser.add_option("--no-dbus", action="store_false",
913
 
                      dest="use_dbus",
914
 
                      help="Do not provide D-Bus system bus"
915
 
                      " interface")
916
905
    options = parser.parse_args()[0]
917
906
    
918
907
    if options.check:
928
917
                        "priority":
929
918
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
930
919
                        "servicename": "Mandos",
931
 
                        "use_dbus": "True",
932
920
                        }
933
921
    
934
922
    # Parse config file for server-global settings
937
925
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
938
926
    # Convert the SafeConfigParser object to a dict
939
927
    server_settings = server_config.defaults()
940
 
    # Use getboolean on the boolean config options
 
928
    # Use getboolean on the boolean config option
941
929
    server_settings["debug"] = (server_config.getboolean
942
930
                                ("DEFAULT", "debug"))
943
 
    server_settings["use_dbus"] = (server_config.getboolean
944
 
                                   ("DEFAULT", "use_dbus"))
945
931
    del server_config
946
932
    
947
933
    # Override the settings from the config file with command line
948
934
    # options, if set.
949
935
    for option in ("interface", "address", "port", "debug",
950
 
                   "priority", "servicename", "configdir",
951
 
                   "use_dbus"):
 
936
                   "priority", "servicename", "configdir"):
952
937
        value = getattr(options, option)
953
938
        if value is not None:
954
939
            server_settings[option] = value
955
940
    del options
956
941
    # Now we have our good server settings in "server_settings"
957
942
    
958
 
    # For convenience
959
943
    debug = server_settings["debug"]
960
 
    use_dbus = server_settings["use_dbus"]
961
944
    
962
945
    if not debug:
963
946
        syslogger.setLevel(logging.WARNING)
972
955
    # Parse config file with clients
973
956
    client_defaults = { "timeout": "1h",
974
957
                        "interval": "5m",
975
 
                        "checker": "fping -q -- %%(host)s",
 
958
                        "checker": "fping -q -- %(host)s",
976
959
                        "host": "",
977
960
                        }
978
961
    client_config = ConfigParser.SafeConfigParser(client_defaults)
993
976
    
994
977
    try:
995
978
        uid = pwd.getpwnam("_mandos").pw_uid
 
979
    except KeyError:
 
980
        try:
 
981
            uid = pwd.getpwnam("mandos").pw_uid
 
982
        except KeyError:
 
983
            try:
 
984
                uid = pwd.getpwnam("nobody").pw_uid
 
985
            except KeyError:
 
986
                uid = 65534
 
987
    try:
996
988
        gid = pwd.getpwnam("_mandos").pw_gid
997
989
    except KeyError:
998
990
        try:
999
 
            uid = pwd.getpwnam("mandos").pw_uid
1000
991
            gid = pwd.getpwnam("mandos").pw_gid
1001
992
        except KeyError:
1002
993
            try:
1003
 
                uid = pwd.getpwnam("nobody").pw_uid
1004
994
                gid = pwd.getpwnam("nogroup").pw_gid
1005
995
            except KeyError:
1006
 
                uid = 65534
1007
996
                gid = 65534
1008
997
    try:
1009
998
        os.setuid(uid)
1030
1019
                                           avahi.DBUS_PATH_SERVER),
1031
1020
                            avahi.DBUS_INTERFACE_SERVER)
1032
1021
    # End of Avahi example code
1033
 
    if use_dbus:
1034
 
        bus_name = dbus.service.BusName(u"org.mandos-system.Mandos",
1035
 
                                        bus)
 
1022
    bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus)
1036
1023
    
1037
1024
    clients.update(Set(Client(name = section,
1038
1025
                              config
1039
 
                              = dict(client_config.items(section)),
1040
 
                              use_dbus = use_dbus)
 
1026
                              = dict(client_config.items(section)))
1041
1027
                       for section in client_config.sections()))
1042
1028
    if not clients:
1043
 
        logger.warning(u"No clients defined")
 
1029
        logger.critical(u"No clients defined")
 
1030
        sys.exit(1)
1044
1031
    
1045
1032
    if debug:
1046
1033
        # Redirect stdin so all checkers get /dev/null
1088
1075
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1089
1076
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1090
1077
    
1091
 
    if use_dbus:
1092
 
        class MandosServer(dbus.service.Object):
1093
 
            """A D-Bus proxy object"""
1094
 
            def __init__(self):
1095
 
                dbus.service.Object.__init__(self, bus,
1096
 
                                             "/Mandos")
1097
 
            _interface = u"org.mandos_system.Mandos"
1098
 
 
1099
 
            @dbus.service.signal(_interface, signature="oa{sv}")
1100
 
            def ClientAdded(self, objpath, properties):
1101
 
                "D-Bus signal"
1102
 
                pass
1103
 
 
1104
 
            @dbus.service.signal(_interface, signature="o")
1105
 
            def ClientRemoved(self, objpath):
1106
 
                "D-Bus signal"
1107
 
                pass
1108
 
 
1109
 
            @dbus.service.method(_interface, out_signature="ao")
1110
 
            def GetAllClients(self):
1111
 
                return dbus.Array(c.dbus_object_path for c in clients)
1112
 
 
1113
 
            @dbus.service.method(_interface, out_signature="a{oa{sv}}")
1114
 
            def GetAllClientsWithProperties(self):
1115
 
                return dbus.Dictionary(
1116
 
                    ((c.dbus_object_path, c.GetAllProperties())
1117
 
                     for c in clients),
1118
 
                    signature="oa{sv}")
1119
 
 
1120
 
            @dbus.service.method(_interface, in_signature="o")
1121
 
            def RemoveClient(self, object_path):
1122
 
                for c in clients:
1123
 
                    if c.dbus_object_path == object_path:
1124
 
                        clients.remove(c)
1125
 
                        # Don't signal anything except ClientRemoved
1126
 
                        c.use_dbus = False
1127
 
                        c.disable()
1128
 
                        # Emit D-Bus signal
1129
 
                        self.ClientRemoved(object_path)
1130
 
                        return
1131
 
                raise KeyError
1132
 
            @dbus.service.method(_interface)
1133
 
            def Quit(self):
1134
 
                main_loop.quit()
1135
 
 
1136
 
            del _interface
 
1078
    class MandosServer(dbus.service.Object):
 
1079
        """A D-Bus proxy object"""
 
1080
        def __init__(self):
 
1081
            dbus.service.Object.__init__(self, bus,
 
1082
                                         "/Mandos")
 
1083
        _interface = u"org.mandos_system.Mandos"
 
1084
        
 
1085
        @dbus.service.signal(_interface, signature="oa{sv}")
 
1086
        def ClientAdded(self, objpath, properties):
 
1087
            "D-Bus signal"
 
1088
            pass
 
1089
        
 
1090
        @dbus.service.signal(_interface, signature="o")
 
1091
        def ClientRemoved(self, objpath):
 
1092
            "D-Bus signal"
 
1093
            pass
 
1094
        
 
1095
        @dbus.service.method(_interface, out_signature="ao")
 
1096
        def GetAllClients(self):
 
1097
            return dbus.Array(c.dbus_object_path for c in clients)
 
1098
        
 
1099
        @dbus.service.method(_interface, out_signature="a{oa{sv}}")
 
1100
        def GetAllClientsWithProperties(self):
 
1101
            return dbus.Dictionary(
 
1102
                ((c.dbus_object_path, c.GetAllProperties())
 
1103
                 for c in clients),
 
1104
                signature="oa{sv}")
 
1105
        
 
1106
        @dbus.service.method(_interface, in_signature="o")
 
1107
        def RemoveClient(self, object_path):
 
1108
            for c in clients:
 
1109
                if c.dbus_object_path == object_path:
 
1110
                    c.disable()
 
1111
                    clients.remove(c)
 
1112
                    return
 
1113
            raise KeyError
 
1114
        
 
1115
        del _interface
1137
1116
    
1138
 
        mandos_server = MandosServer()
 
1117
    mandos_server = MandosServer()
1139
1118
    
1140
1119
    for client in clients:
1141
 
        if use_dbus:
1142
 
            # Emit D-Bus signal
1143
 
            mandos_server.ClientAdded(client.dbus_object_path,
1144
 
                                      client.GetAllProperties())
 
1120
        # Emit D-Bus signal
 
1121
        mandos_server.ClientAdded(client.dbus_object_path,
 
1122
                                  client.GetAllProperties())
1145
1123
        client.enable()
1146
1124
    
1147
1125
    tcp_server.enable()
1172
1150
        logger.debug(u"Starting main loop")
1173
1151
        main_loop.run()
1174
1152
    except AvahiError, error:
1175
 
        logger.critical(u"AvahiError: %s", error)
 
1153
        logger.critical(u"AvahiError: %s" + unicode(error))
1176
1154
        sys.exit(1)
1177
1155
    except KeyboardInterrupt:
1178
1156
        if debug: