/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-29 02:44:54 UTC
  • Revision ID: teddy@fukt.bsnet.se-20081229024454-nbsei556dwy5azr1
* mandos (Client.timeout, Client.interval): Changed from being a
                                            property to be a normal
                                            attribute.
  (Client._timeout, Client._interval): Removed.
  (Client._timeout_milliseconds): Changed from being an attribute to
                                  be a method "timeout_milliseconds".
                                  All users changed.
  (Client._interval_milliseconds): Changed from being an attribute to
                                   be method "interval_milliseconds".
                                   All users changed.
  (Client.__init__): Take additional "use_dbus" keyword argument.
                     Only provide D-Bus interface if "use_dbus" is
                     True.
  (Client.use_dbus): New attribute.
  (Client.dbus_object_path): Changed to only be set if "self.use_dbus"
                             is True.
  (Client.enable, Client.disable, Client.checker_callback,
  Client.bump_timeout, Client.start_checker, Client.stop_checker):
  Only emit D-Bus signals if "self.use_dbus".
  (Client.SetChecker, Client.SetHost, Client.Enable): Bug fix: Emit
                                                      D-Bus signals.
  (Client.SetInterval, Client.SetTimeout): Changed to emit D-Bus
                                           signals.

  (main): Remove deprecated "default" keyword argument to "--check"
          option.  Added new "--no-dbus" option.  Added corresponding
          "use_dbus" server configuration option.  Only provide D-Bus
          interface and emit D-Bus signals if "use_dbus".  Pass
          "use_dbus" on to Client constructor.

* mandos-options.xml ([@id="dbus"]): New option.

* mandos.conf (use_dbus): New option.

* mandos.conf.xml (OPTIONS): New option "use_dbus".
  (EXAMPLE): - '' -

* mandos.xml (SYNOPSIS): New option "--no-dbus".
  (D-BUS INTERFACE): New section.

Show diffs side-by-side

added added

removed removed

Lines of Context:
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
 
    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: - '' -
 
204
    use_dbus: bool(); Whether to provide D-Bus interface and signals
 
205
    dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
210
206
    """
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):
 
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):
243
221
        """Note: the 'checker' key in 'config' sets the
244
222
        'checker_command' attribute and *not* the 'checker'
245
223
        attribute."""
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)
 
224
        self.name = name
251
225
        if config is None:
252
226
            config = {}
253
 
        self.name = name
254
227
        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)
255
235
        # Uppercase and remove spaces from fingerprint for later
256
236
        # comparison purposes with return value from the fingerprint()
257
237
        # function
288
268
        # Schedule a new checker to be started an 'interval' from now,
289
269
        # and every interval from then on.
290
270
        self.checker_initiator_tag = (gobject.timeout_add
291
 
                                      (self._interval_milliseconds,
 
271
                                      (self.interval_milliseconds(),
292
272
                                       self.start_checker))
293
273
        # Also start a new checker *right now*.
294
274
        self.start_checker()
295
275
        # Schedule a disable() when 'timeout' has passed
296
276
        self.disable_initiator_tag = (gobject.timeout_add
297
 
                                   (self._timeout_milliseconds,
 
277
                                   (self.timeout_milliseconds(),
298
278
                                    self.disable))
299
279
        self.enabled = True
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)))
 
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)))
306
287
    
307
288
    def disable(self):
308
289
        """Disable this client."""
319
300
        if self.disable_hook:
320
301
            self.disable_hook(self)
321
302
        self.enabled = False
322
 
        # Emit D-Bus signal
323
 
        self.PropertyChanged(dbus.String(u"enabled"),
324
 
                             dbus.Boolean(False, variant_level=1))
 
303
        if self.use_dbus:
 
304
            # Emit D-Bus signal
 
305
            self.PropertyChanged(dbus.String(u"enabled"),
 
306
                                 dbus.Boolean(False, variant_level=1))
325
307
        # Do not run this again if called by a gobject.timeout_add
326
308
        return False
327
309
    
333
315
        """The checker has completed, so take appropriate actions."""
334
316
        self.checker_callback_tag = None
335
317
        self.checker = None
336
 
        # Emit D-Bus signal
337
 
        self.PropertyChanged(dbus.String(u"checker_running"),
338
 
                             dbus.Boolean(False, variant_level=1))
 
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))
339
322
        if (os.WIFEXITED(condition)
340
323
            and (os.WEXITSTATUS(condition) == 0)):
341
324
            logger.info(u"Checker for %(name)s succeeded",
342
325
                        vars(self))
343
 
            # Emit D-Bus signal
344
 
            self.CheckerCompleted(dbus.Boolean(True),
345
 
                                  dbus.UInt16(condition),
346
 
                                  dbus.String(command))
 
326
            if self.use_dbus:
 
327
                # Emit D-Bus signal
 
328
                self.CheckerCompleted(dbus.Boolean(True),
 
329
                                      dbus.UInt16(condition),
 
330
                                      dbus.String(command))
347
331
            self.bump_timeout()
348
332
        elif not os.WIFEXITED(condition):
349
333
            logger.warning(u"Checker for %(name)s crashed?",
350
334
                           vars(self))
351
 
            # Emit D-Bus signal
352
 
            self.CheckerCompleted(dbus.Boolean(False),
353
 
                                  dbus.UInt16(condition),
354
 
                                  dbus.String(command))
 
335
            if self.use_dbus:
 
336
                # Emit D-Bus signal
 
337
                self.CheckerCompleted(dbus.Boolean(False),
 
338
                                      dbus.UInt16(condition),
 
339
                                      dbus.String(command))
355
340
        else:
356
341
            logger.info(u"Checker for %(name)s failed",
357
342
                        vars(self))
358
 
            # Emit D-Bus signal
359
 
            self.CheckerCompleted(dbus.Boolean(False),
360
 
                                  dbus.UInt16(condition),
361
 
                                  dbus.String(command))
 
343
            if self.use_dbus:
 
344
                # Emit D-Bus signal
 
345
                self.CheckerCompleted(dbus.Boolean(False),
 
346
                                      dbus.UInt16(condition),
 
347
                                      dbus.String(command))
362
348
    
363
349
    def bump_timeout(self):
364
350
        """Bump up the timeout for this client.
368
354
        self.last_checked_ok = datetime.datetime.utcnow()
369
355
        gobject.source_remove(self.disable_initiator_tag)
370
356
        self.disable_initiator_tag = (gobject.timeout_add
371
 
                                      (self._timeout_milliseconds,
 
357
                                      (self.timeout_milliseconds(),
372
358
                                       self.disable))
373
 
        self.PropertyChanged(dbus.String(u"last_checked_ok"),
374
 
                             (_datetime_to_dbus(self.last_checked_ok,
375
 
                                                variant_level=1)))
 
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)))
376
365
    
377
366
    def start_checker(self):
378
367
        """Start a new checker subprocess if one is not running.
411
400
                self.checker = subprocess.Popen(command,
412
401
                                                close_fds=True,
413
402
                                                shell=True, cwd="/")
414
 
                # Emit D-Bus signal
415
 
                self.CheckerStarted(command)
416
 
                self.PropertyChanged(dbus.String("checker_running"),
417
 
                                     dbus.Boolean(True, variant_level=1))
 
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))
418
409
                self.checker_callback_tag = (gobject.child_watch_add
419
410
                                             (self.checker.pid,
420
411
                                              self.checker_callback,
442
433
            if error.errno != errno.ESRCH: # No such process
443
434
                raise
444
435
        self.checker = None
445
 
        self.PropertyChanged(dbus.String(u"checker_running"),
446
 
                             dbus.Boolean(False, variant_level=1))
 
436
        if self.use_dbus:
 
437
            self.PropertyChanged(dbus.String(u"checker_running"),
 
438
                                 dbus.Boolean(False, variant_level=1))
447
439
    
448
440
    def still_valid(self):
449
441
        """Has the timeout not yet passed for this client?"""
500
492
                     if self.last_checked_ok is not None
501
493
                     else dbus.Boolean (False, variant_level=1)),
502
494
                dbus.String("timeout"):
503
 
                    dbus.UInt64(self._timeout_milliseconds,
 
495
                    dbus.UInt64(self.timeout_milliseconds(),
504
496
                                variant_level=1),
505
497
                dbus.String("interval"):
506
 
                    dbus.UInt64(self._interval_milliseconds,
 
498
                    dbus.UInt64(self.interval_milliseconds(),
507
499
                                variant_level=1),
508
500
                dbus.String("checker"):
509
501
                    dbus.String(self.checker_command,
529
521
    def SetChecker(self, checker):
530
522
        "D-Bus setter method"
531
523
        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))
532
528
    
533
529
    # SetHost - method
534
530
    @dbus.service.method(_interface, in_signature="s")
535
531
    def SetHost(self, host):
536
532
        "D-Bus setter method"
537
533
        self.host = host
 
534
        # Emit D-Bus signal
 
535
        self.PropertyChanged(dbus.String(u"host"),
 
536
                             dbus.String(self.host, variant_level=1))
538
537
    
539
538
    # SetInterval - method
540
539
    @dbus.service.method(_interface, in_signature="t")
541
540
    def SetInterval(self, milliseconds):
542
 
        self.interval = datetime.timdeelta(0, 0, 0, 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)))
543
546
    
544
547
    # SetSecret - method
545
548
    @dbus.service.method(_interface, in_signature="ay",
552
555
    @dbus.service.method(_interface, in_signature="t")
553
556
    def SetTimeout(self, milliseconds):
554
557
        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)))
555
562
    
556
563
    # Enable - method
557
564
    Enable = dbus.service.method(_interface)(enable)
889
896
                      help="Address to listen for requests on")
890
897
    parser.add_option("-p", "--port", type="int",
891
898
                      help="Port number to receive requests on")
892
 
    parser.add_option("--check", action="store_true", default=False,
 
899
    parser.add_option("--check", action="store_true",
893
900
                      help="Run self-test")
894
901
    parser.add_option("--debug", action="store_true",
895
902
                      help="Debug mode; run in foreground and log to"
902
909
                      default="/etc/mandos", metavar="DIR",
903
910
                      help="Directory to search for configuration"
904
911
                      " 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")
905
916
    options = parser.parse_args()[0]
906
917
    
907
918
    if options.check:
917
928
                        "priority":
918
929
                        "SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
919
930
                        "servicename": "Mandos",
 
931
                        "use_dbus": "True",
920
932
                        }
921
933
    
922
934
    # Parse config file for server-global settings
925
937
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
926
938
    # Convert the SafeConfigParser object to a dict
927
939
    server_settings = server_config.defaults()
928
 
    # Use getboolean on the boolean config option
 
940
    # Use getboolean on the boolean config options
929
941
    server_settings["debug"] = (server_config.getboolean
930
942
                                ("DEFAULT", "debug"))
 
943
    server_settings["use_dbus"] = (server_config.getboolean
 
944
                                   ("DEFAULT", "use_dbus"))
931
945
    del server_config
932
946
    
933
947
    # Override the settings from the config file with command line
934
948
    # options, if set.
935
949
    for option in ("interface", "address", "port", "debug",
936
 
                   "priority", "servicename", "configdir"):
 
950
                   "priority", "servicename", "configdir",
 
951
                   "use_dbus"):
937
952
        value = getattr(options, option)
938
953
        if value is not None:
939
954
            server_settings[option] = value
940
955
    del options
941
956
    # Now we have our good server settings in "server_settings"
942
957
    
 
958
    # For convenience
943
959
    debug = server_settings["debug"]
 
960
    use_dbus = server_settings["use_dbus"]
944
961
    
945
962
    if not debug:
946
963
        syslogger.setLevel(logging.WARNING)
1019
1036
                                           avahi.DBUS_PATH_SERVER),
1020
1037
                            avahi.DBUS_INTERFACE_SERVER)
1021
1038
    # End of Avahi example code
1022
 
    bus_name = dbus.service.BusName(u"org.mandos-system.Mandos", bus)
 
1039
    if use_dbus:
 
1040
        bus_name = dbus.service.BusName(u"org.mandos-system.Mandos",
 
1041
                                        bus)
1023
1042
    
1024
1043
    clients.update(Set(Client(name = section,
1025
1044
                              config
1026
 
                              = dict(client_config.items(section)))
 
1045
                              = dict(client_config.items(section)),
 
1046
                              use_dbus = use_dbus)
1027
1047
                       for section in client_config.sections()))
1028
1048
    if not clients:
1029
1049
        logger.critical(u"No clients defined")
1075
1095
    signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1076
1096
    signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1077
1097
    
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
 
1098
    if use_dbus:
 
1099
        class MandosServer(dbus.service.Object):
 
1100
            """A D-Bus proxy object"""
 
1101
            def __init__(self):
 
1102
                dbus.service.Object.__init__(self, bus,
 
1103
                                             "/Mandos")
 
1104
            _interface = u"org.mandos_system.Mandos"
 
1105
 
 
1106
            @dbus.service.signal(_interface, signature="oa{sv}")
 
1107
            def ClientAdded(self, objpath, properties):
 
1108
                "D-Bus signal"
 
1109
                pass
 
1110
 
 
1111
            @dbus.service.signal(_interface, signature="o")
 
1112
            def ClientRemoved(self, objpath):
 
1113
                "D-Bus signal"
 
1114
                pass
 
1115
 
 
1116
            @dbus.service.method(_interface, out_signature="ao")
 
1117
            def GetAllClients(self):
 
1118
                return dbus.Array(c.dbus_object_path for c in clients)
 
1119
 
 
1120
            @dbus.service.method(_interface, out_signature="a{oa{sv}}")
 
1121
            def GetAllClientsWithProperties(self):
 
1122
                return dbus.Dictionary(
 
1123
                    ((c.dbus_object_path, c.GetAllProperties())
 
1124
                     for c in clients),
 
1125
                    signature="oa{sv}")
 
1126
 
 
1127
            @dbus.service.method(_interface, in_signature="o")
 
1128
            def RemoveClient(self, object_path):
 
1129
                for c in clients:
 
1130
                    if c.dbus_object_path == object_path:
 
1131
                        clients.remove(c)
 
1132
                        # Don't signal anything except ClientRemoved
 
1133
                        c.use_dbus = False
 
1134
                        c.disable()
 
1135
                        # Emit D-Bus signal
 
1136
                        self.ClientRemoved(object_path)
 
1137
                        return
 
1138
                raise KeyError
 
1139
 
 
1140
            del _interface
1116
1141
    
1117
 
    mandos_server = MandosServer()
 
1142
        mandos_server = MandosServer()
1118
1143
    
1119
1144
    for client in clients:
1120
 
        # Emit D-Bus signal
1121
 
        mandos_server.ClientAdded(client.dbus_object_path,
1122
 
                                  client.GetAllProperties())
 
1145
        if use_dbus:
 
1146
            # Emit D-Bus signal
 
1147
            mandos_server.ClientAdded(client.dbus_object_path,
 
1148
                                      client.GetAllProperties())
1123
1149
        client.enable()
1124
1150
    
1125
1151
    tcp_server.enable()