319
324
# Emit D-Bus signal
320
325
self.PropertyChanged(dbus.String(u"checker_running"),
321
326
dbus.Boolean(False, variant_level=1))
322
if (os.WIFEXITED(condition)
323
and (os.WEXITSTATUS(condition) == 0)):
324
logger.info(u"Checker for %(name)s succeeded",
327
if os.WIFEXITED(condition):
328
exitstatus = os.WEXITSTATUS(condition)
330
logger.info(u"Checker for %(name)s succeeded",
334
logger.info(u"Checker for %(name)s failed",
326
336
if self.use_dbus:
327
337
# Emit D-Bus signal
328
self.CheckerCompleted(dbus.Boolean(True),
329
dbus.UInt16(condition),
338
self.CheckerCompleted(dbus.Int16(exitstatus),
339
dbus.Int64(condition),
330
340
dbus.String(command))
332
elif not os.WIFEXITED(condition):
333
342
logger.warning(u"Checker for %(name)s crashed?",
335
344
if self.use_dbus:
336
345
# Emit D-Bus signal
337
self.CheckerCompleted(dbus.Boolean(False),
338
dbus.UInt16(condition),
339
dbus.String(command))
341
logger.info(u"Checker for %(name)s failed",
345
self.CheckerCompleted(dbus.Boolean(False),
346
dbus.UInt16(condition),
346
self.CheckerCompleted(dbus.Int16(-1),
347
dbus.Int64(condition),
347
348
dbus.String(command))
349
def bump_timeout(self):
350
def checked_ok(self):
350
351
"""Bump up the timeout for this client.
351
352
This should only be called when the client has been seen,
649
656
def handle(self):
650
657
logger.info(u"TCP connection from: %s",
651
658
unicode(self.client_address))
652
session = (gnutls.connection
653
.ClientSession(self.request,
657
line = self.request.makefile().readline()
658
logger.debug(u"Protocol version: %r", line)
660
if int(line.strip().split()[0]) > 1:
662
except (ValueError, IndexError, RuntimeError), error:
663
logger.error(u"Unknown protocol version: %s", error)
666
# Note: gnutls.connection.X509Credentials is really a generic
667
# GnuTLS certificate credentials object so long as no X.509
668
# keys are added to it. Therefore, we can use it here despite
669
# using OpenPGP certificates.
671
#priority = ':'.join(("NONE", "+VERS-TLS1.1", "+AES-256-CBC",
672
# "+SHA1", "+COMP-NULL", "+CTYPE-OPENPGP",
674
# Use a fallback default, since this MUST be set.
675
priority = self.server.settings.get("priority", "NORMAL")
676
(gnutls.library.functions
677
.gnutls_priority_set_direct(session._c_object,
682
except gnutls.errors.GNUTLSError, error:
683
logger.warning(u"Handshake failed: %s", error)
684
# Do not run session.bye() here: the session is not
685
# established. Just abandon the request.
688
fpr = fingerprint(peer_certificate(session))
689
except (TypeError, gnutls.errors.GNUTLSError), error:
690
logger.warning(u"Bad certificate: %s", error)
693
logger.debug(u"Fingerprint: %s", fpr)
694
for c in self.server.clients:
695
if c.fingerprint == fpr:
699
logger.warning(u"Client not found for fingerprint: %s",
703
# Have to check if client.still_valid(), since it is possible
704
# that the client timed out while establishing the GnuTLS
706
if not client.still_valid():
707
logger.warning(u"Client %(name)s is invalid",
711
## This won't work here, since we're in a fork.
712
# client.bump_timeout()
714
while sent_size < len(client.secret):
715
sent = session.send(client.secret[sent_size:])
716
logger.debug(u"Sent: %d, remaining: %d",
717
sent, len(client.secret)
718
- (sent_size + sent))
723
class IPv6_TCPServer(SocketServer.ForkingMixIn,
659
logger.debug(u"Pipe: %d", self.server.pipe[1])
660
# Open IPC pipe to parent process
661
with closing(os.fdopen(self.server.pipe[1], "w", 1)) as ipc:
662
session = (gnutls.connection
663
.ClientSession(self.request,
667
line = self.request.makefile().readline()
668
logger.debug(u"Protocol version: %r", line)
670
if int(line.strip().split()[0]) > 1:
672
except (ValueError, IndexError, RuntimeError), error:
673
logger.error(u"Unknown protocol version: %s", error)
676
# Note: gnutls.connection.X509Credentials is really a
677
# generic GnuTLS certificate credentials object so long as
678
# no X.509 keys are added to it. Therefore, we can use it
679
# here despite using OpenPGP certificates.
681
#priority = ':'.join(("NONE", "+VERS-TLS1.1",
682
# "+AES-256-CBC", "+SHA1",
683
# "+COMP-NULL", "+CTYPE-OPENPGP",
685
# Use a fallback default, since this MUST be set.
686
priority = self.server.settings.get("priority", "NORMAL")
687
(gnutls.library.functions
688
.gnutls_priority_set_direct(session._c_object,
693
except gnutls.errors.GNUTLSError, error:
694
logger.warning(u"Handshake failed: %s", error)
695
# Do not run session.bye() here: the session is not
696
# established. Just abandon the request.
698
logger.debug(u"Handshake succeeded")
700
fpr = fingerprint(peer_certificate(session))
701
except (TypeError, gnutls.errors.GNUTLSError), error:
702
logger.warning(u"Bad certificate: %s", error)
705
logger.debug(u"Fingerprint: %s", fpr)
706
for c in self.server.clients:
707
if c.fingerprint == fpr:
711
logger.warning(u"Client not found for fingerprint: %s",
713
ipc.write("NOTFOUND %s\n" % fpr)
716
# Have to check if client.still_valid(), since it is
717
# possible that the client timed out while establishing
718
# the GnuTLS session.
719
if not client.still_valid():
720
logger.warning(u"Client %(name)s is invalid",
722
ipc.write("INVALID %s\n" % client.name)
725
ipc.write("SENDING %s\n" % client.name)
726
## This won't work here, since we're in a fork.
727
# client.checked_ok()
729
while sent_size < len(client.secret):
730
sent = session.send(client.secret[sent_size:])
731
logger.debug(u"Sent: %d, remaining: %d",
732
sent, len(client.secret)
733
- (sent_size + sent))
738
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
739
"""Like SocketServer.ForkingMixIn, but also pass a pipe.
740
Assumes a gobject.MainLoop event loop.
742
def process_request(self, request, client_address):
743
"""This overrides and wraps the original process_request().
744
This function creates a new pipe in self.pipe
746
self.pipe = os.pipe()
747
super(ForkingMixInWithPipe,
748
self).process_request(request, client_address)
749
os.close(self.pipe[1]) # close write end
750
# Call "handle_ipc" for both data and EOF events
751
gobject.io_add_watch(self.pipe[0],
752
gobject.IO_IN | gobject.IO_HUP,
754
def handle_ipc(source, condition):
755
"""Dummy function; override as necessary"""
760
class IPv6_TCPServer(ForkingMixInWithPipe,
724
761
SocketServer.TCPServer, object):
725
762
"""IPv6 TCP server. Accepts 'None' as address and/or port.
778
815
return super(IPv6_TCPServer, self).server_activate()
779
816
def enable(self):
780
817
self.enabled = True
818
def handle_ipc(self, source, condition, file_objects={}):
819
logger.debug("Handling IPC: %r : %r", source, condition)
821
# Turn a file descriptor into a Python file object
822
if source not in file_objects:
823
file_objects[source] = os.fdopen(source, "r", 1)
825
# Read a line from the file object
826
cmdline = file_objects[source].readline()
827
if not cmdline: # Empty line means end of file
829
logger.debug("Closing: %r", source)
830
file_objects[source].close()
831
del file_objects[source]
833
# Stop calling this function
836
logger.debug("IPC command: %r\n" % cmdline)
838
# Parse and act on command
839
cmd, args = cmdline.split(None, 1)
840
if cmd == "NOTFOUND":
842
elif cmd == "INVALID":
844
elif cmd == "SENDING":
847
logger.error("Unknown IPC command: %r", cmdline)
849
# Keep calling this function
783
853
def string_to_delta(interval):
1098
1164
class MandosServer(dbus.service.Object):
1099
1165
"""A D-Bus proxy object"""
1100
1166
def __init__(self):
1101
dbus.service.Object.__init__(self, bus,
1103
_interface = u"org.mandos_system.Mandos"
1167
dbus.service.Object.__init__(self, bus, "/")
1168
_interface = u"se.bsnet.fukt.Mandos"
1105
1170
@dbus.service.signal(_interface, signature="oa{sv}")
1106
1171
def ClientAdded(self, objpath, properties):
1110
@dbus.service.signal(_interface, signature="o")
1111
def ClientRemoved(self, objpath):
1175
@dbus.service.signal(_interface, signature="os")
1176
def ClientRemoved(self, objpath, name):
1115
1180
@dbus.service.method(_interface, out_signature="ao")
1116
1181
def GetAllClients(self):
1117
1183
return dbus.Array(c.dbus_object_path for c in clients)
1119
1185
@dbus.service.method(_interface, out_signature="a{oa{sv}}")
1120
1186
def GetAllClientsWithProperties(self):
1121
1188
return dbus.Dictionary(
1122
1189
((c.dbus_object_path, c.GetAllProperties())
1123
1190
for c in clients),
1124
1191
signature="oa{sv}")
1126
1193
@dbus.service.method(_interface, in_signature="o")
1127
1194
def RemoveClient(self, object_path):
1128
1196
for c in clients:
1129
1197
if c.dbus_object_path == object_path:
1130
1198
clients.remove(c)