/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-10 01:26:02 UTC
  • mfrom: (237.1.2 mandos)
  • Revision ID: teddy@fukt.bsnet.se-20081210012602-vhz3h75xkj24t340
First version of a somewhat complete D-Bus server interface.  Also
change user/group name to "_mandos".

* debian/mandos.postinst: Rename old "mandos" user and group to
                          "_mandos"; create "_mandos" user and group
                          if none exist.
* debian/mandos-client.postinst: - '' -

* initramfs-tools-hook: Try "_mandos" before "mandos" as user and
                        group name.

* mandos (_datetime_to_dbus_struct): New; was previously local.
  (Client.started): Renamed to "last_started".  All users changed.
  (Client.started): New; boolean.
  (Client.dbus_object_path): New.
  (Client.check_command): Renamed to "checker_command".  All users
                          changed.
  (Client.__init__): Set and use "self.dbus_object_path".  Set
                     "self.started".
  (Client.start): Update "self.started".  Emit "self.PropertyChanged"
                  signals for both "started" and "last_started".
  (Client.stop): Update "self.started".  Emit "self.PropertyChanged"
                 signal for "started".
  (Client.checker_callback): Take additional "command" argument.  All
                             callers changed. Emit
                             "self.PropertyChanged" signal.
  (Client.bump_timeout): Emit "self.PropertyChanged" signal for
                         "last_checked_ok".
  (Client.start_checker): Emit "self.PropertyChanged" signal for
                          "checker_running".
  (Client.stop_checker): Emit "self.PropertyChanged" signal for
                         "checker_running".
  (Client.still_valid): Bug fix: use "getattr(self, started, False)"
                        instead of "self.started" in case this client
                        object is so new that the "started" attribute
                        has not been created yet.
  (Client.IntervalChanged, Client.CheckerIsRunning, Client.GetChecker,
  Client.GetCreated, Client.GetFingerprint, Client.GetHost,
  Client.GetInterval, Client.GetName, Client.GetStarted,
  Client.GetTimeout, Client.StateChanged, Client.TimeoutChanged):
  Removed; all callers changed.
  (Client.CheckerCompleted): Add "condition" and "command" arguments.
                             All callers changed.
  (Client.GetAllProperties, Client.PropertyChanged): New.
  (Client.StillValid): Renamed to "IsStillValid".
  (Client.StartChecker): Changed to its own function to avoid the
                         return value from "Client.start_checker()".
  (Client.Stop): Changed to its own function to avoid the return value
                 from "Client.stop()".
  (main): Try "_mandos" before "mandos" as user and group name.
          Removed inner function "remove_from_clients".  New inner
          class "MandosServer".

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
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))
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)
 
173
def _datetime_to_dbus_struct(dt, variant_level=0):
 
174
    """Convert a UTC datetime.datetime() to a D-Bus struct.
 
175
    The format is special to this application, since we could not find
 
176
    any other standard way."""
 
177
    return dbus.Struct((dbus.Int16(dt.year),
 
178
                        dbus.Byte(dt.month),
 
179
                        dbus.Byte(dt.day),
 
180
                        dbus.Byte(dt.hour),
 
181
                        dbus.Byte(dt.minute),
 
182
                        dbus.Byte(dt.second),
 
183
                        dbus.UInt32(dt.microsecond)),
 
184
                       signature="nyyyyyu",
 
185
                       variant_level=variant_level)
176
186
 
177
187
 
178
188
class Client(dbus.service.Object):
184
194
    secret:     bytestring; sent verbatim (over TLS) to client
185
195
    host:       string; available for use by the checker command
186
196
    created:    datetime.datetime(); (UTC) object creation
187
 
    last_enabled: datetime.datetime(); (UTC)
188
 
    enabled:    bool()
 
197
    last_started: datetime.datetime(); (UTC)
 
198
    started:    bool()
189
199
    last_checked_ok: datetime.datetime(); (UTC) or None
190
200
    timeout:    datetime.timedelta(); How long from last_checked_ok
191
201
                                      until this client is invalid
192
202
    interval:   datetime.timedelta(); How often to start a new checker
193
 
    disable_hook:  If set, called by disable() as disable_hook(self)
 
203
    stop_hook:  If set, called by stop() as stop_hook(self)
194
204
    checker:    subprocess.Popen(); a running checker process used
195
205
                                    to see if the client lives.
196
206
                                    'None' if no process is running.
197
207
    checker_initiator_tag: a gobject event source tag, or None
198
 
    disable_initiator_tag:    - '' -
 
208
    stop_initiator_tag:    - '' -
199
209
    checker_callback_tag:  - '' -
200
210
    checker_command: string; External command which is run to check if
201
211
                     client lives.  %() expansions are done at
202
212
                     runtime with vars(self) as dict, so that for
203
213
                     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
 
214
    dbus_object_path: dbus.ObjectPath
 
215
    Private attibutes:
 
216
    _timeout: Real variable for 'timeout'
 
217
    _interval: Real variable for 'interval'
 
218
    _timeout_milliseconds: Used when calling gobject.timeout_add()
 
219
    _interval_milliseconds: - '' -
206
220
    """
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):
 
221
    def _set_timeout(self, timeout):
 
222
        "Setter function for the 'timeout' attribute"
 
223
        self._timeout = timeout
 
224
        self._timeout_milliseconds = ((self.timeout.days
 
225
                                       * 24 * 60 * 60 * 1000)
 
226
                                      + (self.timeout.seconds * 1000)
 
227
                                      + (self.timeout.microseconds
 
228
                                         // 1000))
 
229
        # Emit D-Bus signal
 
230
        self.PropertyChanged(dbus.String(u"timeout"),
 
231
                             (dbus.UInt64(self._timeout_milliseconds,
 
232
                                          variant_level=1)))
 
233
    timeout = property(lambda self: self._timeout, _set_timeout)
 
234
    del _set_timeout
 
235
    
 
236
    def _set_interval(self, interval):
 
237
        "Setter function for the 'interval' attribute"
 
238
        self._interval = interval
 
239
        self._interval_milliseconds = ((self.interval.days
 
240
                                        * 24 * 60 * 60 * 1000)
 
241
                                       + (self.interval.seconds
 
242
                                          * 1000)
 
243
                                       + (self.interval.microseconds
 
244
                                          // 1000))
 
245
        # Emit D-Bus signal
 
246
        self.PropertyChanged(dbus.String(u"interval"),
 
247
                             (dbus.UInt64(self._interval_milliseconds,
 
248
                                          variant_level=1)))
 
249
    interval = property(lambda self: self._interval, _set_interval)
 
250
    del _set_interval
 
251
    
 
252
    def __init__(self, name = None, stop_hook=None, config=None):
221
253
        """Note: the 'checker' key in 'config' sets the
222
254
        'checker_command' attribute and *not* the 'checker'
223
255
        attribute."""
224
 
        self.name = name
 
256
        self.dbus_object_path = (dbus.ObjectPath
 
257
                                 ("/Mandos/clients/"
 
258
                                  + name.replace(".", "_")))
 
259
        dbus.service.Object.__init__(self, bus,
 
260
                                     self.dbus_object_path)
225
261
        if config is None:
226
262
            config = {}
 
263
        self.name = name
227
264
        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
265
        # Uppercase and remove spaces from fingerprint for later
236
266
        # comparison purposes with return value from the fingerprint()
237
267
        # function
250
280
                            % self.name)
251
281
        self.host = config.get("host", "")
252
282
        self.created = datetime.datetime.utcnow()
253
 
        self.enabled = False
254
 
        self.last_enabled = None
 
283
        self.started = False
 
284
        self.last_started = None
255
285
        self.last_checked_ok = None
256
286
        self.timeout = string_to_delta(config["timeout"])
257
287
        self.interval = string_to_delta(config["interval"])
258
 
        self.disable_hook = disable_hook
 
288
        self.stop_hook = stop_hook
259
289
        self.checker = None
260
290
        self.checker_initiator_tag = None
261
 
        self.disable_initiator_tag = None
 
291
        self.stop_initiator_tag = None
262
292
        self.checker_callback_tag = None
263
293
        self.checker_command = config["checker"]
264
294
    
265
 
    def enable(self):
 
295
    def start(self):
266
296
        """Start this client's checker and timeout hooks"""
267
 
        self.last_enabled = datetime.datetime.utcnow()
 
297
        self.last_started = datetime.datetime.utcnow()
268
298
        # Schedule a new checker to be started an 'interval' from now,
269
299
        # and every interval from then on.
270
300
        self.checker_initiator_tag = (gobject.timeout_add
271
 
                                      (self.interval_milliseconds(),
 
301
                                      (self._interval_milliseconds,
272
302
                                       self.start_checker))
273
303
        # Also start a new checker *right now*.
274
304
        self.start_checker()
275
 
        # Schedule a disable() when 'timeout' has passed
276
 
        self.disable_initiator_tag = (gobject.timeout_add
277
 
                                   (self.timeout_milliseconds(),
278
 
                                    self.disable))
279
 
        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)))
 
305
        # Schedule a stop() when 'timeout' has passed
 
306
        self.stop_initiator_tag = (gobject.timeout_add
 
307
                                   (self._timeout_milliseconds,
 
308
                                    self.stop))
 
309
        self.started = True
 
310
        # Emit D-Bus signal
 
311
        self.PropertyChanged(dbus.String(u"started"),
 
312
                             dbus.Boolean(True, variant_level=1))
 
313
        self.PropertyChanged(dbus.String(u"last_started"),
 
314
                             (_datetime_to_dbus_struct
 
315
                              (self.last_started, variant_level=1)))
287
316
    
288
 
    def disable(self):
289
 
        """Disable this client."""
290
 
        if not getattr(self, "enabled", False):
 
317
    def stop(self):
 
318
        """Stop this client."""
 
319
        if not getattr(self, "started", False):
291
320
            return False
292
 
        logger.info(u"Disabling client %s", self.name)
293
 
        if getattr(self, "disable_initiator_tag", False):
294
 
            gobject.source_remove(self.disable_initiator_tag)
295
 
            self.disable_initiator_tag = None
 
321
        logger.info(u"Stopping client %s", self.name)
 
322
        if getattr(self, "stop_initiator_tag", False):
 
323
            gobject.source_remove(self.stop_initiator_tag)
 
324
            self.stop_initiator_tag = None
296
325
        if getattr(self, "checker_initiator_tag", False):
297
326
            gobject.source_remove(self.checker_initiator_tag)
298
327
            self.checker_initiator_tag = None
299
328
        self.stop_checker()
300
 
        if self.disable_hook:
301
 
            self.disable_hook(self)
302
 
        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))
 
329
        if self.stop_hook:
 
330
            self.stop_hook(self)
 
331
        self.started = False
 
332
        # Emit D-Bus signal
 
333
        self.PropertyChanged(dbus.String(u"started"),
 
334
                             dbus.Boolean(False, variant_level=1))
307
335
        # Do not run this again if called by a gobject.timeout_add
308
336
        return False
309
337
    
310
338
    def __del__(self):
311
 
        self.disable_hook = None
312
 
        self.disable()
 
339
        self.stop_hook = None
 
340
        self.stop()
313
341
    
314
342
    def checker_callback(self, pid, condition, command):
315
343
        """The checker has completed, so take appropriate actions."""
316
344
        self.checker_callback_tag = None
317
345
        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))
 
346
        # Emit D-Bus signal
 
347
        self.PropertyChanged(dbus.String(u"checker_running"),
 
348
                             dbus.Boolean(False, variant_level=1))
322
349
        if (os.WIFEXITED(condition)
323
350
            and (os.WEXITSTATUS(condition) == 0)):
324
351
            logger.info(u"Checker for %(name)s succeeded",
325
352
                        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))
 
353
            # Emit D-Bus signal
 
354
            self.CheckerCompleted(dbus.Boolean(True),
 
355
                                  dbus.UInt16(condition),
 
356
                                  dbus.String(command))
331
357
            self.bump_timeout()
332
358
        elif not os.WIFEXITED(condition):
333
359
            logger.warning(u"Checker for %(name)s crashed?",
334
360
                           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))
 
361
            # Emit D-Bus signal
 
362
            self.CheckerCompleted(dbus.Boolean(False),
 
363
                                  dbus.UInt16(condition),
 
364
                                  dbus.String(command))
340
365
        else:
341
366
            logger.info(u"Checker for %(name)s failed",
342
367
                        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))
 
368
            # Emit D-Bus signal
 
369
            self.CheckerCompleted(dbus.Boolean(False),
 
370
                                  dbus.UInt16(condition),
 
371
                                  dbus.String(command))
348
372
    
349
373
    def bump_timeout(self):
350
374
        """Bump up the timeout for this client.
352
376
        alive and well.
353
377
        """
354
378
        self.last_checked_ok = datetime.datetime.utcnow()
355
 
        gobject.source_remove(self.disable_initiator_tag)
356
 
        self.disable_initiator_tag = (gobject.timeout_add
357
 
                                      (self.timeout_milliseconds(),
358
 
                                       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)))
 
379
        gobject.source_remove(self.stop_initiator_tag)
 
380
        self.stop_initiator_tag = (gobject.timeout_add
 
381
                                   (self._timeout_milliseconds,
 
382
                                    self.stop))
 
383
        self.PropertyChanged(dbus.String(u"last_checked_ok"),
 
384
                             (_datetime_to_dbus_struct
 
385
                              (self.last_checked_ok,
 
386
                               variant_level=1)))
365
387
    
366
388
    def start_checker(self):
367
389
        """Start a new checker subprocess if one is not running.
400
422
                self.checker = subprocess.Popen(command,
401
423
                                                close_fds=True,
402
424
                                                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))
 
425
                # Emit D-Bus signal
 
426
                self.CheckerStarted(command)
 
427
                self.PropertyChanged(dbus.String("checker_running"),
 
428
                                     dbus.Boolean(True, variant_level=1))
409
429
                self.checker_callback_tag = (gobject.child_watch_add
410
430
                                             (self.checker.pid,
411
431
                                              self.checker_callback,
433
453
            if error.errno != errno.ESRCH: # No such process
434
454
                raise
435
455
        self.checker = None
436
 
        if self.use_dbus:
437
 
            self.PropertyChanged(dbus.String(u"checker_running"),
438
 
                                 dbus.Boolean(False, variant_level=1))
 
456
        self.PropertyChanged(dbus.String(u"checker_running"),
 
457
                             dbus.Boolean(False, variant_level=1))
439
458
    
440
459
    def still_valid(self):
441
460
        """Has the timeout not yet passed for this client?"""
442
 
        if not getattr(self, "enabled", False):
 
461
        if not getattr(self, "started", False):
443
462
            return False
444
463
        now = datetime.datetime.utcnow()
445
464
        if self.last_checked_ok is None:
478
497
                dbus.String("host"):
479
498
                    dbus.String(self.host, variant_level=1),
480
499
                dbus.String("created"):
481
 
                    _datetime_to_dbus(self.created, variant_level=1),
482
 
                dbus.String("last_enabled"):
483
 
                    (_datetime_to_dbus(self.last_enabled,
484
 
                                       variant_level=1)
485
 
                     if self.last_enabled is not None
 
500
                    _datetime_to_dbus_struct(self.created,
 
501
                                             variant_level=1),
 
502
                dbus.String("last_started"):
 
503
                    (_datetime_to_dbus_struct(self.last_started,
 
504
                                              variant_level=1)
 
505
                     if self.last_started is not None
486
506
                     else dbus.Boolean(False, variant_level=1)),
487
 
                dbus.String("enabled"):
488
 
                    dbus.Boolean(self.enabled, variant_level=1),
 
507
                dbus.String("started"):
 
508
                    dbus.Boolean(self.started, variant_level=1),
489
509
                dbus.String("last_checked_ok"):
490
 
                    (_datetime_to_dbus(self.last_checked_ok,
491
 
                                       variant_level=1)
 
510
                    (_datetime_to_dbus_struct(self.last_checked_ok,
 
511
                                              variant_level=1)
492
512
                     if self.last_checked_ok is not None
493
513
                     else dbus.Boolean (False, variant_level=1)),
494
514
                dbus.String("timeout"):
495
 
                    dbus.UInt64(self.timeout_milliseconds(),
 
515
                    dbus.UInt64(self._timeout_milliseconds,
496
516
                                variant_level=1),
497
517
                dbus.String("interval"):
498
 
                    dbus.UInt64(self.interval_milliseconds(),
 
518
                    dbus.UInt64(self._interval_milliseconds,
499
519
                                variant_level=1),
500
520
                dbus.String("checker"):
501
521
                    dbus.String(self.checker_command,
521
541
    def SetChecker(self, checker):
522
542
        "D-Bus setter method"
523
543
        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
544
    
529
545
    # SetHost - method
530
546
    @dbus.service.method(_interface, in_signature="s")
531
547
    def SetHost(self, host):
532
548
        "D-Bus setter method"
533
549
        self.host = host
534
 
        # Emit D-Bus signal
535
 
        self.PropertyChanged(dbus.String(u"host"),
536
 
                             dbus.String(self.host, variant_level=1))
537
550
    
538
551
    # SetInterval - method
539
552
    @dbus.service.method(_interface, in_signature="t")
540
553
    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)))
 
554
        self.interval = datetime.timdeelta(0, 0, 0, milliseconds)
546
555
    
547
556
    # SetSecret - method
548
557
    @dbus.service.method(_interface, in_signature="ay",
555
564
    @dbus.service.method(_interface, in_signature="t")
556
565
    def SetTimeout(self, milliseconds):
557
566
        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
567
    
563
 
    # Enable - method
564
 
    Enable = dbus.service.method(_interface)(enable)
565
 
    Enable.__name__ = "Enable"
 
568
    # Start - method
 
569
    Start = dbus.service.method(_interface)(start)
 
570
    Start.__name__ = "Start"
566
571
    
567
572
    # StartChecker - method
568
573
    @dbus.service.method(_interface)
570
575
        "D-Bus method"
571
576
        self.start_checker()
572
577
    
573
 
    # Disable - method
 
578
    # Stop - method
574
579
    @dbus.service.method(_interface)
575
 
    def Disable(self):
 
580
    def Stop(self):
576
581
        "D-Bus method"
577
 
        self.disable()
 
582
        self.stop()
578
583
    
579
584
    # StopChecker - method
580
585
    StopChecker = dbus.service.method(_interface)(stop_checker)
840
845
    elif state == avahi.ENTRY_GROUP_FAILURE:
841
846
        logger.critical(u"Avahi: Error in group state changed %s",
842
847
                        unicode(error))
843
 
        raise AvahiGroupError(u"State changed: %s" % unicode(error))
 
848
        raise AvahiGroupError("State changed: %s", str(error))
844
849
 
845
850
def if_nametoindex(interface):
846
851
    """Call the C function if_nametoindex(), or equivalent"""
896
901
                      help="Address to listen for requests on")
897
902
    parser.add_option("-p", "--port", type="int",
898
903
                      help="Port number to receive requests on")
899
 
    parser.add_option("--check", action="store_true",
 
904
    parser.add_option("--check", action="store_true", default=False,
900
905
                      help="Run self-test")
901
906
    parser.add_option("--debug", action="store_true",
902
907
                      help="Debug mode; run in foreground and log to"
909
914
                      default="/etc/mandos", metavar="DIR",
910
915
                      help="Directory to search for configuration"
911
916
                      " 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
917
    options = parser.parse_args()[0]
917
918
    
918
919
    if options.check:
928
929
                        "priority":
929
930
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
930
931
                        "servicename": "Mandos",
931
 
                        "use_dbus": "True",
932
932
                        }
933
933
    
934
934
    # Parse config file for server-global settings
937
937
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
938
938
    # Convert the SafeConfigParser object to a dict
939
939
    server_settings = server_config.defaults()
940
 
    # Use getboolean on the boolean config options
 
940
    # Use getboolean on the boolean config option
941
941
    server_settings["debug"] = (server_config.getboolean
942
942
                                ("DEFAULT", "debug"))
943
 
    server_settings["use_dbus"] = (server_config.getboolean
944
 
                                   ("DEFAULT", "use_dbus"))
945
943
    del server_config
946
944
    
947
945
    # Override the settings from the config file with command line
948
946
    # options, if set.
949
947
    for option in ("interface", "address", "port", "debug",
950
 
                   "priority", "servicename", "configdir",
951
 
                   "use_dbus"):
 
948
                   "priority", "servicename", "configdir"):
952
949
        value = getattr(options, option)
953
950
        if value is not None:
954
951
            server_settings[option] = value
955
952
    del options
956
953
    # Now we have our good server settings in "server_settings"
957
954
    
958
 
    # For convenience
959
955
    debug = server_settings["debug"]
960
 
    use_dbus = server_settings["use_dbus"]
961
956
    
962
957
    if not debug:
963
958
        syslogger.setLevel(logging.WARNING)
1036
1031
                                           avahi.DBUS_PATH_SERVER),
1037
1032
                            avahi.DBUS_INTERFACE_SERVER)
1038
1033
    # End of Avahi example code
1039
 
    if use_dbus:
1040
 
        bus_name = dbus.service.BusName(u"org.mandos-system.Mandos",
1041
 
                                        bus)
 
1034
    bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus)
1042
1035
    
1043
1036
    clients.update(Set(Client(name = section,
1044
1037
                              config
1045
 
                              = dict(client_config.items(section)),
1046
 
                              use_dbus = use_dbus)
 
1038
                              = dict(client_config.items(section)))
1047
1039
                       for section in client_config.sections()))
1048
1040
    if not clients:
1049
 
        logger.warning(u"No clients defined")
 
1041
        logger.critical(u"No clients defined")
 
1042
        sys.exit(1)
1050
1043
    
1051
1044
    if debug:
1052
1045
        # Redirect stdin so all checkers get /dev/null
1084
1077
        
1085
1078
        while clients:
1086
1079
            client = clients.pop()
1087
 
            client.disable_hook = None
1088
 
            client.disable()
 
1080
            client.stop_hook = None
 
1081
            client.stop()
1089
1082
    
1090
1083
    atexit.register(cleanup)
1091
1084
    
1094
1087
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1095
1088
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1096
1089
    
1097
 
    if use_dbus:
1098
 
        class MandosServer(dbus.service.Object):
1099
 
            """A D-Bus proxy object"""
1100
 
            def __init__(self):
1101
 
                dbus.service.Object.__init__(self, bus,
1102
 
                                             "/Mandos")
1103
 
            _interface = u"org.mandos_system.Mandos"
1104
 
 
1105
 
            @dbus.service.signal(_interface, signature="oa{sv}")
1106
 
            def ClientAdded(self, objpath, properties):
1107
 
                "D-Bus signal"
1108
 
                pass
1109
 
 
1110
 
            @dbus.service.signal(_interface, signature="o")
1111
 
            def ClientRemoved(self, objpath):
1112
 
                "D-Bus signal"
1113
 
                pass
1114
 
 
1115
 
            @dbus.service.method(_interface, out_signature="ao")
1116
 
            def GetAllClients(self):
1117
 
                return dbus.Array(c.dbus_object_path for c in clients)
1118
 
 
1119
 
            @dbus.service.method(_interface, out_signature="a{oa{sv}}")
1120
 
            def GetAllClientsWithProperties(self):
1121
 
                return dbus.Dictionary(
1122
 
                    ((c.dbus_object_path, c.GetAllProperties())
1123
 
                     for c in clients),
1124
 
                    signature="oa{sv}")
1125
 
 
1126
 
            @dbus.service.method(_interface, in_signature="o")
1127
 
            def RemoveClient(self, object_path):
1128
 
                for c in clients:
1129
 
                    if c.dbus_object_path == object_path:
1130
 
                        clients.remove(c)
1131
 
                        # Don't signal anything except ClientRemoved
1132
 
                        c.use_dbus = False
1133
 
                        c.disable()
1134
 
                        # Emit D-Bus signal
1135
 
                        self.ClientRemoved(object_path)
1136
 
                        return
1137
 
                raise KeyError
1138
 
            @dbus.service.method(_interface)
1139
 
            def Quit(self):
1140
 
                main_loop.quit()
1141
 
 
1142
 
            del _interface
 
1090
    class MandosServer(dbus.service.Object):
 
1091
        """A D-Bus proxy object"""
 
1092
        def __init__(self):
 
1093
            dbus.service.Object.__init__(self, bus,
 
1094
                                         "/Mandos")
 
1095
        _interface = u"org.mandos_system.Mandos"
 
1096
        
 
1097
        @dbus.service.signal(_interface, signature="oa{sv}")
 
1098
        def ClientAdded(self, objpath, properties):
 
1099
            "D-Bus signal"
 
1100
            pass
 
1101
        
 
1102
        @dbus.service.signal(_interface, signature="o")
 
1103
        def ClientRemoved(self, objpath):
 
1104
            "D-Bus signal"
 
1105
            pass
 
1106
        
 
1107
        @dbus.service.method(_interface, out_signature="ao")
 
1108
        def GetAllClients(self):
 
1109
            return dbus.Array(c.dbus_object_path for c in clients)
 
1110
        
 
1111
        @dbus.service.method(_interface, out_signature="a{oa{sv}}")
 
1112
        def GetAllClientsWithProperties(self):
 
1113
            return dbus.Dictionary(
 
1114
                ((c.dbus_object_path, c.GetAllProperties())
 
1115
                 for c in clients),
 
1116
                signature="oa{sv}")
 
1117
        
 
1118
        @dbus.service.method(_interface, in_signature="o")
 
1119
        def RemoveClient(self, object_path):
 
1120
            for c in clients:
 
1121
                if c.dbus_object_path == object_path:
 
1122
                    c.stop()
 
1123
                    clients.remove(c)
 
1124
                    return
 
1125
            raise KeyError
 
1126
        
 
1127
        del _interface
1143
1128
    
1144
 
        mandos_server = MandosServer()
 
1129
    mandos_server = MandosServer()
1145
1130
    
1146
1131
    for client in clients:
1147
 
        if use_dbus:
1148
 
            # Emit D-Bus signal
1149
 
            mandos_server.ClientAdded(client.dbus_object_path,
1150
 
                                      client.GetAllProperties())
1151
 
        client.enable()
 
1132
        # Emit D-Bus signal
 
1133
        mandos_server.ClientAdded(client.dbus_object_path,
 
1134
                                  client.GetAllProperties())
 
1135
        client.start()
1152
1136
    
1153
1137
    tcp_server.enable()
1154
1138
    tcp_server.server_activate()
1178
1162
        logger.debug(u"Starting main loop")
1179
1163
        main_loop.run()
1180
1164
    except AvahiError, error:
1181
 
        logger.critical(u"AvahiError: %s", error)
 
1165
        logger.critical(u"AvahiError: %s" + unicode(error))
1182
1166
        sys.exit(1)
1183
1167
    except KeyboardInterrupt:
1184
1168
        if debug: