104
126
max_renames: integer; maximum number of renames
105
127
rename_count: integer; counter so we only rename after collisions
106
128
a sensible number of times
129
group: D-Bus Entry Group
131
bus: dbus.SystemBus()
108
133
def __init__(self, interface = avahi.IF_UNSPEC, name = None,
109
type = None, port = None, TXT = None, domain = "",
110
host = "", max_renames = 32768):
134
servicetype = None, port = None, TXT = None,
135
domain = u"", host = u"", max_renames = 32768,
136
protocol = avahi.PROTO_UNSPEC, bus = None):
111
137
self.interface = interface
139
self.type = servicetype
141
self.TXT = TXT if TXT is not None else []
119
142
self.domain = domain
121
144
self.rename_count = 0
122
145
self.max_renames = max_renames
146
self.protocol = protocol
147
self.group = None # our entry group
123
150
def rename(self):
124
151
"""Derived from the Avahi example code"""
125
152
if self.rename_count >= self.max_renames:
126
logger.critical(u"No suitable service name found after %i"
127
u" retries, exiting.", rename_count)
128
raise AvahiServiceError("Too many renames")
129
self.name = server.GetAlternativeServiceName(self.name)
130
logger.info(u"Changing name to %r ...", str(self.name))
131
syslogger.setFormatter(logging.Formatter\
132
('Mandos (%s): %%(levelname)s:'
133
' %%(message)s' % self.name))
153
logger.critical(u"No suitable Zeroconf service name found"
154
u" after %i retries, exiting.",
156
raise AvahiServiceError(u"Too many renames")
157
self.name = self.server.GetAlternativeServiceName(self.name)
158
logger.info(u"Changing Zeroconf service name to %r ...",
160
syslogger.setFormatter(logging.Formatter
161
(u'Mandos (%s) [%%(process)d]:'
162
u' %%(levelname)s: %%(message)s'
136
166
self.rename_count += 1
137
167
def remove(self):
138
168
"""Derived from the Avahi example code"""
139
if group is not None:
169
if self.group is not None:
142
172
"""Derived from the Avahi example code"""
145
group = dbus.Interface\
146
(bus.get_object(avahi.DBUS_NAME,
147
server.EntryGroupNew()),
148
avahi.DBUS_INTERFACE_ENTRY_GROUP)
149
group.connect_to_signal('StateChanged',
150
entry_group_state_changed)
151
logger.debug(u"Adding service '%s' of type '%s' ...",
152
service.name, service.type)
154
self.interface, # interface
155
avahi.PROTO_INET6, # protocol
156
dbus.UInt32(0), # flags
157
self.name, self.type,
158
self.domain, self.host,
159
dbus.UInt16(self.port),
160
avahi.string_array_to_txt_array(self.TXT))
163
# From the Avahi example code:
164
group = None # our entry group
165
# End of Avahi example code
173
if self.group is None:
174
self.group = dbus.Interface(
175
self.bus.get_object(avahi.DBUS_NAME,
176
self.server.EntryGroupNew()),
177
avahi.DBUS_INTERFACE_ENTRY_GROUP)
178
self.group.connect_to_signal('StateChanged',
180
.entry_group_state_changed)
181
logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
182
self.name, self.type)
183
self.group.AddService(
186
dbus.UInt32(0), # flags
187
self.name, self.type,
188
self.domain, self.host,
189
dbus.UInt16(self.port),
190
avahi.string_array_to_txt_array(self.TXT))
192
def entry_group_state_changed(self, state, error):
193
"""Derived from the Avahi example code"""
194
logger.debug(u"Avahi state change: %i", state)
196
if state == avahi.ENTRY_GROUP_ESTABLISHED:
197
logger.debug(u"Zeroconf service established.")
198
elif state == avahi.ENTRY_GROUP_COLLISION:
199
logger.warning(u"Zeroconf service name collision.")
201
elif state == avahi.ENTRY_GROUP_FAILURE:
202
logger.critical(u"Avahi: Error in group state changed %s",
204
raise AvahiGroupError(u"State changed: %s"
207
"""Derived from the Avahi example code"""
208
if self.group is not None:
211
def server_state_changed(self, state):
212
"""Derived from the Avahi example code"""
213
if state == avahi.SERVER_COLLISION:
214
logger.error(u"Zeroconf server name collision")
216
elif state == avahi.SERVER_RUNNING:
219
"""Derived from the Avahi example code"""
220
if self.server is None:
221
self.server = dbus.Interface(
222
self.bus.get_object(avahi.DBUS_NAME,
223
avahi.DBUS_PATH_SERVER),
224
avahi.DBUS_INTERFACE_SERVER)
225
self.server.connect_to_signal(u"StateChanged",
226
self.server_state_changed)
227
self.server_state_changed(self.server.GetState())
168
230
class Client(object):
169
231
"""A representation of a client host served by this server.
171
name: string; from the config file, used in log messages
234
name: string; from the config file, used in log messages and
172
236
fingerprint: string (40 or 32 hexadecimal digits); used to
173
237
uniquely identify the client
174
secret: bytestring; sent verbatim (over TLS) to client
175
host: string; available for use by the checker command
176
created: datetime.datetime(); object creation, not client host
177
last_checked_ok: datetime.datetime() or None if not yet checked OK
178
timeout: datetime.timedelta(); How long from last_checked_ok
179
until this client is invalid
180
interval: datetime.timedelta(); How often to start a new checker
181
stop_hook: If set, called by stop() as stop_hook(self)
182
checker: subprocess.Popen(); a running checker process used
183
to see if the client lives.
184
'None' if no process is running.
238
secret: bytestring; sent verbatim (over TLS) to client
239
host: string; available for use by the checker command
240
created: datetime.datetime(); (UTC) object creation
241
last_enabled: datetime.datetime(); (UTC)
243
last_checked_ok: datetime.datetime(); (UTC) or None
244
timeout: datetime.timedelta(); How long from last_checked_ok
245
until this client is invalid
246
interval: datetime.timedelta(); How often to start a new checker
247
disable_hook: If set, called by disable() as disable_hook(self)
248
checker: subprocess.Popen(); a running checker process used
249
to see if the client lives.
250
'None' if no process is running.
185
251
checker_initiator_tag: a gobject event source tag, or None
186
stop_initiator_tag: - '' -
252
disable_initiator_tag: - '' -
187
253
checker_callback_tag: - '' -
188
254
checker_command: string; External command which is run to check if
189
255
client lives. %() expansions are done at
190
256
runtime with vars(self) as dict, so that for
191
257
instance %(name)s can be used in the command.
193
_timeout: Real variable for 'timeout'
194
_interval: Real variable for 'interval'
195
_timeout_milliseconds: Used when calling gobject.timeout_add()
196
_interval_milliseconds: - '' -
258
current_checker_command: string; current running checker_command
198
def _set_timeout(self, timeout):
199
"Setter function for 'timeout' attribute"
200
self._timeout = timeout
201
self._timeout_milliseconds = ((self.timeout.days
202
* 24 * 60 * 60 * 1000)
203
+ (self.timeout.seconds * 1000)
204
+ (self.timeout.microseconds
206
timeout = property(lambda self: self._timeout,
209
def _set_interval(self, interval):
210
"Setter function for 'interval' attribute"
211
self._interval = interval
212
self._interval_milliseconds = ((self.interval.days
213
* 24 * 60 * 60 * 1000)
214
+ (self.interval.seconds
216
+ (self.interval.microseconds
218
interval = property(lambda self: self._interval,
221
def __init__(self, name = None, stop_hook=None, config={}):
262
def _timedelta_to_milliseconds(td):
263
"Convert a datetime.timedelta() to milliseconds"
264
return ((td.days * 24 * 60 * 60 * 1000)
265
+ (td.seconds * 1000)
266
+ (td.microseconds // 1000))
268
def timeout_milliseconds(self):
269
"Return the 'timeout' attribute in milliseconds"
270
return self._timedelta_to_milliseconds(self.timeout)
272
def interval_milliseconds(self):
273
"Return the 'interval' attribute in milliseconds"
274
return self._timedelta_to_milliseconds(self.interval)
276
def __init__(self, name = None, disable_hook=None, config=None):
222
277
"""Note: the 'checker' key in 'config' sets the
223
278
'checker_command' attribute and *not* the 'checker'
226
283
logger.debug(u"Creating client %r", self.name)
227
284
# Uppercase and remove spaces from fingerprint for later
228
285
# comparison purposes with return value from the fingerprint()
230
self.fingerprint = config["fingerprint"].upper()\
287
self.fingerprint = (config[u"fingerprint"].upper()
232
289
logger.debug(u" Fingerprint: %s", self.fingerprint)
233
if "secret" in config:
234
self.secret = config["secret"].decode(u"base64")
235
elif "secfile" in config:
236
sf = open(config["secfile"])
237
self.secret = sf.read()
290
if u"secret" in config:
291
self.secret = config[u"secret"].decode(u"base64")
292
elif u"secfile" in config:
293
with closing(open(os.path.expanduser
295
(config[u"secfile"])))) as secfile:
296
self.secret = secfile.read()
240
298
raise TypeError(u"No secret or secfile for client %s"
242
self.host = config.get("host", "")
243
self.created = datetime.datetime.now()
300
self.host = config.get(u"host", u"")
301
self.created = datetime.datetime.utcnow()
303
self.last_enabled = None
244
304
self.last_checked_ok = None
245
self.timeout = string_to_delta(config["timeout"])
246
self.interval = string_to_delta(config["interval"])
247
self.stop_hook = stop_hook
305
self.timeout = string_to_delta(config[u"timeout"])
306
self.interval = string_to_delta(config[u"interval"])
307
self.disable_hook = disable_hook
248
308
self.checker = None
249
309
self.checker_initiator_tag = None
250
self.stop_initiator_tag = None
310
self.disable_initiator_tag = None
251
311
self.checker_callback_tag = None
252
self.check_command = config["checker"]
312
self.checker_command = config[u"checker"]
313
self.current_checker_command = None
314
self.last_connect = None
254
317
"""Start this client's checker and timeout hooks"""
318
if getattr(self, u"enabled", False):
321
self.last_enabled = datetime.datetime.utcnow()
255
322
# Schedule a new checker to be started an 'interval' from now,
256
323
# and every interval from then on.
257
self.checker_initiator_tag = gobject.timeout_add\
258
(self._interval_milliseconds,
324
self.checker_initiator_tag = (gobject.timeout_add
325
(self.interval_milliseconds(),
260
327
# Also start a new checker *right now*.
261
328
self.start_checker()
262
# Schedule a stop() when 'timeout' has passed
263
self.stop_initiator_tag = gobject.timeout_add\
264
(self._timeout_milliseconds,
268
The possibility that a client might be restarted is left open,
269
but not currently used."""
270
# If this client doesn't have a secret, it is already stopped.
271
if hasattr(self, "secret") and self.secret:
272
logger.info(u"Stopping client %s", self.name)
329
# Schedule a disable() when 'timeout' has passed
330
self.disable_initiator_tag = (gobject.timeout_add
331
(self.timeout_milliseconds(),
336
"""Disable this client."""
337
if not getattr(self, "enabled", False):
276
if getattr(self, "stop_initiator_tag", False):
277
gobject.source_remove(self.stop_initiator_tag)
278
self.stop_initiator_tag = None
279
if getattr(self, "checker_initiator_tag", False):
339
logger.info(u"Disabling client %s", self.name)
340
if getattr(self, u"disable_initiator_tag", False):
341
gobject.source_remove(self.disable_initiator_tag)
342
self.disable_initiator_tag = None
343
if getattr(self, u"checker_initiator_tag", False):
280
344
gobject.source_remove(self.checker_initiator_tag)
281
345
self.checker_initiator_tag = None
282
346
self.stop_checker()
347
if self.disable_hook:
348
self.disable_hook(self)
285
350
# Do not run this again if called by a gobject.timeout_add
287
353
def __del__(self):
288
self.stop_hook = None
290
def checker_callback(self, pid, condition):
354
self.disable_hook = None
357
def checker_callback(self, pid, condition, command):
291
358
"""The checker has completed, so take appropriate actions."""
292
now = datetime.datetime.now()
293
359
self.checker_callback_tag = None
294
360
self.checker = None
295
if os.WIFEXITED(condition) \
296
and (os.WEXITSTATUS(condition) == 0):
297
logger.info(u"Checker for %(name)s succeeded",
299
self.last_checked_ok = now
300
gobject.source_remove(self.stop_initiator_tag)
301
self.stop_initiator_tag = gobject.timeout_add\
302
(self._timeout_milliseconds,
304
elif not os.WIFEXITED(condition):
361
if os.WIFEXITED(condition):
362
exitstatus = os.WEXITSTATUS(condition)
364
logger.info(u"Checker for %(name)s succeeded",
368
logger.info(u"Checker for %(name)s failed",
305
371
logger.warning(u"Checker for %(name)s crashed?",
308
logger.info(u"Checker for %(name)s failed",
374
def checked_ok(self):
375
"""Bump up the timeout for this client.
377
This should only be called when the client has been seen,
380
self.last_checked_ok = datetime.datetime.utcnow()
381
gobject.source_remove(self.disable_initiator_tag)
382
self.disable_initiator_tag = (gobject.timeout_add
383
(self.timeout_milliseconds(),
310
386
def start_checker(self):
311
387
"""Start a new checker subprocess if one is not running.
312
389
If a checker already exists, leave it running and do
314
391
# The reason for not killing a running checker is that if we
369
473
if error.errno != errno.ESRCH: # No such process
371
475
self.checker = None
372
477
def still_valid(self):
373
478
"""Has the timeout not yet passed for this client?"""
374
now = datetime.datetime.now()
479
if not getattr(self, u"enabled", False):
481
now = datetime.datetime.utcnow()
375
482
if self.last_checked_ok is None:
376
483
return now < (self.created + self.timeout)
378
485
return now < (self.last_checked_ok + self.timeout)
381
def peer_certificate(session):
382
"Return the peer's OpenPGP certificate as a bytestring"
383
# If not an OpenPGP certificate...
384
if gnutls.library.functions.gnutls_certificate_type_get\
385
(session._c_object) \
386
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP:
387
# ...do the normal thing
388
return session.peer_certificate
389
list_size = ctypes.c_uint()
390
cert_list = gnutls.library.functions.gnutls_certificate_get_peers\
391
(session._c_object, ctypes.byref(list_size))
392
if list_size.value == 0:
395
return ctypes.string_at(cert.data, cert.size)
398
def fingerprint(openpgp):
399
"Convert an OpenPGP bytestring to a hexdigit fingerprint string"
400
# New GnuTLS "datum" with the OpenPGP public key
401
datum = gnutls.library.types.gnutls_datum_t\
402
(ctypes.cast(ctypes.c_char_p(openpgp),
403
ctypes.POINTER(ctypes.c_ubyte)),
404
ctypes.c_uint(len(openpgp)))
405
# New empty GnuTLS certificate
406
crt = gnutls.library.types.gnutls_openpgp_crt_t()
407
gnutls.library.functions.gnutls_openpgp_crt_init\
409
# Import the OpenPGP public key into the certificate
410
gnutls.library.functions.gnutls_openpgp_crt_import\
411
(crt, ctypes.byref(datum),
412
gnutls.library.constants.GNUTLS_OPENPGP_FMT_RAW)
413
# Verify the self signature in the key
414
crtverify = ctypes.c_uint();
415
gnutls.library.functions.gnutls_openpgp_crt_verify_self\
416
(crt, ctypes.c_uint(0), ctypes.byref(crtverify))
417
if crtverify.value != 0:
418
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
419
raise gnutls.errors.CertificateSecurityError("Verify failed")
420
# New buffer for the fingerprint
421
buffer = ctypes.create_string_buffer(20)
422
buffer_length = ctypes.c_size_t()
423
# Get the fingerprint from the certificate into the buffer
424
gnutls.library.functions.gnutls_openpgp_crt_get_fingerprint\
425
(crt, ctypes.byref(buffer), ctypes.byref(buffer_length))
426
# Deinit the certificate
427
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
428
# Convert the buffer to a Python bytestring
429
fpr = ctypes.string_at(buffer, buffer_length.value)
430
# Convert the bytestring to hexadecimal notation
431
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
435
class tcp_handler(SocketServer.BaseRequestHandler, object):
436
"""A TCP request handler class.
437
Instantiated by IPv6_TCPServer for each request to handle it.
488
def dbus_service_property(dbus_interface, signature=u"v",
489
access=u"readwrite", byte_arrays=False):
490
"""Decorators for marking methods of a DBusObjectWithProperties to
491
become properties on the D-Bus.
493
The decorated method will be called with no arguments by "Get"
494
and with one argument by "Set".
496
The parameters, where they are supported, are the same as
497
dbus.service.method, except there is only "signature", since the
498
type from Get() and the type sent to Set() is the same.
501
func._dbus_is_property = True
502
func._dbus_interface = dbus_interface
503
func._dbus_signature = signature
504
func._dbus_access = access
505
func._dbus_name = func.__name__
506
if func._dbus_name.endswith(u"_dbus_property"):
507
func._dbus_name = func._dbus_name[:-14]
508
func._dbus_get_args_options = {u'byte_arrays': byte_arrays }
513
class DBusPropertyException(dbus.exceptions.DBusException):
514
"""A base class for D-Bus property-related exceptions
516
def __unicode__(self):
517
return unicode(str(self))
520
class DBusPropertyAccessException(DBusPropertyException):
521
"""A property's access permissions disallows an operation.
526
class DBusPropertyNotFound(DBusPropertyException):
527
"""An attempt was made to access a non-existing property.
532
class DBusObjectWithProperties(dbus.service.Object):
533
"""A D-Bus object with properties.
535
Classes inheriting from this can use the dbus_service_property
536
decorator to expose methods as D-Bus properties. It exposes the
537
standard Get(), Set(), and GetAll() methods on the D-Bus.
541
def _is_dbus_property(obj):
542
return getattr(obj, u"_dbus_is_property", False)
544
def _get_all_dbus_properties(self):
545
"""Returns a generator of (name, attribute) pairs
547
return ((prop._dbus_name, prop)
549
inspect.getmembers(self, self._is_dbus_property))
551
def _get_dbus_property(self, interface_name, property_name):
552
"""Returns a bound method if one exists which is a D-Bus
553
property with the specified name and interface.
555
for name in (property_name,
556
property_name + u"_dbus_property"):
557
prop = getattr(self, name, None)
559
or not self._is_dbus_property(prop)
560
or prop._dbus_name != property_name
561
or (interface_name and prop._dbus_interface
562
and interface_name != prop._dbus_interface)):
566
raise DBusPropertyNotFound(self.dbus_object_path + u":"
567
+ interface_name + u"."
570
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ss",
572
def Get(self, interface_name, property_name):
573
"""Standard D-Bus property Get() method, see D-Bus standard.
575
prop = self._get_dbus_property(interface_name, property_name)
576
if prop._dbus_access == u"write":
577
raise DBusPropertyAccessException(property_name)
579
if not hasattr(value, u"variant_level"):
581
return type(value)(value, variant_level=value.variant_level+1)
583
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"ssv")
584
def Set(self, interface_name, property_name, value):
585
"""Standard D-Bus property Set() method, see D-Bus standard.
587
prop = self._get_dbus_property(interface_name, property_name)
588
if prop._dbus_access == u"read":
589
raise DBusPropertyAccessException(property_name)
590
if prop._dbus_get_args_options[u"byte_arrays"]:
591
value = dbus.ByteArray(''.join(unichr(byte)
595
@dbus.service.method(dbus.PROPERTIES_IFACE, in_signature=u"s",
596
out_signature=u"a{sv}")
597
def GetAll(self, interface_name):
598
"""Standard D-Bus property GetAll() method, see D-Bus
601
Note: Will not include properties with access="write".
604
for name, prop in self._get_all_dbus_properties():
606
and interface_name != prop._dbus_interface):
607
# Interface non-empty but did not match
609
# Ignore write-only properties
610
if prop._dbus_access == u"write":
613
if not hasattr(value, u"variant_level"):
616
all[name] = type(value)(value, variant_level=
617
value.variant_level+1)
618
return dbus.Dictionary(all, signature=u"sv")
620
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
622
path_keyword='object_path',
623
connection_keyword='connection')
624
def Introspect(self, object_path, connection):
625
"""Standard D-Bus method, overloaded to insert property tags.
627
xmlstring = dbus.service.Object.Introspect(self, object_path,
629
document = xml.dom.minidom.parseString(xmlstring)
631
def make_tag(document, name, prop):
632
e = document.createElement(u"property")
633
e.setAttribute(u"name", name)
634
e.setAttribute(u"type", prop._dbus_signature)
635
e.setAttribute(u"access", prop._dbus_access)
637
for if_tag in document.getElementsByTagName(u"interface"):
638
for tag in (make_tag(document, name, prop)
640
in self._get_all_dbus_properties()
641
if prop._dbus_interface
642
== if_tag.getAttribute(u"name")):
643
if_tag.appendChild(tag)
644
xmlstring = document.toxml(u"utf-8")
649
class ClientDBus(Client, DBusObjectWithProperties):
650
"""A Client class using D-Bus
653
dbus_object_path: dbus.ObjectPath
654
bus: dbus.SystemBus()
656
# dbus.service.Object doesn't use super(), so we can't either.
658
def __init__(self, bus = None, *args, **kwargs):
660
Client.__init__(self, *args, **kwargs)
661
# Only now, when this client is initialized, can it show up on
663
self.dbus_object_path = (dbus.ObjectPath
665
+ self.name.replace(u".", u"_")))
666
DBusObjectWithProperties.__init__(self, self.bus,
667
self.dbus_object_path)
670
def _datetime_to_dbus(dt, variant_level=0):
671
"""Convert a UTC datetime.datetime() to a D-Bus type."""
672
return dbus.String(dt.isoformat(),
673
variant_level=variant_level)
676
oldstate = getattr(self, u"enabled", False)
677
r = Client.enable(self)
678
if oldstate != self.enabled:
680
self.PropertyChanged(dbus.String(u"enabled"),
681
dbus.Boolean(True, variant_level=1))
682
self.PropertyChanged(
683
dbus.String(u"last_enabled"),
684
self._datetime_to_dbus(self.last_enabled,
688
def disable(self, signal = True):
689
oldstate = getattr(self, u"enabled", False)
690
r = Client.disable(self)
691
if signal and oldstate != self.enabled:
693
self.PropertyChanged(dbus.String(u"enabled"),
694
dbus.Boolean(False, variant_level=1))
697
def __del__(self, *args, **kwargs):
699
self.remove_from_connection()
702
if hasattr(DBusObjectWithProperties, u"__del__"):
703
DBusObjectWithProperties.__del__(self, *args, **kwargs)
704
Client.__del__(self, *args, **kwargs)
706
def checker_callback(self, pid, condition, command,
708
self.checker_callback_tag = None
711
self.PropertyChanged(dbus.String(u"checker_running"),
712
dbus.Boolean(False, variant_level=1))
713
if os.WIFEXITED(condition):
714
exitstatus = os.WEXITSTATUS(condition)
716
self.CheckerCompleted(dbus.Int16(exitstatus),
717
dbus.Int64(condition),
718
dbus.String(command))
721
self.CheckerCompleted(dbus.Int16(-1),
722
dbus.Int64(condition),
723
dbus.String(command))
725
return Client.checker_callback(self, pid, condition, command,
728
def checked_ok(self, *args, **kwargs):
729
r = Client.checked_ok(self, *args, **kwargs)
731
self.PropertyChanged(
732
dbus.String(u"last_checked_ok"),
733
(self._datetime_to_dbus(self.last_checked_ok,
737
def start_checker(self, *args, **kwargs):
738
old_checker = self.checker
739
if self.checker is not None:
740
old_checker_pid = self.checker.pid
742
old_checker_pid = None
743
r = Client.start_checker(self, *args, **kwargs)
744
# Only if new checker process was started
745
if (self.checker is not None
746
and old_checker_pid != self.checker.pid):
748
self.CheckerStarted(self.current_checker_command)
749
self.PropertyChanged(
750
dbus.String(u"checker_running"),
751
dbus.Boolean(True, variant_level=1))
754
def stop_checker(self, *args, **kwargs):
755
old_checker = getattr(self, u"checker", None)
756
r = Client.stop_checker(self, *args, **kwargs)
757
if (old_checker is not None
758
and getattr(self, u"checker", None) is None):
759
self.PropertyChanged(dbus.String(u"checker_running"),
760
dbus.Boolean(False, variant_level=1))
763
## D-Bus methods & signals
764
_interface = u"se.bsnet.fukt.Mandos.Client"
767
@dbus.service.method(_interface)
769
return self.checked_ok()
771
# CheckerCompleted - signal
772
@dbus.service.signal(_interface, signature=u"nxs")
773
def CheckerCompleted(self, exitcode, waitstatus, command):
777
# CheckerStarted - signal
778
@dbus.service.signal(_interface, signature=u"s")
779
def CheckerStarted(self, command):
783
# PropertyChanged - signal
784
@dbus.service.signal(_interface, signature=u"sv")
785
def PropertyChanged(self, property, value):
789
# ReceivedSecret - signal
790
@dbus.service.signal(_interface)
791
def ReceivedSecret(self):
796
@dbus.service.signal(_interface)
802
@dbus.service.method(_interface)
807
# StartChecker - method
808
@dbus.service.method(_interface)
809
def StartChecker(self):
814
@dbus.service.method(_interface)
819
# StopChecker - method
820
@dbus.service.method(_interface)
821
def StopChecker(self):
825
@dbus_service_property(_interface, signature=u"s", access=u"read")
826
def name_dbus_property(self):
827
return dbus.String(self.name)
829
# fingerprint - property
830
@dbus_service_property(_interface, signature=u"s", access=u"read")
831
def fingerprint_dbus_property(self):
832
return dbus.String(self.fingerprint)
835
@dbus_service_property(_interface, signature=u"s",
837
def host_dbus_property(self, value=None):
838
if value is None: # get
839
return dbus.String(self.host)
842
self.PropertyChanged(dbus.String(u"host"),
843
dbus.String(value, variant_level=1))
846
@dbus_service_property(_interface, signature=u"s", access=u"read")
847
def created_dbus_property(self):
848
return dbus.String(self._datetime_to_dbus(self.created))
850
# last_enabled - property
851
@dbus_service_property(_interface, signature=u"s", access=u"read")
852
def last_enabled_dbus_property(self):
853
if self.last_enabled is None:
854
return dbus.String(u"")
855
return dbus.String(self._datetime_to_dbus(self.last_enabled))
858
@dbus_service_property(_interface, signature=u"b",
860
def enabled_dbus_property(self, value=None):
861
if value is None: # get
862
return dbus.Boolean(self.enabled)
868
# last_checked_ok - property
869
@dbus_service_property(_interface, signature=u"s",
871
def last_checked_ok_dbus_property(self, value=None):
872
if value is not None:
875
if self.last_checked_ok is None:
876
return dbus.String(u"")
877
return dbus.String(self._datetime_to_dbus(self
881
@dbus_service_property(_interface, signature=u"t",
883
def timeout_dbus_property(self, value=None):
884
if value is None: # get
885
return dbus.UInt64(self.timeout_milliseconds())
886
self.timeout = datetime.timedelta(0, 0, 0, value)
888
self.PropertyChanged(dbus.String(u"timeout"),
889
dbus.UInt64(value, variant_level=1))
890
if getattr(self, u"disable_initiator_tag", None) is None:
893
gobject.source_remove(self.disable_initiator_tag)
894
self.disable_initiator_tag = None
896
_timedelta_to_milliseconds((self
902
# The timeout has passed
905
self.disable_initiator_tag = (gobject.timeout_add
906
(time_to_die, self.disable))
908
# interval - property
909
@dbus_service_property(_interface, signature=u"t",
911
def interval_dbus_property(self, value=None):
912
if value is None: # get
913
return dbus.UInt64(self.interval_milliseconds())
914
self.interval = datetime.timedelta(0, 0, 0, value)
916
self.PropertyChanged(dbus.String(u"interval"),
917
dbus.UInt64(value, variant_level=1))
918
if getattr(self, u"checker_initiator_tag", None) is None:
920
# Reschedule checker run
921
gobject.source_remove(self.checker_initiator_tag)
922
self.checker_initiator_tag = (gobject.timeout_add
923
(value, self.start_checker))
924
self.start_checker() # Start one now, too
927
@dbus_service_property(_interface, signature=u"s",
929
def checker_dbus_property(self, value=None):
930
if value is None: # get
931
return dbus.String(self.checker_command)
932
self.checker_command = value
934
self.PropertyChanged(dbus.String(u"checker"),
935
dbus.String(self.checker_command,
938
# checker_running - property
939
@dbus_service_property(_interface, signature=u"b",
941
def checker_running_dbus_property(self, value=None):
942
if value is None: # get
943
return dbus.Boolean(self.checker is not None)
949
# object_path - property
950
@dbus_service_property(_interface, signature=u"o", access=u"read")
951
def object_path_dbus_property(self):
952
return self.dbus_object_path # is already a dbus.ObjectPath
955
@dbus_service_property(_interface, signature=u"ay",
956
access=u"write", byte_arrays=True)
957
def secret_dbus_property(self, value):
958
self.secret = str(value)
963
class ClientHandler(socketserver.BaseRequestHandler, object):
964
"""A class to handle client connections.
966
Instantiated once for each connection to handle it.
438
967
Note: This will run in its own forked process."""
440
969
def handle(self):
441
970
logger.info(u"TCP connection from: %s",
442
unicode(self.client_address))
443
session = gnutls.connection.ClientSession\
444
(self.request, gnutls.connection.X509Credentials())
446
line = self.request.makefile().readline()
447
logger.debug(u"Protocol version: %r", line)
449
if int(line.strip().split()[0]) > 1:
451
except (ValueError, IndexError, RuntimeError), error:
452
logger.error(u"Unknown protocol version: %s", error)
455
# Note: gnutls.connection.X509Credentials is really a generic
456
# GnuTLS certificate credentials object so long as no X.509
457
# keys are added to it. Therefore, we can use it here despite
458
# using OpenPGP certificates.
460
#priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
461
# "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
463
priority = "NORMAL" # Fallback default, since this
465
if self.server.settings["priority"]:
466
priority = self.server.settings["priority"]
467
gnutls.library.functions.gnutls_priority_set_direct\
468
(session._c_object, priority, None);
472
except gnutls.errors.GNUTLSError, error:
473
logger.warning(u"Handshake failed: %s", error)
474
# Do not run session.bye() here: the session is not
475
# established. Just abandon the request.
478
fpr = fingerprint(peer_certificate(session))
479
except (TypeError, gnutls.errors.GNUTLSError), error:
480
logger.warning(u"Bad certificate: %s", error)
483
logger.debug(u"Fingerprint: %s", fpr)
485
for c in self.server.clients:
486
if c.fingerprint == fpr:
490
logger.warning(u"Client not found for fingerprint: %s",
494
# Have to check if client.still_valid(), since it is possible
495
# that the client timed out while establishing the GnuTLS
497
if not client.still_valid():
498
logger.warning(u"Client %(name)s is invalid",
503
while sent_size < len(client.secret):
504
sent = session.send(client.secret[sent_size:])
505
logger.debug(u"Sent: %d, remaining: %d",
506
sent, len(client.secret)
507
- (sent_size + sent))
512
class IPv6_TCPServer(SocketServer.ForkingTCPServer, object):
513
"""IPv6 TCP server. Accepts 'None' as address and/or port.
971
unicode(self.client_address))
972
logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
973
# Open IPC pipe to parent process
974
with closing(os.fdopen(self.server.pipe[1], u"w", 1)) as ipc:
975
session = (gnutls.connection
976
.ClientSession(self.request,
980
line = self.request.makefile().readline()
981
logger.debug(u"Protocol version: %r", line)
983
if int(line.strip().split()[0]) > 1:
985
except (ValueError, IndexError, RuntimeError), error:
986
logger.error(u"Unknown protocol version: %s", error)
989
# Note: gnutls.connection.X509Credentials is really a
990
# generic GnuTLS certificate credentials object so long as
991
# no X.509 keys are added to it. Therefore, we can use it
992
# here despite using OpenPGP certificates.
994
#priority = u':'.join((u"NONE", u"+VERS-TLS1.1",
995
# u"+AES-256-CBC", u"+SHA1",
996
# u"+COMP-NULL", u"+CTYPE-OPENPGP",
998
# Use a fallback default, since this MUST be set.
999
priority = self.server.gnutls_priority
1000
if priority is None:
1001
priority = u"NORMAL"
1002
(gnutls.library.functions
1003
.gnutls_priority_set_direct(session._c_object,
1008
except gnutls.errors.GNUTLSError, error:
1009
logger.warning(u"Handshake failed: %s", error)
1010
# Do not run session.bye() here: the session is not
1011
# established. Just abandon the request.
1013
logger.debug(u"Handshake succeeded")
1015
fpr = self.fingerprint(self.peer_certificate(session))
1016
except (TypeError, gnutls.errors.GNUTLSError), error:
1017
logger.warning(u"Bad certificate: %s", error)
1020
logger.debug(u"Fingerprint: %s", fpr)
1022
for c in self.server.clients:
1023
if c.fingerprint == fpr:
1027
ipc.write(u"NOTFOUND %s %s\n"
1028
% (fpr, unicode(self.client_address)))
1031
# Have to check if client.still_valid(), since it is
1032
# possible that the client timed out while establishing
1033
# the GnuTLS session.
1034
if not client.still_valid():
1035
ipc.write(u"INVALID %s\n" % client.name)
1038
ipc.write(u"SENDING %s\n" % client.name)
1040
while sent_size < len(client.secret):
1041
sent = session.send(client.secret[sent_size:])
1042
logger.debug(u"Sent: %d, remaining: %d",
1043
sent, len(client.secret)
1044
- (sent_size + sent))
1049
def peer_certificate(session):
1050
"Return the peer's OpenPGP certificate as a bytestring"
1051
# If not an OpenPGP certificate...
1052
if (gnutls.library.functions
1053
.gnutls_certificate_type_get(session._c_object)
1054
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP):
1055
# ...do the normal thing
1056
return session.peer_certificate
1057
list_size = ctypes.c_uint(1)
1058
cert_list = (gnutls.library.functions
1059
.gnutls_certificate_get_peers
1060
(session._c_object, ctypes.byref(list_size)))
1061
if not bool(cert_list) and list_size.value != 0:
1062
raise gnutls.errors.GNUTLSError(u"error getting peer"
1064
if list_size.value == 0:
1067
return ctypes.string_at(cert.data, cert.size)
1070
def fingerprint(openpgp):
1071
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
1072
# New GnuTLS "datum" with the OpenPGP public key
1073
datum = (gnutls.library.types
1074
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
1077
ctypes.c_uint(len(openpgp))))
1078
# New empty GnuTLS certificate
1079
crt = gnutls.library.types.gnutls_openpgp_crt_t()
1080
(gnutls.library.functions
1081
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
1082
# Import the OpenPGP public key into the certificate
1083
(gnutls.library.functions
1084
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
1085
gnutls.library.constants
1086
.GNUTLS_OPENPGP_FMT_RAW))
1087
# Verify the self signature in the key
1088
crtverify = ctypes.c_uint()
1089
(gnutls.library.functions
1090
.gnutls_openpgp_crt_verify_self(crt, 0,
1091
ctypes.byref(crtverify)))
1092
if crtverify.value != 0:
1093
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
1094
raise (gnutls.errors.CertificateSecurityError
1096
# New buffer for the fingerprint
1097
buf = ctypes.create_string_buffer(20)
1098
buf_len = ctypes.c_size_t()
1099
# Get the fingerprint from the certificate into the buffer
1100
(gnutls.library.functions
1101
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
1102
ctypes.byref(buf_len)))
1103
# Deinit the certificate
1104
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
1105
# Convert the buffer to a Python bytestring
1106
fpr = ctypes.string_at(buf, buf_len.value)
1107
# Convert the bytestring to hexadecimal notation
1108
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
1112
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
1113
"""Like socketserver.ForkingMixIn, but also pass a pipe."""
1114
def process_request(self, request, client_address):
1115
"""Overrides and wraps the original process_request().
1117
This function creates a new pipe in self.pipe
1119
self.pipe = os.pipe()
1120
super(ForkingMixInWithPipe,
1121
self).process_request(request, client_address)
1122
os.close(self.pipe[1]) # close write end
1123
self.add_pipe(self.pipe[0])
1124
def add_pipe(self, pipe):
1125
"""Dummy function; override as necessary"""
1129
class IPv6_TCPServer(ForkingMixInWithPipe,
1130
socketserver.TCPServer, object):
1131
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
515
settings: Server settings
516
clients: Set() of Client objects
1134
enabled: Boolean; whether this server is activated yet
1135
interface: None or a network interface name (string)
1136
use_ipv6: Boolean; to use IPv6 or not
518
address_family = socket.AF_INET6
519
def __init__(self, *args, **kwargs):
520
if "settings" in kwargs:
521
self.settings = kwargs["settings"]
522
del kwargs["settings"]
523
if "clients" in kwargs:
524
self.clients = kwargs["clients"]
525
del kwargs["clients"]
526
return super(type(self), self).__init__(*args, **kwargs)
1138
def __init__(self, server_address, RequestHandlerClass,
1139
interface=None, use_ipv6=True):
1140
self.interface = interface
1142
self.address_family = socket.AF_INET6
1143
socketserver.TCPServer.__init__(self, server_address,
1144
RequestHandlerClass)
527
1145
def server_bind(self):
528
1146
"""This overrides the normal server_bind() function
529
1147
to bind to an interface if one was specified, and also NOT to
530
1148
bind to an address or port if they were not specified."""
531
if self.settings["interface"]:
532
# 25 is from /usr/include/asm-i486/socket.h
533
SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
535
self.socket.setsockopt(socket.SOL_SOCKET,
537
self.settings["interface"])
538
except socket.error, error:
539
if error[0] == errno.EPERM:
540
logger.error(u"No permission to"
541
u" bind to interface %s",
542
self.settings["interface"])
1149
if self.interface is not None:
1150
if SO_BINDTODEVICE is None:
1151
logger.error(u"SO_BINDTODEVICE does not exist;"
1152
u" cannot bind to interface %s",
1156
self.socket.setsockopt(socket.SOL_SOCKET,
1160
except socket.error, error:
1161
if error[0] == errno.EPERM:
1162
logger.error(u"No permission to"
1163
u" bind to interface %s",
1165
elif error[0] == errno.ENOPROTOOPT:
1166
logger.error(u"SO_BINDTODEVICE not available;"
1167
u" cannot bind to interface %s",
545
1171
# Only bind(2) the socket if we really need to.
546
1172
if self.server_address[0] or self.server_address[1]:
547
1173
if not self.server_address[0]:
549
self.server_address = (in6addr_any,
1174
if self.address_family == socket.AF_INET6:
1175
any_address = u"::" # in6addr_any
1177
any_address = socket.INADDR_ANY
1178
self.server_address = (any_address,
550
1179
self.server_address[1])
551
1180
elif not self.server_address[1]:
552
1181
self.server_address = (self.server_address[0],
554
# if self.settings["interface"]:
1183
# if self.interface:
555
1184
# self.server_address = (self.server_address[0],
558
1187
# if_nametoindex
561
return super(type(self), self).server_bind()
1189
return socketserver.TCPServer.server_bind(self)
1192
class MandosServer(IPv6_TCPServer):
1196
clients: set of Client objects
1197
gnutls_priority GnuTLS priority string
1198
use_dbus: Boolean; to emit D-Bus signals or not
1200
Assumes a gobject.MainLoop event loop.
1202
def __init__(self, server_address, RequestHandlerClass,
1203
interface=None, use_ipv6=True, clients=None,
1204
gnutls_priority=None, use_dbus=True):
1205
self.enabled = False
1206
self.clients = clients
1207
if self.clients is None:
1208
self.clients = set()
1209
self.use_dbus = use_dbus
1210
self.gnutls_priority = gnutls_priority
1211
IPv6_TCPServer.__init__(self, server_address,
1212
RequestHandlerClass,
1213
interface = interface,
1214
use_ipv6 = use_ipv6)
1215
def server_activate(self):
1217
return socketserver.TCPServer.server_activate(self)
1220
def add_pipe(self, pipe):
1221
# Call "handle_ipc" for both data and EOF events
1222
gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
1224
def handle_ipc(self, source, condition, file_objects={}):
1226
gobject.IO_IN: u"IN", # There is data to read.
1227
gobject.IO_OUT: u"OUT", # Data can be written (without
1229
gobject.IO_PRI: u"PRI", # There is urgent data to read.
1230
gobject.IO_ERR: u"ERR", # Error condition.
1231
gobject.IO_HUP: u"HUP" # Hung up (the connection has been
1232
# broken, usually for pipes and
1235
conditions_string = ' | '.join(name
1237
condition_names.iteritems()
1238
if cond & condition)
1239
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
1242
# Turn the pipe file descriptor into a Python file object
1243
if source not in file_objects:
1244
file_objects[source] = os.fdopen(source, u"r", 1)
1246
# Read a line from the file object
1247
cmdline = file_objects[source].readline()
1248
if not cmdline: # Empty line means end of file
1249
# close the IPC pipe
1250
file_objects[source].close()
1251
del file_objects[source]
1253
# Stop calling this function
1256
logger.debug(u"IPC command: %r", cmdline)
1258
# Parse and act on command
1259
cmd, args = cmdline.rstrip(u"\r\n").split(None, 1)
1261
if cmd == u"NOTFOUND":
1262
logger.warning(u"Client not found for fingerprint: %s",
1266
mandos_dbus_service.ClientNotFound(args)
1267
elif cmd == u"INVALID":
1268
for client in self.clients:
1269
if client.name == args:
1270
logger.warning(u"Client %s is invalid", args)
1276
logger.error(u"Unknown client %s is invalid", args)
1277
elif cmd == u"SENDING":
1278
for client in self.clients:
1279
if client.name == args:
1280
logger.info(u"Sending secret to %s", client.name)
1284
client.ReceivedSecret()
1287
logger.error(u"Sending secret to unknown client %s",
1290
logger.error(u"Unknown IPC command: %r", cmdline)
1292
# Keep calling this function
564
1296
def string_to_delta(interval):
565
1297
"""Parse a string and return a datetime.timedelta
567
>>> string_to_delta('7d')
1299
>>> string_to_delta(u'7d')
568
1300
datetime.timedelta(7)
569
>>> string_to_delta('60s')
1301
>>> string_to_delta(u'60s')
570
1302
datetime.timedelta(0, 60)
571
>>> string_to_delta('60m')
1303
>>> string_to_delta(u'60m')
572
1304
datetime.timedelta(0, 3600)
573
>>> string_to_delta('24h')
1305
>>> string_to_delta(u'24h')
574
1306
datetime.timedelta(1)
575
1307
>>> string_to_delta(u'1w')
576
1308
datetime.timedelta(7)
577
>>> string_to_delta('5m 30s')
1309
>>> string_to_delta(u'5m 30s')
578
1310
datetime.timedelta(0, 330)
580
1312
timevalue = datetime.timedelta(0)
581
1313
for s in interval.split():
583
suffix=unicode(s[-1])
1315
suffix = unicode(s[-1])
585
1317
if suffix == u"d":
586
1318
delta = datetime.timedelta(value)
587
1319
elif suffix == u"s":
705
1420
# Default values for config file for server-global settings
706
server_defaults = { "interface": "",
711
"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
712
"servicename": "Mandos",
1421
server_defaults = { u"interface": u"",
1426
u"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1427
u"servicename": u"Mandos",
1428
u"use_dbus": u"True",
1429
u"use_ipv6": u"True",
715
1432
# Parse config file for server-global settings
716
server_config = ConfigParser.SafeConfigParser(server_defaults)
1433
server_config = configparser.SafeConfigParser(server_defaults)
717
1434
del server_defaults
718
server_config.read(os.path.join(options.configdir, "mandos.conf"))
1435
server_config.read(os.path.join(options.configdir,
719
1437
# Convert the SafeConfigParser object to a dict
720
1438
server_settings = server_config.defaults()
721
# Use getboolean on the boolean config option
722
server_settings["debug"] = server_config.getboolean\
1439
# Use the appropriate methods on the non-string config options
1440
for option in (u"debug", u"use_dbus", u"use_ipv6"):
1441
server_settings[option] = server_config.getboolean(u"DEFAULT",
1443
if server_settings["port"]:
1444
server_settings["port"] = server_config.getint(u"DEFAULT",
724
1446
del server_config
726
1448
# Override the settings from the config file with command line
727
1449
# options, if set.
728
for option in ("interface", "address", "port", "debug",
729
"priority", "servicename", "configdir"):
1450
for option in (u"interface", u"address", u"port", u"debug",
1451
u"priority", u"servicename", u"configdir",
1452
u"use_dbus", u"use_ipv6"):
730
1453
value = getattr(options, option)
731
1454
if value is not None:
732
1455
server_settings[option] = value
1457
# Force all strings to be unicode
1458
for option in server_settings.keys():
1459
if type(server_settings[option]) is str:
1460
server_settings[option] = unicode(server_settings[option])
734
1461
# Now we have our good server settings in "server_settings"
736
debug = server_settings["debug"]
1463
##################################################################
1466
debug = server_settings[u"debug"]
1467
use_dbus = server_settings[u"use_dbus"]
1468
use_ipv6 = server_settings[u"use_ipv6"]
739
1471
syslogger.setLevel(logging.WARNING)
740
1472
console.setLevel(logging.WARNING)
742
if server_settings["servicename"] != "Mandos":
743
syslogger.setFormatter(logging.Formatter\
744
('Mandos (%s): %%(levelname)s:'
746
% server_settings["servicename"]))
1474
if server_settings[u"servicename"] != u"Mandos":
1475
syslogger.setFormatter(logging.Formatter
1476
(u'Mandos (%s) [%%(process)d]:'
1477
u' %%(levelname)s: %%(message)s'
1478
% server_settings[u"servicename"]))
748
1480
# Parse config file with clients
749
client_defaults = { "timeout": "1h",
751
"checker": "fping -q -- %(host)s",
1481
client_defaults = { u"timeout": u"1h",
1483
u"checker": u"fping -q -- %%(host)s",
754
client_config = ConfigParser.SafeConfigParser(client_defaults)
755
client_config.read(os.path.join(server_settings["configdir"],
759
service = AvahiService(name = server_settings["servicename"],
760
type = "_mandos._tcp", );
761
if server_settings["interface"]:
762
service.interface = if_nametoindex(server_settings["interface"])
1486
client_config = configparser.SafeConfigParser(client_defaults)
1487
client_config.read(os.path.join(server_settings[u"configdir"],
1490
global mandos_dbus_service
1491
mandos_dbus_service = None
1493
tcp_server = MandosServer((server_settings[u"address"],
1494
server_settings[u"port"]),
1496
interface=server_settings[u"interface"],
1499
server_settings[u"priority"],
1501
pidfilename = u"/var/run/mandos.pid"
1503
pidfile = open(pidfilename, u"w")
1505
logger.error(u"Could not open file %r", pidfilename)
1508
uid = pwd.getpwnam(u"_mandos").pw_uid
1509
gid = pwd.getpwnam(u"_mandos").pw_gid
1512
uid = pwd.getpwnam(u"mandos").pw_uid
1513
gid = pwd.getpwnam(u"mandos").pw_gid
1516
uid = pwd.getpwnam(u"nobody").pw_uid
1517
gid = pwd.getpwnam(u"nobody").pw_gid
1524
except OSError, error:
1525
if error[0] != errno.EPERM:
1528
# Enable all possible GnuTLS debugging
1530
# "Use a log level over 10 to enable all debugging options."
1532
gnutls.library.functions.gnutls_global_set_log_level(11)
1534
@gnutls.library.types.gnutls_log_func
1535
def debug_gnutls(level, string):
1536
logger.debug(u"GnuTLS: %s", string[:-1])
1538
(gnutls.library.functions
1539
.gnutls_global_set_log_function(debug_gnutls))
764
1541
global main_loop
767
1542
# From the Avahi example code
768
1543
DBusGMainLoop(set_as_default=True )
769
1544
main_loop = gobject.MainLoop()
770
1545
bus = dbus.SystemBus()
771
server = dbus.Interface(
772
bus.get_object( avahi.DBUS_NAME, avahi.DBUS_PATH_SERVER ),
773
avahi.DBUS_INTERFACE_SERVER )
774
1546
# End of Avahi example code
777
def remove_from_clients(client):
778
clients.remove(client)
780
logger.critical(u"No clients left, exiting")
783
clients.update(Set(Client(name = section,
784
stop_hook = remove_from_clients,
786
= dict(client_config.items(section)))
787
for section in client_config.sections()))
789
logger.critical(u"No clients defined")
1548
bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1549
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1550
service = AvahiService(name = server_settings[u"servicename"],
1551
servicetype = u"_mandos._tcp",
1552
protocol = protocol, bus = bus)
1553
if server_settings["interface"]:
1554
service.interface = (if_nametoindex
1555
(str(server_settings[u"interface"])))
1557
client_class = Client
1559
client_class = functools.partial(ClientDBus, bus = bus)
1560
tcp_server.clients.update(set(
1561
client_class(name = section,
1562
config= dict(client_config.items(section)))
1563
for section in client_config.sections()))
1564
if not tcp_server.clients:
1565
logger.warning(u"No clients defined")
793
1568
# Redirect stdin so all checkers get /dev/null