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)
197
last_started: datetime.datetime(); (UTC)
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
216
_timeout: Real variable for 'timeout'
217
_interval: Real variable for 'interval'
218
_timeout_milliseconds: Used when calling gobject.timeout_add()
219
_interval_milliseconds: - '' -
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))
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))
219
def __init__(self, name = None, disable_hook=None, config=None,
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
230
self.PropertyChanged(dbus.String(u"timeout"),
231
(dbus.UInt64(self._timeout_milliseconds,
233
timeout = property(lambda self: self._timeout, _set_timeout)
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
243
+ (self.interval.microseconds
246
self.PropertyChanged(dbus.String(u"interval"),
247
(dbus.UInt64(self._interval_milliseconds,
249
interval = property(lambda self: self._interval, _set_interval)
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'
256
self.dbus_object_path = (dbus.ObjectPath
258
+ name.replace(".", "_")))
259
dbus.service.Object.__init__(self, bus,
260
self.dbus_object_path)
225
261
if config is None:
227
264
logger.debug(u"Creating client %r", self.name)
228
self.use_dbus = use_dbus
230
self.dbus_object_path = (dbus.ObjectPath
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()
251
281
self.host = config.get("host", "")
252
282
self.created = datetime.datetime.utcnow()
254
self.last_enabled = None
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"]
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(),
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,
305
# Schedule a stop() when 'timeout' has passed
306
self.stop_initiator_tag = (gobject.timeout_add
307
(self._timeout_milliseconds,
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)))
289
"""Disable this client."""
290
if not getattr(self, "enabled", False):
318
"""Stop this client."""
319
if not getattr(self, "started", 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)
305
self.PropertyChanged(dbus.String(u"enabled"),
306
dbus.Boolean(False, variant_level=1))
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
310
338
def __del__(self):
311
self.disable_hook = None
339
self.stop_hook = None
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
320
self.PropertyChanged(dbus.String(u"checker_running"),
321
dbus.Boolean(False, variant_level=1))
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",
328
self.CheckerCompleted(dbus.Boolean(True),
329
dbus.UInt16(condition),
330
dbus.String(command))
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?",
337
self.CheckerCompleted(dbus.Boolean(False),
338
dbus.UInt16(condition),
339
dbus.String(command))
362
self.CheckerCompleted(dbus.Boolean(False),
363
dbus.UInt16(condition),
364
dbus.String(command))
341
366
logger.info(u"Checker for %(name)s failed",
345
self.CheckerCompleted(dbus.Boolean(False),
346
dbus.UInt16(condition),
347
dbus.String(command))
369
self.CheckerCompleted(dbus.Boolean(False),
370
dbus.UInt16(condition),
371
dbus.String(command))
349
373
def bump_timeout(self):
350
374
"""Bump up the timeout for this client.
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,
485
if self.last_enabled is not None
500
_datetime_to_dbus_struct(self.created,
502
dbus.String("last_started"):
503
(_datetime_to_dbus_struct(self.last_started,
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,
510
(_datetime_to_dbus_struct(self.last_checked_ok,
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
525
self.PropertyChanged(dbus.String(u"checker"),
526
dbus.String(self.checker_command,
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"
535
self.PropertyChanged(dbus.String(u"host"),
536
dbus.String(self.host, variant_level=1))
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)
543
self.PropertyChanged(dbus.String(u"interval"),
544
(dbus.UInt64(self.interval_milliseconds(),
554
self.interval = datetime.timdeelta(0, 0, 0, milliseconds)
547
556
# SetSecret - method
548
557
@dbus.service.method(_interface, in_signature="ay",
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
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",
948
"priority", "servicename", "configdir"):
952
949
value = getattr(options, option)
953
950
if value is not None:
954
951
server_settings[option] = value
956
953
# Now we have our good server settings in "server_settings"
959
955
debug = server_settings["debug"]
960
use_dbus = server_settings["use_dbus"]
963
958
syslogger.setLevel(logging.WARNING)
1094
1087
signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
1095
1088
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1098
class MandosServer(dbus.service.Object):
1099
"""A D-Bus proxy object"""
1101
dbus.service.Object.__init__(self, bus,
1103
_interface = u"org.mandos_system.Mandos"
1105
@dbus.service.signal(_interface, signature="oa{sv}")
1106
def ClientAdded(self, objpath, properties):
1110
@dbus.service.signal(_interface, signature="o")
1111
def ClientRemoved(self, objpath):
1115
@dbus.service.method(_interface, out_signature="ao")
1116
def GetAllClients(self):
1117
return dbus.Array(c.dbus_object_path for c in clients)
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())
1126
@dbus.service.method(_interface, in_signature="o")
1127
def RemoveClient(self, object_path):
1129
if c.dbus_object_path == object_path:
1131
# Don't signal anything except ClientRemoved
1135
self.ClientRemoved(object_path)
1138
@dbus.service.method(_interface)
1090
class MandosServer(dbus.service.Object):
1091
"""A D-Bus proxy object"""
1093
dbus.service.Object.__init__(self, bus,
1095
_interface = u"org.mandos_system.Mandos"
1097
@dbus.service.signal(_interface, signature="oa{sv}")
1098
def ClientAdded(self, objpath, properties):
1102
@dbus.service.signal(_interface, signature="o")
1103
def ClientRemoved(self, objpath):
1107
@dbus.service.method(_interface, out_signature="ao")
1108
def GetAllClients(self):
1109
return dbus.Array(c.dbus_object_path for c in clients)
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())
1118
@dbus.service.method(_interface, in_signature="o")
1119
def RemoveClient(self, object_path):
1121
if c.dbus_object_path == object_path:
1144
mandos_server = MandosServer()
1129
mandos_server = MandosServer()
1146
1131
for client in clients:
1149
mandos_server.ClientAdded(client.dbus_object_path,
1150
client.GetAllProperties())
1133
mandos_server.ClientAdded(client.dbus_object_path,
1134
client.GetAllProperties())
1153
1137
tcp_server.enable()
1154
1138
tcp_server.server_activate()