330
319
# Emit D-Bus signal
331
320
self.PropertyChanged(dbus.String(u"checker_running"),
332
321
dbus.Boolean(False, variant_level=1))
333
if os.WIFEXITED(condition):
334
exitstatus = os.WEXITSTATUS(condition)
336
logger.info(u"Checker for %(name)s succeeded",
340
logger.info(u"Checker for %(name)s failed",
322
if (os.WIFEXITED(condition)
323
and (os.WEXITSTATUS(condition) == 0)):
324
logger.info(u"Checker for %(name)s succeeded",
342
326
if self.use_dbus:
343
327
# Emit D-Bus signal
344
self.CheckerCompleted(dbus.Int16(exitstatus),
345
dbus.Int64(condition),
328
self.CheckerCompleted(dbus.Boolean(True),
329
dbus.UInt16(condition),
346
330
dbus.String(command))
332
elif not os.WIFEXITED(condition):
348
333
logger.warning(u"Checker for %(name)s crashed?",
350
335
if self.use_dbus:
351
336
# Emit D-Bus signal
352
self.CheckerCompleted(dbus.Int16(-1),
353
dbus.Int64(condition),
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),
354
347
dbus.String(command))
356
def checked_ok(self):
349
def bump_timeout(self):
357
350
"""Bump up the timeout for this client.
358
351
This should only be called when the client has been seen,
691
649
def handle(self):
692
650
logger.info(u"TCP connection from: %s",
693
651
unicode(self.client_address))
694
logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
695
# Open IPC pipe to parent process
696
with closing(os.fdopen(self.server.pipe[1], "w", 1)) as ipc:
697
session = (gnutls.connection
698
.ClientSession(self.request,
702
line = self.request.makefile().readline()
703
logger.debug(u"Protocol version: %r", line)
705
if int(line.strip().split()[0]) > 1:
707
except (ValueError, IndexError, RuntimeError), error:
708
logger.error(u"Unknown protocol version: %s", error)
711
# Note: gnutls.connection.X509Credentials is really a
712
# generic GnuTLS certificate credentials object so long as
713
# no X.509 keys are added to it. Therefore, we can use it
714
# here despite using OpenPGP certificates.
716
#priority = ':'.join(("NONE", "+VERS-TLS1.1",
717
# "+AES-256-CBC", "+SHA1",
718
# "+COMP-NULL", "+CTYPE-OPENPGP",
720
# Use a fallback default, since this MUST be set.
721
priority = self.server.settings.get("priority", "NORMAL")
722
(gnutls.library.functions
723
.gnutls_priority_set_direct(session._c_object,
728
except gnutls.errors.GNUTLSError, error:
729
logger.warning(u"Handshake failed: %s", error)
730
# Do not run session.bye() here: the session is not
731
# established. Just abandon the request.
733
logger.debug(u"Handshake succeeded")
735
fpr = fingerprint(peer_certificate(session))
736
except (TypeError, gnutls.errors.GNUTLSError), error:
737
logger.warning(u"Bad certificate: %s", error)
740
logger.debug(u"Fingerprint: %s", fpr)
742
for c in self.server.clients:
743
if c.fingerprint == fpr:
747
logger.warning(u"Client not found for fingerprint: %s",
749
ipc.write("NOTFOUND %s\n" % fpr)
752
# Have to check if client.still_valid(), since it is
753
# possible that the client timed out while establishing
754
# the GnuTLS session.
755
if not client.still_valid():
756
logger.warning(u"Client %(name)s is invalid",
758
ipc.write("INVALID %s\n" % client.name)
761
ipc.write("SENDING %s\n" % client.name)
763
while sent_size < len(client.secret):
764
sent = session.send(client.secret[sent_size:])
765
logger.debug(u"Sent: %d, remaining: %d",
766
sent, len(client.secret)
767
- (sent_size + sent))
772
class ForkingMixInWithPipe(SocketServer.ForkingMixIn, object):
773
"""Like SocketServer.ForkingMixIn, but also pass a pipe.
774
Assumes a gobject.MainLoop event loop.
776
def process_request(self, request, client_address):
777
"""This overrides and wraps the original process_request().
778
This function creates a new pipe in self.pipe
780
self.pipe = os.pipe()
781
super(ForkingMixInWithPipe,
782
self).process_request(request, client_address)
783
os.close(self.pipe[1]) # close write end
784
# Call "handle_ipc" for both data and EOF events
785
gobject.io_add_watch(self.pipe[0],
786
gobject.IO_IN | gobject.IO_HUP,
788
def handle_ipc(source, condition):
789
"""Dummy function; override as necessary"""
794
class IPv6_TCPServer(ForkingMixInWithPipe,
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,
795
724
SocketServer.TCPServer, object):
796
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
725
"""IPv6 TCP server. Accepts 'None' as address and/or port.
798
727
settings: Server settings
799
728
clients: Set() of Client objects
856
778
return super(IPv6_TCPServer, self).server_activate()
857
779
def enable(self):
858
780
self.enabled = True
859
def handle_ipc(self, source, condition, file_objects={}):
861
gobject.IO_IN: "IN", # There is data to read.
862
gobject.IO_OUT: "OUT", # Data can be written (without
864
gobject.IO_PRI: "PRI", # There is urgent data to read.
865
gobject.IO_ERR: "ERR", # Error condition.
866
gobject.IO_HUP: "HUP" # Hung up (the connection has been
867
# broken, usually for pipes and
870
conditions_string = ' | '.join(name
872
condition_names.iteritems()
874
logger.debug("Handling IPC: FD = %d, condition = %s", source,
877
# Turn the pipe file descriptor into a Python file object
878
if source not in file_objects:
879
file_objects[source] = os.fdopen(source, "r", 1)
881
# Read a line from the file object
882
cmdline = file_objects[source].readline()
883
if not cmdline: # Empty line means end of file
885
file_objects[source].close()
886
del file_objects[source]
888
# Stop calling this function
891
logger.debug("IPC command: %r\n" % cmdline)
893
# Parse and act on command
894
cmd, args = cmdline.split(None, 1)
895
if cmd == "NOTFOUND":
896
if self.settings["use_dbus"]:
898
mandos_dbus_service.ClientNotFound(args)
899
elif cmd == "INVALID":
900
if self.settings["use_dbus"]:
901
for client in self.clients:
902
if client.name == args:
906
elif cmd == "SENDING":
907
for client in self.clients:
908
if client.name == args:
910
if self.settings["use_dbus"]:
912
client.ReceivedSecret()
915
logger.error("Unknown IPC command: %r", cmdline)
917
# Keep calling this function
921
783
def string_to_delta(interval):
922
784
"""Parse a string and return a datetime.timedelta
924
786
>>> string_to_delta('7d')
925
787
datetime.timedelta(7)
926
788
>>> string_to_delta('60s')
1082
937
server_config.read(os.path.join(options.configdir, "mandos.conf"))
1083
938
# Convert the SafeConfigParser object to a dict
1084
939
server_settings = server_config.defaults()
1085
# Use the appropriate methods on the non-string config options
1086
server_settings["debug"] = server_config.getboolean("DEFAULT",
1088
server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
1090
server_settings["use_ipv6"] = server_config.getboolean("DEFAULT",
1092
if server_settings["port"]:
1093
server_settings["port"] = server_config.getint("DEFAULT",
940
# Use getboolean on the boolean config options
941
server_settings["debug"] = (server_config.getboolean
942
("DEFAULT", "debug"))
943
server_settings["use_dbus"] = (server_config.getboolean
944
("DEFAULT", "use_dbus"))
1095
945
del server_config
1097
947
# Override the settings from the config file with command line
1098
948
# options, if set.
1099
949
for option in ("interface", "address", "port", "debug",
1100
950
"priority", "servicename", "configdir",
1101
"use_dbus", "use_ipv6"):
1102
952
value = getattr(options, option)
1103
953
if value is not None:
1104
954
server_settings[option] = value
1106
956
# Now we have our good server settings in "server_settings"
1108
##################################################################
1110
958
# For convenience
1111
959
debug = server_settings["debug"]
1112
960
use_dbus = server_settings["use_dbus"]
1113
use_ipv6 = server_settings["use_ipv6"]
1116
963
syslogger.setLevel(logging.WARNING)
1259
1089
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
1262
class MandosDBusService(dbus.service.Object):
1092
class MandosServer(dbus.service.Object):
1263
1093
"""A D-Bus proxy object"""
1264
1094
def __init__(self):
1265
dbus.service.Object.__init__(self, bus, "/")
1266
_interface = u"se.bsnet.fukt.Mandos"
1095
dbus.service.Object.__init__(self, bus,
1097
_interface = u"org.mandos_system.Mandos"
1268
1099
@dbus.service.signal(_interface, signature="oa{sv}")
1269
1100
def ClientAdded(self, objpath, properties):
1273
@dbus.service.signal(_interface, signature="s")
1274
def ClientNotFound(self, fingerprint):
1278
@dbus.service.signal(_interface, signature="os")
1279
def ClientRemoved(self, objpath, name):
1104
@dbus.service.signal(_interface, signature="o")
1105
def ClientRemoved(self, objpath):
1283
1109
@dbus.service.method(_interface, out_signature="ao")
1284
1110
def GetAllClients(self):
1286
1111
return dbus.Array(c.dbus_object_path for c in clients)
1288
1113
@dbus.service.method(_interface, out_signature="a{oa{sv}}")
1289
1114
def GetAllClientsWithProperties(self):
1291
1115
return dbus.Dictionary(
1292
1116
((c.dbus_object_path, c.GetAllProperties())
1293
1117
for c in clients),
1294
1118
signature="oa{sv}")
1296
1120
@dbus.service.method(_interface, in_signature="o")
1297
1121
def RemoveClient(self, object_path):
1299
1122
for c in clients:
1300
1123
if c.dbus_object_path == object_path:
1301
1124
clients.remove(c)