448
417
return now < (self.created + self.timeout)
450
419
return now < (self.last_checked_ok + self.timeout)
422
class ClientDBus(Client, dbus.service.Object):
423
"""A Client class using D-Bus
425
dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
427
# dbus.service.Object doesn't use super(), so we can't either.
429
def __init__(self, *args, **kwargs):
430
Client.__init__(self, *args, **kwargs)
431
# Only now, when this client is initialized, can it show up on
433
self.dbus_object_path = (dbus.ObjectPath
435
+ self.name.replace(".", "_")))
436
dbus.service.Object.__init__(self, bus,
437
self.dbus_object_path)
439
oldstate = getattr(self, "enabled", False)
440
r = Client.enable(self)
441
if oldstate != self.enabled:
443
self.PropertyChanged(dbus.String(u"enabled"),
444
dbus.Boolean(True, variant_level=1))
445
self.PropertyChanged(dbus.String(u"last_enabled"),
446
(_datetime_to_dbus(self.last_enabled,
450
def disable(self, signal = True):
451
oldstate = getattr(self, "enabled", False)
452
r = Client.disable(self)
453
if signal and oldstate != self.enabled:
455
self.PropertyChanged(dbus.String(u"enabled"),
456
dbus.Boolean(False, variant_level=1))
459
def __del__(self, *args, **kwargs):
461
self.remove_from_connection()
464
if hasattr(dbus.service.Object, "__del__"):
465
dbus.service.Object.__del__(self, *args, **kwargs)
466
Client.__del__(self, *args, **kwargs)
468
def checker_callback(self, pid, condition, command,
470
self.checker_callback_tag = None
473
self.PropertyChanged(dbus.String(u"checker_running"),
474
dbus.Boolean(False, variant_level=1))
475
if os.WIFEXITED(condition):
476
exitstatus = os.WEXITSTATUS(condition)
478
self.CheckerCompleted(dbus.Int16(exitstatus),
479
dbus.Int64(condition),
480
dbus.String(command))
483
self.CheckerCompleted(dbus.Int16(-1),
484
dbus.Int64(condition),
485
dbus.String(command))
487
return Client.checker_callback(self, pid, condition, command,
490
def checked_ok(self, *args, **kwargs):
491
r = Client.checked_ok(self, *args, **kwargs)
493
self.PropertyChanged(
494
dbus.String(u"last_checked_ok"),
495
(_datetime_to_dbus(self.last_checked_ok,
499
def start_checker(self, *args, **kwargs):
500
old_checker = self.checker
501
if self.checker is not None:
502
old_checker_pid = self.checker.pid
504
old_checker_pid = None
505
r = Client.start_checker(self, *args, **kwargs)
506
# Only if new checker process was started
507
if (self.checker is not None
508
and old_checker_pid != self.checker.pid):
510
self.CheckerStarted(self.current_checker_command)
511
self.PropertyChanged(
512
dbus.String("checker_running"),
513
dbus.Boolean(True, variant_level=1))
516
def stop_checker(self, *args, **kwargs):
517
old_checker = getattr(self, "checker", None)
518
r = Client.stop_checker(self, *args, **kwargs)
519
if (old_checker is not None
520
and getattr(self, "checker", None) is None):
521
self.PropertyChanged(dbus.String(u"checker_running"),
522
dbus.Boolean(False, variant_level=1))
452
525
## D-Bus methods & signals
453
526
_interface = u"se.bsnet.fukt.Mandos.Client"
657
742
def handle(self):
658
743
logger.info(u"TCP connection from: %s",
659
744
unicode(self.client_address))
660
session = (gnutls.connection
661
.ClientSession(self.request,
665
line = self.request.makefile().readline()
666
logger.debug(u"Protocol version: %r", line)
668
if int(line.strip().split()[0]) > 1:
670
except (ValueError, IndexError, RuntimeError), error:
671
logger.error(u"Unknown protocol version: %s", error)
674
# Note: gnutls.connection.X509Credentials is really a generic
675
# GnuTLS certificate credentials object so long as no X.509
676
# keys are added to it. Therefore, we can use it here despite
677
# using OpenPGP certificates.
679
#priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
680
# "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
682
# Use a fallback default, since this MUST be set.
683
priority = self.server.settings.get("priority", "NORMAL")
684
(gnutls.library.functions
685
.gnutls_priority_set_direct(session._c_object,
690
except gnutls.errors.GNUTLSError, error:
691
logger.warning(u"Handshake failed: %s", error)
692
# Do not run session.bye() here: the session is not
693
# established. Just abandon the request.
695
logger.debug(u"Handshake succeeded")
697
fpr = fingerprint(peer_certificate(session))
698
except (TypeError, gnutls.errors.GNUTLSError), error:
699
logger.warning(u"Bad certificate: %s", error)
702
logger.debug(u"Fingerprint: %s", fpr)
704
for c in self.server.clients:
705
if c.fingerprint == fpr:
709
logger.warning(u"Client not found for fingerprint: %s",
713
# Have to check if client.still_valid(), since it is possible
714
# that the client timed out while establishing the GnuTLS
716
if not client.still_valid():
717
logger.warning(u"Client %(name)s is invalid",
721
## This won't work here, since we're in a fork.
722
# client.checked_ok()
724
while sent_size < len(client.secret):
725
sent = session.send(client.secret[sent_size:])
726
logger.debug(u"Sent: %d, remaining: %d",
727
sent, len(client.secret)
728
- (sent_size + sent))
733
class IPv6_TCPServer(SocketServer.ForkingMixIn,
745
logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
746
# Open IPC pipe to parent process
747
with closing(os.fdopen(self.server.pipe[1], "w", 1)) as ipc:
748
session = (gnutls.connection
749
.ClientSession(self.request,
753
line = self.request.makefile().readline()
754
logger.debug(u"Protocol version: %r", line)
756
if int(line.strip().split()[0]) > 1:
758
except (ValueError, IndexError, RuntimeError), error:
759
logger.error(u"Unknown protocol version: %s", error)
762
# Note: gnutls.connection.X509Credentials is really a
763
# generic GnuTLS certificate credentials object so long as
764
# no X.509 keys are added to it. Therefore, we can use it
765
# here despite using OpenPGP certificates.
767
#priority = ':'.join(("NONE", "+VERS-TLS1.1",
768
# "+AES-256-CBC", "+SHA1",
769
# "+COMP-NULL", "+CTYPE-OPENPGP",
771
# Use a fallback default, since this MUST be set.
772
priority = self.server.settings.get("priority", "NORMAL")
773
(gnutls.library.functions
774
.gnutls_priority_set_direct(session._c_object,
779
except gnutls.errors.GNUTLSError, error:
780
logger.warning(u"Handshake failed: %s", error)
781
# Do not run session.bye() here: the session is not
782
# established. Just abandon the request.
784
logger.debug(u"Handshake succeeded")
786
fpr = fingerprint(peer_certificate(session))
787
except (TypeError, gnutls.errors.GNUTLSError), error:
788
logger.warning(u"Bad certificate: %s", error)
791
logger.debug(u"Fingerprint: %s", fpr)
793
for c in self.server.clients:
794
if c.fingerprint == fpr:
798
logger.warning(u"Client not found for fingerprint: %s",
800
ipc.write("NOTFOUND %s\n" % fpr)
803
# Have to check if client.still_valid(), since it is
804
# possible that the client timed out while establishing
805
# the GnuTLS session.
806
if not client.still_valid():
807
logger.warning(u"Client %(name)s is invalid",
809
ipc.write("INVALID %s\n" % client.name)
812
ipc.write("SENDING %s\n" % client.name)
814
while sent_size < len(client.secret):
815
sent = session.send(client.secret[sent_size:])
816
logger.debug(u"Sent: %d, remaining: %d",
817
sent, len(client.secret)
818
- (sent_size + sent))
823
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
824
"""Like SocketServer.ForkingMixIn, but also pass a pipe.
825
Assumes a gobject.MainLoop event loop.
827
def process_request(self, request, client_address):
828
"""This overrides and wraps the original process_request().
829
This function creates a new pipe in self.pipe
831
self.pipe = os.pipe()
832
super(ForkingMixInWithPipe,
833
self).process_request(request, client_address)
834
os.close(self.pipe[1]) # close write end
835
# Call "handle_ipc" for both data and EOF events
836
gobject.io_add_watch(self.pipe[0],
837
gobject.IO_IN | gobject.IO_HUP,
839
def handle_ipc(source, condition):
840
"""Dummy function; override as necessary"""
845
class IPv6_TCPServer(ForkingMixInWithPipe,
734
846
SocketServer.TCPServer, object):
735
"""IPv6 TCP server. Accepts 'None' as address and/or port.
847
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
737
849
settings: Server settings
738
850
clients: Set() of Client objects
788
907
return super(IPv6_TCPServer, self).server_activate()
789
908
def enable(self):
790
909
self.enabled = True
910
def handle_ipc(self, source, condition, file_objects={}):
912
gobject.IO_IN: "IN", # There is data to read.
913
gobject.IO_OUT: "OUT", # Data can be written (without
915
gobject.IO_PRI: "PRI", # There is urgent data to read.
916
gobject.IO_ERR: "ERR", # Error condition.
917
gobject.IO_HUP: "HUP" # Hung up (the connection has been
918
# broken, usually for pipes and
921
conditions_string = ' | '.join(name
923
condition_names.iteritems()
925
logger.debug("Handling IPC: FD = %d, condition = %s", source,
928
# Turn the pipe file descriptor into a Python file object
929
if source not in file_objects:
930
file_objects[source] = os.fdopen(source, "r", 1)
932
# Read a line from the file object
933
cmdline = file_objects[source].readline()
934
if not cmdline: # Empty line means end of file
936
file_objects[source].close()
937
del file_objects[source]
939
# Stop calling this function
942
logger.debug("IPC command: %r\n" % cmdline)
944
# Parse and act on command
945
cmd, args = cmdline.split(None, 1)
946
if cmd == "NOTFOUND":
947
if self.settings["use_dbus"]:
949
mandos_dbus_service.ClientNotFound(args)
950
elif cmd == "INVALID":
951
if self.settings["use_dbus"]:
952
for client in self.clients:
953
if client.name == args:
957
elif cmd == "SENDING":
958
for client in self.clients:
959
if client.name == args:
961
if self.settings["use_dbus"]:
963
client.ReceivedSecret()
966
logger.error("Unknown IPC command: %r", cmdline)
968
# Keep calling this function
793
972
def string_to_delta(interval):