/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

merge

Show diffs side-by-side

added added

removed removed

Lines of Context:
170
170
# End of Avahi example code
171
171
 
172
172
 
173
 
def _datetime_to_dbus(dt, variant_level=0):
174
 
    """Convert a UTC datetime.datetime() to a D-Bus type."""
175
 
    return dbus.String(dt.isoformat(), variant_level=variant_level)
176
 
 
177
 
 
178
173
class Client(dbus.service.Object):
179
174
    """A representation of a client host served by this server.
180
175
    Attributes:
181
 
    name:       string; from the config file, used in log messages
 
176
    name:      string; from the config file, used in log messages
182
177
    fingerprint: string (40 or 32 hexadecimal digits); used to
183
178
                 uniquely identify the client
184
 
    secret:     bytestring; sent verbatim (over TLS) to client
185
 
    host:       string; available for use by the checker command
186
 
    created:    datetime.datetime(); (UTC) object creation
187
 
    last_enabled: datetime.datetime(); (UTC)
188
 
    enabled:    bool()
 
179
    secret:    bytestring; sent verbatim (over TLS) to client
 
180
    host:      string; available for use by the checker command
 
181
    created:   datetime.datetime(); (UTC) object creation
 
182
    started:   datetime.datetime(); (UTC) last started
189
183
    last_checked_ok: datetime.datetime(); (UTC) or None
190
 
    timeout:    datetime.timedelta(); How long from last_checked_ok
191
 
                                      until this client is invalid
192
 
    interval:   datetime.timedelta(); How often to start a new checker
193
 
    disable_hook:  If set, called by disable() as disable_hook(self)
194
 
    checker:    subprocess.Popen(); a running checker process used
195
 
                                    to see if the client lives.
196
 
                                    'None' if no process is running.
 
184
    timeout:   datetime.timedelta(); How long from last_checked_ok
 
185
                                     until this client is invalid
 
186
    interval:  datetime.timedelta(); How often to start a new checker
 
187
    stop_hook: If set, called by stop() as stop_hook(self)
 
188
    checker:   subprocess.Popen(); a running checker process used
 
189
                                   to see if the client lives.
 
190
                                   'None' if no process is running.
197
191
    checker_initiator_tag: a gobject event source tag, or None
198
 
    disable_initiator_tag:    - '' -
 
192
    stop_initiator_tag:    - '' -
199
193
    checker_callback_tag:  - '' -
200
194
    checker_command: string; External command which is run to check if
201
195
                     client lives.  %() expansions are done at
202
196
                     runtime with vars(self) as dict, so that for
203
197
                     instance %(name)s can be used in the command.
204
 
    dbus_object_path: dbus.ObjectPath
205
198
    Private attibutes:
206
199
    _timeout: Real variable for 'timeout'
207
200
    _interval: Real variable for 'interval'
217
210
                                      + (self.timeout.microseconds
218
211
                                         // 1000))
219
212
        # Emit D-Bus signal
220
 
        self.PropertyChanged(dbus.String(u"timeout"),
221
 
                             (dbus.UInt64(self._timeout_milliseconds,
222
 
                                          variant_level=1)))
 
213
        self.TimeoutChanged(self._timeout_milliseconds)
223
214
    timeout = property(lambda self: self._timeout, _set_timeout)
224
215
    del _set_timeout
225
216
    
233
224
                                       + (self.interval.microseconds
234
225
                                          // 1000))
235
226
        # Emit D-Bus signal
236
 
        self.PropertyChanged(dbus.String(u"interval"),
237
 
                             (dbus.UInt64(self._interval_milliseconds,
238
 
                                          variant_level=1)))
 
227
        self.IntervalChanged(self._interval_milliseconds)
239
228
    interval = property(lambda self: self._interval, _set_interval)
240
229
    del _set_interval
241
230
    
242
 
    def __init__(self, name = None, disable_hook=None, config=None):
 
231
    def __init__(self, name = None, stop_hook=None, config=None):
243
232
        """Note: the 'checker' key in 'config' sets the
244
233
        'checker_command' attribute and *not* the 'checker'
245
234
        attribute."""
246
 
        self.dbus_object_path = (dbus.ObjectPath
247
 
                                 ("/Mandos/clients/"
248
 
                                  + name.replace(".", "_")))
249
235
        dbus.service.Object.__init__(self, bus,
250
 
                                     self.dbus_object_path)
 
236
                                     "/Mandos/clients/%s"
 
237
                                     % name.replace(".", "_"))
251
238
        if config is None:
252
239
            config = {}
253
240
        self.name = name
270
257
                            % self.name)
271
258
        self.host = config.get("host", "")
272
259
        self.created = datetime.datetime.utcnow()
273
 
        self.enabled = False
274
 
        self.last_enabled = None
 
260
        self.started = None
275
261
        self.last_checked_ok = None
276
262
        self.timeout = string_to_delta(config["timeout"])
277
263
        self.interval = string_to_delta(config["interval"])
278
 
        self.disable_hook = disable_hook
 
264
        self.stop_hook = stop_hook
279
265
        self.checker = None
280
266
        self.checker_initiator_tag = None
281
 
        self.disable_initiator_tag = None
 
267
        self.stop_initiator_tag = None
282
268
        self.checker_callback_tag = None
283
 
        self.checker_command = config["checker"]
 
269
        self.check_command = config["checker"]
284
270
    
285
 
    def enable(self):
 
271
    def start(self):
286
272
        """Start this client's checker and timeout hooks"""
287
 
        self.last_enabled = datetime.datetime.utcnow()
 
273
        self.started = datetime.datetime.utcnow()
288
274
        # Schedule a new checker to be started an 'interval' from now,
289
275
        # and every interval from then on.
290
276
        self.checker_initiator_tag = (gobject.timeout_add
292
278
                                       self.start_checker))
293
279
        # Also start a new checker *right now*.
294
280
        self.start_checker()
295
 
        # Schedule a disable() when 'timeout' has passed
296
 
        self.disable_initiator_tag = (gobject.timeout_add
 
281
        # Schedule a stop() when 'timeout' has passed
 
282
        self.stop_initiator_tag = (gobject.timeout_add
297
283
                                   (self._timeout_milliseconds,
298
 
                                    self.disable))
299
 
        self.enabled = True
 
284
                                    self.stop))
300
285
        # 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)))
 
286
        self.StateChanged(True)
306
287
    
307
 
    def disable(self):
308
 
        """Disable this client."""
309
 
        if not getattr(self, "enabled", False):
 
288
    def stop(self):
 
289
        """Stop this client."""
 
290
        if getattr(self, "started", None) is not None:
 
291
            logger.info(u"Stopping client %s", self.name)
 
292
        else:
310
293
            return False
311
 
        logger.info(u"Disabling client %s", self.name)
312
 
        if getattr(self, "disable_initiator_tag", False):
313
 
            gobject.source_remove(self.disable_initiator_tag)
314
 
            self.disable_initiator_tag = None
 
294
        if getattr(self, "stop_initiator_tag", False):
 
295
            gobject.source_remove(self.stop_initiator_tag)
 
296
            self.stop_initiator_tag = None
315
297
        if getattr(self, "checker_initiator_tag", False):
316
298
            gobject.source_remove(self.checker_initiator_tag)
317
299
            self.checker_initiator_tag = None
318
300
        self.stop_checker()
319
 
        if self.disable_hook:
320
 
            self.disable_hook(self)
321
 
        self.enabled = False
 
301
        if self.stop_hook:
 
302
            self.stop_hook(self)
 
303
        self.started = None
322
304
        # Emit D-Bus signal
323
 
        self.PropertyChanged(dbus.String(u"enabled"),
324
 
                             dbus.Boolean(False, variant_level=1))
 
305
        self.StateChanged(False)
325
306
        # Do not run this again if called by a gobject.timeout_add
326
307
        return False
327
308
    
328
309
    def __del__(self):
329
 
        self.disable_hook = None
330
 
        self.disable()
 
310
        self.stop_hook = None
 
311
        self.stop()
331
312
    
332
 
    def checker_callback(self, pid, condition, command):
 
313
    def checker_callback(self, pid, condition):
333
314
        """The checker has completed, so take appropriate actions."""
334
315
        self.checker_callback_tag = None
335
316
        self.checker = None
336
 
        # Emit D-Bus signal
337
 
        self.PropertyChanged(dbus.String(u"checker_running"),
338
 
                             dbus.Boolean(False, variant_level=1))
339
 
        if (os.WIFEXITED(condition)
 
317
        if (os.WIFEXITED(condition) 
340
318
            and (os.WEXITSTATUS(condition) == 0)):
341
319
            logger.info(u"Checker for %(name)s succeeded",
342
320
                        vars(self))
343
321
            # Emit D-Bus signal
344
 
            self.CheckerCompleted(dbus.Boolean(True),
345
 
                                  dbus.UInt16(condition),
346
 
                                  dbus.String(command))
 
322
            self.CheckerCompleted(True)
347
323
            self.bump_timeout()
348
324
        elif not os.WIFEXITED(condition):
349
325
            logger.warning(u"Checker for %(name)s crashed?",
350
326
                           vars(self))
351
327
            # Emit D-Bus signal
352
 
            self.CheckerCompleted(dbus.Boolean(False),
353
 
                                  dbus.UInt16(condition),
354
 
                                  dbus.String(command))
 
328
            self.CheckerCompleted(False)
355
329
        else:
356
330
            logger.info(u"Checker for %(name)s failed",
357
331
                        vars(self))
358
332
            # Emit D-Bus signal
359
 
            self.CheckerCompleted(dbus.Boolean(False),
360
 
                                  dbus.UInt16(condition),
361
 
                                  dbus.String(command))
 
333
            self.CheckerCompleted(False)
362
334
    
363
335
    def bump_timeout(self):
364
336
        """Bump up the timeout for this client.
366
338
        alive and well.
367
339
        """
368
340
        self.last_checked_ok = datetime.datetime.utcnow()
369
 
        gobject.source_remove(self.disable_initiator_tag)
370
 
        self.disable_initiator_tag = (gobject.timeout_add
371
 
                                      (self._timeout_milliseconds,
372
 
                                       self.disable))
373
 
        self.PropertyChanged(dbus.String(u"last_checked_ok"),
374
 
                             (_datetime_to_dbus(self.last_checked_ok,
375
 
                                                variant_level=1)))
 
341
        gobject.source_remove(self.stop_initiator_tag)
 
342
        self.stop_initiator_tag = (gobject.timeout_add
 
343
                                   (self._timeout_milliseconds,
 
344
                                    self.stop))
376
345
    
377
346
    def start_checker(self):
378
347
        """Start a new checker subprocess if one is not running.
388
357
        # is as it should be.
389
358
        if self.checker is None:
390
359
            try:
391
 
                # In case checker_command has exactly one % operator
392
 
                command = self.checker_command % self.host
 
360
                # In case check_command has exactly one % operator
 
361
                command = self.check_command % self.host
393
362
            except TypeError:
394
363
                # Escape attributes for the shell
395
364
                escaped_attrs = dict((key, re.escape(str(val)))
396
365
                                     for key, val in
397
366
                                     vars(self).iteritems())
398
367
                try:
399
 
                    command = self.checker_command % escaped_attrs
 
368
                    command = self.check_command % escaped_attrs
400
369
                except TypeError, error:
401
370
                    logger.error(u'Could not format string "%s":'
402
 
                                 u' %s', self.checker_command, error)
 
371
                                 u' %s', self.check_command, error)
403
372
                    return True # Try again later
404
373
            try:
405
374
                logger.info(u"Starting checker %r for %s",
411
380
                self.checker = subprocess.Popen(command,
412
381
                                                close_fds=True,
413
382
                                                shell=True, cwd="/")
 
383
                self.checker_callback_tag = (gobject.child_watch_add
 
384
                                             (self.checker.pid,
 
385
                                              self.checker_callback))
414
386
                # Emit D-Bus signal
415
387
                self.CheckerStarted(command)
416
 
                self.PropertyChanged(dbus.String("checker_running"),
417
 
                                     dbus.Boolean(True, variant_level=1))
418
 
                self.checker_callback_tag = (gobject.child_watch_add
419
 
                                             (self.checker.pid,
420
 
                                              self.checker_callback,
421
 
                                              data=command))
422
388
            except OSError, error:
423
389
                logger.error(u"Failed to start subprocess: %s",
424
390
                             error)
442
408
            if error.errno != errno.ESRCH: # No such process
443
409
                raise
444
410
        self.checker = None
445
 
        self.PropertyChanged(dbus.String(u"checker_running"),
446
 
                             dbus.Boolean(False, variant_level=1))
447
411
    
448
412
    def still_valid(self):
449
413
        """Has the timeout not yet passed for this client?"""
450
 
        if not getattr(self, "enabled", False):
 
414
        if not self.started:
451
415
            return False
452
416
        now = datetime.datetime.utcnow()
453
417
        if self.last_checked_ok is None:
458
422
    ## D-Bus methods & signals
459
423
    _interface = u"org.mandos_system.Mandos.Client"
460
424
    
 
425
    def _datetime_to_dbus_struct(dt):
 
426
        return dbus.Struct(dt.year, dt.month, dt.day, dt.hour,
 
427
                           dt.minute, dt.second, dt.microsecond,
 
428
                           signature="nyyyyyu")
 
429
    
461
430
    # BumpTimeout - method
462
431
    BumpTimeout = dbus.service.method(_interface)(bump_timeout)
463
432
    BumpTimeout.__name__ = "BumpTimeout"
464
433
    
 
434
    # IntervalChanged - signal
 
435
    @dbus.service.signal(_interface, signature="t")
 
436
    def IntervalChanged(self, t):
 
437
        "D-Bus signal"
 
438
        pass
 
439
    
465
440
    # CheckerCompleted - signal
466
 
    @dbus.service.signal(_interface, signature="bqs")
467
 
    def CheckerCompleted(self, success, condition, command):
 
441
    @dbus.service.signal(_interface, signature="b")
 
442
    def CheckerCompleted(self, success):
468
443
        "D-Bus signal"
469
444
        pass
470
445
    
 
446
    # CheckerIsRunning - method
 
447
    @dbus.service.method(_interface, out_signature="b")
 
448
    def CheckerIsRunning(self):
 
449
        "D-Bus getter method"
 
450
        return self.checker is not None
 
451
    
471
452
    # CheckerStarted - signal
472
453
    @dbus.service.signal(_interface, signature="s")
473
454
    def CheckerStarted(self, command):
474
455
        "D-Bus signal"
475
456
        pass
476
457
    
477
 
    # GetAllProperties - method
478
 
    @dbus.service.method(_interface, out_signature="a{sv}")
479
 
    def GetAllProperties(self):
480
 
        "D-Bus method"
481
 
        return dbus.Dictionary({
482
 
                dbus.String("name"):
483
 
                    dbus.String(self.name, variant_level=1),
484
 
                dbus.String("fingerprint"):
485
 
                    dbus.String(self.fingerprint, variant_level=1),
486
 
                dbus.String("host"):
487
 
                    dbus.String(self.host, variant_level=1),
488
 
                dbus.String("created"):
489
 
                    _datetime_to_dbus(self.created, variant_level=1),
490
 
                dbus.String("last_enabled"):
491
 
                    (_datetime_to_dbus(self.last_enabled,
492
 
                                       variant_level=1)
493
 
                     if self.last_enabled is not None
494
 
                     else dbus.Boolean(False, variant_level=1)),
495
 
                dbus.String("enabled"):
496
 
                    dbus.Boolean(self.enabled, variant_level=1),
497
 
                dbus.String("last_checked_ok"):
498
 
                    (_datetime_to_dbus(self.last_checked_ok,
499
 
                                       variant_level=1)
500
 
                     if self.last_checked_ok is not None
501
 
                     else dbus.Boolean (False, variant_level=1)),
502
 
                dbus.String("timeout"):
503
 
                    dbus.UInt64(self._timeout_milliseconds,
504
 
                                variant_level=1),
505
 
                dbus.String("interval"):
506
 
                    dbus.UInt64(self._interval_milliseconds,
507
 
                                variant_level=1),
508
 
                dbus.String("checker"):
509
 
                    dbus.String(self.checker_command,
510
 
                                variant_level=1),
511
 
                dbus.String("checker_running"):
512
 
                    dbus.Boolean(self.checker is not None,
513
 
                                 variant_level=1),
514
 
                }, signature="sv")
515
 
    
516
 
    # IsStillValid - method
517
 
    IsStillValid = (dbus.service.method(_interface, out_signature="b")
518
 
                    (still_valid))
519
 
    IsStillValid.__name__ = "IsStillValid"
520
 
    
521
 
    # PropertyChanged - signal
522
 
    @dbus.service.signal(_interface, signature="sv")
523
 
    def PropertyChanged(self, property, value):
524
 
        "D-Bus signal"
525
 
        pass
 
458
    # GetChecker - method
 
459
    @dbus.service.method(_interface, out_signature="s")
 
460
    def GetChecker(self):
 
461
        "D-Bus getter method"
 
462
        return self.checker_command
 
463
    
 
464
    # GetCreated - method
 
465
    @dbus.service.method(_interface, out_signature="(nyyyyyu)")
 
466
    def GetCreated(self):
 
467
        "D-Bus getter method"
 
468
        return datetime_to_dbus_struct(self.created)
 
469
    
 
470
    # GetFingerprint - method
 
471
    @dbus.service.method(_interface, out_signature="s")
 
472
    def GetFingerprint(self):
 
473
        "D-Bus getter method"
 
474
        return self.fingerprint
 
475
    
 
476
    # GetHost - method
 
477
    @dbus.service.method(_interface, out_signature="s")
 
478
    def GetHost(self):
 
479
        "D-Bus getter method"
 
480
        return self.host
 
481
    
 
482
    # GetInterval - method
 
483
    @dbus.service.method(_interface, out_signature="t")
 
484
    def GetInterval(self):
 
485
        "D-Bus getter method"
 
486
        return self._interval_milliseconds
 
487
    
 
488
    # GetName - method
 
489
    @dbus.service.method(_interface, out_signature="s")
 
490
    def GetName(self):
 
491
        "D-Bus getter method"
 
492
        return self.name
 
493
    
 
494
    # GetStarted - method
 
495
    @dbus.service.method(_interface, out_signature="(nyyyyyu)")
 
496
    def GetStarted(self):
 
497
        "D-Bus getter method"
 
498
        if self.started is not None:
 
499
            return datetime_to_dbus_struct(self.started)
 
500
        else:
 
501
            return dbus.Struct(0, 0, 0, 0, 0, 0, 0,
 
502
                               signature="nyyyyyu")
 
503
    
 
504
    # GetTimeout - method
 
505
    @dbus.service.method(_interface, out_signature="t")
 
506
    def GetTimeout(self):
 
507
        "D-Bus getter method"
 
508
        return self._timeout_milliseconds
526
509
    
527
510
    # SetChecker - method
528
511
    @dbus.service.method(_interface, in_signature="s")
541
524
    def SetInterval(self, milliseconds):
542
525
        self.interval = datetime.timdeelta(0, 0, 0, milliseconds)
543
526
    
 
527
    # SetTimeout - method
 
528
    @dbus.service.method(_interface, in_signature="t")
 
529
    def SetTimeout(self, milliseconds):
 
530
        self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
 
531
    
544
532
    # SetSecret - method
545
533
    @dbus.service.method(_interface, in_signature="ay",
546
534
                         byte_arrays=True)
548
536
        "D-Bus setter method"
549
537
        self.secret = str(secret)
550
538
    
551
 
    # SetTimeout - method
552
 
    @dbus.service.method(_interface, in_signature="t")
553
 
    def SetTimeout(self, milliseconds):
554
 
        self.timeout = datetime.timedelta(0, 0, 0, milliseconds)
555
 
    
556
 
    # Enable - method
557
 
    Enable = dbus.service.method(_interface)(enable)
558
 
    Enable.__name__ = "Enable"
 
539
    # Start - method
 
540
    Start = dbus.service.method(_interface)(start)
 
541
    Start.__name__ = "Start"
559
542
    
560
543
    # StartChecker - method
561
 
    @dbus.service.method(_interface)
562
 
    def StartChecker(self):
563
 
        "D-Bus method"
564
 
        self.start_checker()
565
 
    
566
 
    # Disable - method
567
 
    @dbus.service.method(_interface)
568
 
    def Disable(self):
569
 
        "D-Bus method"
570
 
        self.disable()
 
544
    StartChecker = dbus.service.method(_interface)(start_checker)
 
545
    StartChecker.__name__ = "StartChecker"
 
546
    
 
547
    # StateChanged - signal
 
548
    @dbus.service.signal(_interface, signature="b")
 
549
    def StateChanged(self, started):
 
550
        "D-Bus signal"
 
551
        pass
 
552
    
 
553
    # StillValid - method
 
554
    StillValid = (dbus.service.method(_interface, out_signature="b")
 
555
                  (still_valid))
 
556
    StillValid.__name__ = "StillValid"
 
557
    
 
558
    # Stop - method
 
559
    Stop = dbus.service.method(_interface)(stop)
 
560
    Stop.__name__ = "Stop"
571
561
    
572
562
    # StopChecker - method
573
563
    StopChecker = dbus.service.method(_interface)(stop_checker)
574
564
    StopChecker.__name__ = "StopChecker"
575
565
    
 
566
    # TimeoutChanged - signal
 
567
    @dbus.service.signal(_interface, signature="t")
 
568
    def TimeoutChanged(self, t):
 
569
        "D-Bus signal"
 
570
        pass
 
571
    
 
572
    del _datetime_to_dbus_struct
576
573
    del _interface
577
574
 
578
575
 
974
971
    except IOError, error:
975
972
        logger.error("Could not open file %r", pidfilename)
976
973
    
977
 
    try:
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:
988
 
        gid = pwd.getpwnam("_mandos").pw_gid
989
 
    except KeyError:
990
 
        try:
991
 
            gid = pwd.getpwnam("mandos").pw_gid
992
 
        except KeyError:
993
 
            try:
994
 
                gid = pwd.getpwnam("nogroup").pw_gid
995
 
            except KeyError:
996
 
                gid = 65534
 
974
    uid = 65534
 
975
    gid = 65534
 
976
    try:
 
977
        uid = pwd.getpwnam("mandos").pw_uid
 
978
    except KeyError:
 
979
        try:
 
980
            uid = pwd.getpwnam("nobody").pw_uid
 
981
        except KeyError:
 
982
            pass
 
983
    try:
 
984
        gid = pwd.getpwnam("mandos").pw_gid
 
985
    except KeyError:
 
986
        try:
 
987
            gid = pwd.getpwnam("nogroup").pw_gid
 
988
        except KeyError:
 
989
            pass
997
990
    try:
998
991
        os.setuid(uid)
999
992
        os.setgid(gid)
1021
1014
    # End of Avahi example code
1022
1015
    bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus)
1023
1016
    
 
1017
    def remove_from_clients(client):
 
1018
        clients.remove(client)
 
1019
        if not clients:
 
1020
            logger.critical(u"No clients left, exiting")
 
1021
            sys.exit()
 
1022
    
1024
1023
    clients.update(Set(Client(name = section,
 
1024
                              stop_hook = remove_from_clients,
1025
1025
                              config
1026
1026
                              = dict(client_config.items(section)))
1027
1027
                       for section in client_config.sections()))
1065
1065
        
1066
1066
        while clients:
1067
1067
            client = clients.pop()
1068
 
            client.disable_hook = None
1069
 
            client.disable()
 
1068
            client.stop_hook = None
 
1069
            client.stop()
1070
1070
    
1071
1071
    atexit.register(cleanup)
1072
1072
    
1075
1075
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1076
1076
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1077
1077
    
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
1116
 
    
1117
 
    mandos_server = MandosServer()
1118
 
    
1119
1078
    for client in clients:
1120
 
        # Emit D-Bus signal
1121
 
        mandos_server.ClientAdded(client.dbus_object_path,
1122
 
                                  client.GetAllProperties())
1123
 
        client.enable()
 
1079
        client.start()
1124
1080
    
1125
1081
    tcp_server.enable()
1126
1082
    tcp_server.server_activate()