152
130
u" after %i retries, exiting.",
153
131
self.rename_count)
154
132
raise AvahiServiceError(u"Too many renames")
155
self.name = self.server.GetAlternativeServiceName(self.name)
133
self.name = server.GetAlternativeServiceName(self.name)
156
134
logger.info(u"Changing Zeroconf service name to %r ...",
158
136
syslogger.setFormatter(logging.Formatter
159
(u'Mandos (%s) [%%(process)d]:'
160
u' %%(levelname)s: %%(message)s'
137
('Mandos (%s): %%(levelname)s:'
138
' %%(message)s' % self.name))
164
141
self.rename_count += 1
165
142
def remove(self):
166
143
"""Derived from the Avahi example code"""
167
if self.group is not None:
144
if group is not None:
170
147
"""Derived from the Avahi example code"""
171
if self.group is None:
172
self.group = dbus.Interface(
173
self.bus.get_object(avahi.DBUS_NAME,
174
self.server.EntryGroupNew()),
175
avahi.DBUS_INTERFACE_ENTRY_GROUP)
176
self.group.connect_to_signal('StateChanged',
177
self.entry_group_state_changed)
150
group = dbus.Interface(bus.get_object
152
server.EntryGroupNew()),
153
avahi.DBUS_INTERFACE_ENTRY_GROUP)
154
group.connect_to_signal('StateChanged',
155
entry_group_state_changed)
178
156
logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
179
self.name, self.type)
180
self.group.AddService(
183
dbus.UInt32(0), # flags
184
self.name, self.type,
185
self.domain, self.host,
186
dbus.UInt16(self.port),
187
avahi.string_array_to_txt_array(self.TXT))
189
def entry_group_state_changed(self, state, error):
190
"""Derived from the Avahi example code"""
191
logger.debug(u"Avahi state change: %i", state)
193
if state == avahi.ENTRY_GROUP_ESTABLISHED:
194
logger.debug(u"Zeroconf service established.")
195
elif state == avahi.ENTRY_GROUP_COLLISION:
196
logger.warning(u"Zeroconf service name collision.")
198
elif state == avahi.ENTRY_GROUP_FAILURE:
199
logger.critical(u"Avahi: Error in group state changed %s",
201
raise AvahiGroupError(u"State changed: %s"
204
"""Derived from the Avahi example code"""
205
if self.group is not None:
208
def server_state_changed(self, state):
209
"""Derived from the Avahi example code"""
210
if state == avahi.SERVER_COLLISION:
211
logger.error(u"Zeroconf server name collision")
213
elif state == avahi.SERVER_RUNNING:
216
"""Derived from the Avahi example code"""
217
if self.server is None:
218
self.server = dbus.Interface(
219
self.bus.get_object(avahi.DBUS_NAME,
220
avahi.DBUS_PATH_SERVER),
221
avahi.DBUS_INTERFACE_SERVER)
222
self.server.connect_to_signal(u"StateChanged",
223
self.server_state_changed)
224
self.server_state_changed(self.server.GetState())
227
class Client(object):
157
service.name, service.type)
159
self.interface, # interface
160
avahi.PROTO_INET6, # protocol
161
dbus.UInt32(0), # flags
162
self.name, self.type,
163
self.domain, self.host,
164
dbus.UInt16(self.port),
165
avahi.string_array_to_txt_array(self.TXT))
168
# From the Avahi example code:
169
group = None # our entry group
170
# End of Avahi example code
173
def _datetime_to_dbus(dt, variant_level=0):
174
"""Convert a UTC datetime.datetime() to a D-Bus type."""
175
return dbus.String(dt.isoformat(), variant_level=variant_level)
178
class Client(dbus.service.Object):
228
179
"""A representation of a client host served by this server.
231
name: string; from the config file, used in log messages and
181
name: string; from the config file, used in log messages
233
182
fingerprint: string (40 or 32 hexadecimal digits); used to
234
183
uniquely identify the client
235
184
secret: bytestring; sent verbatim (over TLS) to client
462
433
if error.errno != errno.ESRCH: # No such process
464
435
self.checker = None
437
self.PropertyChanged(dbus.String(u"checker_running"),
438
dbus.Boolean(False, variant_level=1))
466
440
def still_valid(self):
467
441
"""Has the timeout not yet passed for this client?"""
468
if not getattr(self, u"enabled", False):
442
if not getattr(self, "enabled", False):
470
444
now = datetime.datetime.utcnow()
471
445
if self.last_checked_ok is None:
472
446
return now < (self.created + self.timeout)
474
448
return now < (self.last_checked_ok + self.timeout)
477
class ClientDBus(Client, dbus.service.Object):
478
"""A Client class using D-Bus
481
dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
483
# dbus.service.Object doesn't use super(), so we can't either.
485
def __init__(self, bus = None, *args, **kwargs):
487
Client.__init__(self, *args, **kwargs)
488
# Only now, when this client is initialized, can it show up on
490
self.dbus_object_path = (dbus.ObjectPath
492
+ self.name.replace(u".", u"_")))
493
dbus.service.Object.__init__(self, self.bus,
494
self.dbus_object_path)
497
def _datetime_to_dbus(dt, variant_level=0):
498
"""Convert a UTC datetime.datetime() to a D-Bus type."""
499
return dbus.String(dt.isoformat(),
500
variant_level=variant_level)
503
oldstate = getattr(self, u"enabled", False)
504
r = Client.enable(self)
505
if oldstate != self.enabled:
507
self.PropertyChanged(dbus.String(u"enabled"),
508
dbus.Boolean(True, variant_level=1))
509
self.PropertyChanged(
510
dbus.String(u"last_enabled"),
511
self._datetime_to_dbus(self.last_enabled,
515
def disable(self, signal = True):
516
oldstate = getattr(self, u"enabled", False)
517
r = Client.disable(self)
518
if signal and oldstate != self.enabled:
520
self.PropertyChanged(dbus.String(u"enabled"),
521
dbus.Boolean(False, variant_level=1))
524
def __del__(self, *args, **kwargs):
526
self.remove_from_connection()
529
if hasattr(dbus.service.Object, u"__del__"):
530
dbus.service.Object.__del__(self, *args, **kwargs)
531
Client.__del__(self, *args, **kwargs)
533
def checker_callback(self, pid, condition, command,
535
self.checker_callback_tag = None
538
self.PropertyChanged(dbus.String(u"checker_running"),
539
dbus.Boolean(False, variant_level=1))
540
if os.WIFEXITED(condition):
541
exitstatus = os.WEXITSTATUS(condition)
543
self.CheckerCompleted(dbus.Int16(exitstatus),
544
dbus.Int64(condition),
545
dbus.String(command))
548
self.CheckerCompleted(dbus.Int16(-1),
549
dbus.Int64(condition),
550
dbus.String(command))
552
return Client.checker_callback(self, pid, condition, command,
555
def checked_ok(self, *args, **kwargs):
556
r = Client.checked_ok(self, *args, **kwargs)
558
self.PropertyChanged(
559
dbus.String(u"last_checked_ok"),
560
(self._datetime_to_dbus(self.last_checked_ok,
564
def start_checker(self, *args, **kwargs):
565
old_checker = self.checker
566
if self.checker is not None:
567
old_checker_pid = self.checker.pid
569
old_checker_pid = None
570
r = Client.start_checker(self, *args, **kwargs)
571
# Only if new checker process was started
572
if (self.checker is not None
573
and old_checker_pid != self.checker.pid):
575
self.CheckerStarted(self.current_checker_command)
576
self.PropertyChanged(
577
dbus.String(u"checker_running"),
578
dbus.Boolean(True, variant_level=1))
581
def stop_checker(self, *args, **kwargs):
582
old_checker = getattr(self, u"checker", None)
583
r = Client.stop_checker(self, *args, **kwargs)
584
if (old_checker is not None
585
and getattr(self, u"checker", None) is None):
586
self.PropertyChanged(dbus.String(u"checker_running"),
587
dbus.Boolean(False, variant_level=1))
590
450
## D-Bus methods & signals
591
_interface = u"se.bsnet.fukt.Mandos.Client"
451
_interface = u"org.mandos_system.Mandos.Client"
594
@dbus.service.method(_interface)
596
return self.checked_ok()
453
# BumpTimeout - method
454
BumpTimeout = dbus.service.method(_interface)(bump_timeout)
455
BumpTimeout.__name__ = "BumpTimeout"
598
457
# CheckerCompleted - signal
599
@dbus.service.signal(_interface, signature=u"nxs")
600
def CheckerCompleted(self, exitcode, waitstatus, command):
458
@dbus.service.signal(_interface, signature="bqs")
459
def CheckerCompleted(self, success, condition, command):
604
463
# CheckerStarted - signal
605
@dbus.service.signal(_interface, signature=u"s")
464
@dbus.service.signal(_interface, signature="s")
606
465
def CheckerStarted(self, command):
610
469
# GetAllProperties - method
611
@dbus.service.method(_interface, out_signature=u"a{sv}")
470
@dbus.service.method(_interface, out_signature="a{sv}")
612
471
def GetAllProperties(self):
614
473
return dbus.Dictionary({
615
dbus.String(u"name"):
616
475
dbus.String(self.name, variant_level=1),
617
dbus.String(u"fingerprint"):
476
dbus.String("fingerprint"):
618
477
dbus.String(self.fingerprint, variant_level=1),
619
dbus.String(u"host"):
620
479
dbus.String(self.host, variant_level=1),
621
dbus.String(u"created"):
622
self._datetime_to_dbus(self.created,
624
dbus.String(u"last_enabled"):
625
(self._datetime_to_dbus(self.last_enabled,
480
dbus.String("created"):
481
_datetime_to_dbus(self.created, variant_level=1),
482
dbus.String("last_enabled"):
483
(_datetime_to_dbus(self.last_enabled,
627
485
if self.last_enabled is not None
628
486
else dbus.Boolean(False, variant_level=1)),
629
dbus.String(u"enabled"):
487
dbus.String("enabled"):
630
488
dbus.Boolean(self.enabled, variant_level=1),
631
dbus.String(u"last_checked_ok"):
632
(self._datetime_to_dbus(self.last_checked_ok,
489
dbus.String("last_checked_ok"):
490
(_datetime_to_dbus(self.last_checked_ok,
634
492
if self.last_checked_ok is not None
635
493
else dbus.Boolean (False, variant_level=1)),
636
dbus.String(u"timeout"):
494
dbus.String("timeout"):
637
495
dbus.UInt64(self.timeout_milliseconds(),
638
496
variant_level=1),
639
dbus.String(u"interval"):
497
dbus.String("interval"):
640
498
dbus.UInt64(self.interval_milliseconds(),
641
499
variant_level=1),
642
dbus.String(u"checker"):
500
dbus.String("checker"):
643
501
dbus.String(self.checker_command,
644
502
variant_level=1),
645
dbus.String(u"checker_running"):
503
dbus.String("checker_running"):
646
504
dbus.Boolean(self.checker is not None,
647
505
variant_level=1),
648
dbus.String(u"object_path"):
649
dbus.ObjectPath(self.dbus_object_path,
653
508
# IsStillValid - method
654
@dbus.service.method(_interface, out_signature=u"b")
655
def IsStillValid(self):
656
return self.still_valid()
509
IsStillValid = (dbus.service.method(_interface, out_signature="b")
511
IsStillValid.__name__ = "IsStillValid"
658
513
# PropertyChanged - signal
659
@dbus.service.signal(_interface, signature=u"sv")
514
@dbus.service.signal(_interface, signature="sv")
660
515
def PropertyChanged(self, property, value):
664
# ReceivedSecret - signal
665
@dbus.service.signal(_interface)
666
def ReceivedSecret(self):
671
@dbus.service.signal(_interface)
676
519
# SetChecker - method
677
@dbus.service.method(_interface, in_signature=u"s")
520
@dbus.service.method(_interface, in_signature="s")
678
521
def SetChecker(self, checker):
679
522
"D-Bus setter method"
680
523
self.checker_command = checker
738
579
# StopChecker - method
739
@dbus.service.method(_interface)
740
def StopChecker(self):
580
StopChecker = dbus.service.method(_interface)(stop_checker)
581
StopChecker.__name__ = "StopChecker"
746
class ClientHandler(socketserver.BaseRequestHandler, object):
747
"""A class to handle client connections.
749
Instantiated once for each connection to handle it.
586
def peer_certificate(session):
587
"Return the peer's OpenPGP certificate as a bytestring"
588
# If not an OpenPGP certificate...
589
if (gnutls.library.functions
590
.gnutls_certificate_type_get(session._c_object)
591
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP):
592
# ...do the normal thing
593
return session.peer_certificate
594
list_size = ctypes.c_uint()
595
cert_list = (gnutls.library.functions
596
.gnutls_certificate_get_peers
597
(session._c_object, ctypes.byref(list_size)))
598
if list_size.value == 0:
601
return ctypes.string_at(cert.data, cert.size)
604
def fingerprint(openpgp):
605
"Convert an OpenPGP bytestring to a hexdigit fingerprint string"
606
# New GnuTLS "datum" with the OpenPGP public key
607
datum = (gnutls.library.types
608
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
611
ctypes.c_uint(len(openpgp))))
612
# New empty GnuTLS certificate
613
crt = gnutls.library.types.gnutls_openpgp_crt_t()
614
(gnutls.library.functions
615
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
616
# Import the OpenPGP public key into the certificate
617
(gnutls.library.functions
618
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
619
gnutls.library.constants
620
.GNUTLS_OPENPGP_FMT_RAW))
621
# Verify the self signature in the key
622
crtverify = ctypes.c_uint()
623
(gnutls.library.functions
624
.gnutls_openpgp_crt_verify_self(crt, 0, ctypes.byref(crtverify)))
625
if crtverify.value != 0:
626
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
627
raise gnutls.errors.CertificateSecurityError("Verify failed")
628
# New buffer for the fingerprint
629
buf = ctypes.create_string_buffer(20)
630
buf_len = ctypes.c_size_t()
631
# Get the fingerprint from the certificate into the buffer
632
(gnutls.library.functions
633
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
634
ctypes.byref(buf_len)))
635
# Deinit the certificate
636
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
637
# Convert the buffer to a Python bytestring
638
fpr = ctypes.string_at(buf, buf_len.value)
639
# Convert the bytestring to hexadecimal notation
640
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
644
class TCP_handler(SocketServer.BaseRequestHandler, object):
645
"""A TCP request handler class.
646
Instantiated by IPv6_TCPServer for each request to handle it.
750
647
Note: This will run in its own forked process."""
752
649
def handle(self):
753
650
logger.info(u"TCP connection from: %s",
754
651
unicode(self.client_address))
755
logger.debug(u"IPC Pipe FD: %d", self.server.pipe[1])
756
# Open IPC pipe to parent process
757
with closing(os.fdopen(self.server.pipe[1], u"w", 1)) as ipc:
758
session = (gnutls.connection
759
.ClientSession(self.request,
763
line = self.request.makefile().readline()
764
logger.debug(u"Protocol version: %r", line)
766
if int(line.strip().split()[0]) > 1:
768
except (ValueError, IndexError, RuntimeError), error:
769
logger.error(u"Unknown protocol version: %s", error)
772
# Note: gnutls.connection.X509Credentials is really a
773
# generic GnuTLS certificate credentials object so long as
774
# no X.509 keys are added to it. Therefore, we can use it
775
# here despite using OpenPGP certificates.
777
#priority = u':'.join((u"NONE", u"+VERS-TLS1.1",
778
# u"+AES-256-CBC", u"+SHA1",
779
# u"+COMP-NULL", u"+CTYPE-OPENPGP",
781
# Use a fallback default, since this MUST be set.
782
priority = self.server.gnutls_priority
785
(gnutls.library.functions
786
.gnutls_priority_set_direct(session._c_object,
791
except gnutls.errors.GNUTLSError, error:
792
logger.warning(u"Handshake failed: %s", error)
793
# Do not run session.bye() here: the session is not
794
# established. Just abandon the request.
796
logger.debug(u"Handshake succeeded")
798
fpr = self.fingerprint(self.peer_certificate(session))
799
except (TypeError, gnutls.errors.GNUTLSError), error:
800
logger.warning(u"Bad certificate: %s", error)
803
logger.debug(u"Fingerprint: %s", fpr)
805
for c in self.server.clients:
806
if c.fingerprint == fpr:
810
ipc.write(u"NOTFOUND %s\n" % fpr)
813
# Have to check if client.still_valid(), since it is
814
# possible that the client timed out while establishing
815
# the GnuTLS session.
816
if not client.still_valid():
817
ipc.write(u"INVALID %s\n" % client.name)
820
ipc.write(u"SENDING %s\n" % client.name)
822
while sent_size < len(client.secret):
823
sent = session.send(client.secret[sent_size:])
824
logger.debug(u"Sent: %d, remaining: %d",
825
sent, len(client.secret)
826
- (sent_size + sent))
831
def peer_certificate(session):
832
"Return the peer's OpenPGP certificate as a bytestring"
833
# If not an OpenPGP certificate...
834
if (gnutls.library.functions
835
.gnutls_certificate_type_get(session._c_object)
836
!= gnutls.library.constants.GNUTLS_CRT_OPENPGP):
837
# ...do the normal thing
838
return session.peer_certificate
839
list_size = ctypes.c_uint(1)
840
cert_list = (gnutls.library.functions
841
.gnutls_certificate_get_peers
842
(session._c_object, ctypes.byref(list_size)))
843
if not bool(cert_list) and list_size.value != 0:
844
raise gnutls.errors.GNUTLSError(u"error getting peer"
846
if list_size.value == 0:
849
return ctypes.string_at(cert.data, cert.size)
852
def fingerprint(openpgp):
853
"Convert an OpenPGP bytestring to a hexdigit fingerprint"
854
# New GnuTLS "datum" with the OpenPGP public key
855
datum = (gnutls.library.types
856
.gnutls_datum_t(ctypes.cast(ctypes.c_char_p(openpgp),
859
ctypes.c_uint(len(openpgp))))
860
# New empty GnuTLS certificate
861
crt = gnutls.library.types.gnutls_openpgp_crt_t()
862
(gnutls.library.functions
863
.gnutls_openpgp_crt_init(ctypes.byref(crt)))
864
# Import the OpenPGP public key into the certificate
865
(gnutls.library.functions
866
.gnutls_openpgp_crt_import(crt, ctypes.byref(datum),
867
gnutls.library.constants
868
.GNUTLS_OPENPGP_FMT_RAW))
869
# Verify the self signature in the key
870
crtverify = ctypes.c_uint()
871
(gnutls.library.functions
872
.gnutls_openpgp_crt_verify_self(crt, 0,
873
ctypes.byref(crtverify)))
874
if crtverify.value != 0:
875
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
876
raise (gnutls.errors.CertificateSecurityError
878
# New buffer for the fingerprint
879
buf = ctypes.create_string_buffer(20)
880
buf_len = ctypes.c_size_t()
881
# Get the fingerprint from the certificate into the buffer
882
(gnutls.library.functions
883
.gnutls_openpgp_crt_get_fingerprint(crt, ctypes.byref(buf),
884
ctypes.byref(buf_len)))
885
# Deinit the certificate
886
gnutls.library.functions.gnutls_openpgp_crt_deinit(crt)
887
# Convert the buffer to a Python bytestring
888
fpr = ctypes.string_at(buf, buf_len.value)
889
# Convert the bytestring to hexadecimal notation
890
hex_fpr = u''.join(u"%02X" % ord(char) for char in fpr)
894
class ForkingMixInWithPipe(socketserver.ForkingMixIn, object):
895
"""Like socketserver.ForkingMixIn, but also pass a pipe.
897
Assumes a gobject.MainLoop event loop.
899
def process_request(self, request, client_address):
900
"""Overrides and wraps the original process_request().
902
This function creates a new pipe in self.pipe
904
self.pipe = os.pipe()
905
super(ForkingMixInWithPipe,
906
self).process_request(request, client_address)
907
os.close(self.pipe[1]) # close write end
908
# Call "handle_ipc" for both data and EOF events
909
gobject.io_add_watch(self.pipe[0],
910
gobject.IO_IN | gobject.IO_HUP,
912
def handle_ipc(source, condition):
913
"""Dummy function; override as necessary"""
918
class IPv6_TCPServer(ForkingMixInWithPipe,
919
socketserver.TCPServer, object):
920
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
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,
724
SocketServer.TCPServer, object):
725
"""IPv6 TCP server. Accepts 'None' as address and/or port.
727
settings: Server settings
728
clients: Set() of Client objects
923
729
enabled: Boolean; whether this server is activated yet
924
interface: None or a network interface name (string)
925
use_ipv6: Boolean; to use IPv6 or not
927
clients: set of Client objects
928
gnutls_priority GnuTLS priority string
929
use_dbus: Boolean; to emit D-Bus signals or not
931
def __init__(self, server_address, RequestHandlerClass,
932
interface=None, use_ipv6=True, clients=None,
933
gnutls_priority=None, use_dbus=True):
731
address_family = socket.AF_INET6
732
def __init__(self, *args, **kwargs):
733
if "settings" in kwargs:
734
self.settings = kwargs["settings"]
735
del kwargs["settings"]
736
if "clients" in kwargs:
737
self.clients = kwargs["clients"]
738
del kwargs["clients"]
934
739
self.enabled = False
935
self.interface = interface
937
self.address_family = socket.AF_INET6
938
self.clients = clients
939
self.use_dbus = use_dbus
940
self.gnutls_priority = gnutls_priority
941
socketserver.TCPServer.__init__(self, server_address,
740
super(IPv6_TCPServer, self).__init__(*args, **kwargs)
943
741
def server_bind(self):
944
742
"""This overrides the normal server_bind() function
945
743
to bind to an interface if one was specified, and also NOT to
946
744
bind to an address or port if they were not specified."""
947
if self.interface is not None:
745
if self.settings["interface"]:
746
# 25 is from /usr/include/asm-i486/socket.h
747
SO_BINDTODEVICE = getattr(socket, "SO_BINDTODEVICE", 25)
949
749
self.socket.setsockopt(socket.SOL_SOCKET,
951
str(self.interface + u'\0'))
751
self.settings["interface"])
952
752
except socket.error, error:
953
753
if error[0] == errno.EPERM:
954
754
logger.error(u"No permission to"
955
755
u" bind to interface %s",
756
self.settings["interface"])
959
759
# Only bind(2) the socket if we really need to.
960
760
if self.server_address[0] or self.server_address[1]:
961
761
if not self.server_address[0]:
962
if self.address_family == socket.AF_INET6:
963
any_address = u"::" # in6addr_any
965
any_address = socket.INADDR_ANY
966
self.server_address = (any_address,
763
self.server_address = (in6addr_any,
967
764
self.server_address[1])
968
765
elif not self.server_address[1]:
969
766
self.server_address = (self.server_address[0],
768
# if self.settings["interface"]:
972
769
# self.server_address = (self.server_address[0],
977
return socketserver.TCPServer.server_bind(self)
775
return super(IPv6_TCPServer, self).server_bind()
978
776
def server_activate(self):
980
return socketserver.TCPServer.server_activate(self)
778
return super(IPv6_TCPServer, self).server_activate()
981
779
def enable(self):
982
780
self.enabled = True
983
def handle_ipc(self, source, condition, file_objects={}):
985
gobject.IO_IN: u"IN", # There is data to read.
986
gobject.IO_OUT: u"OUT", # Data can be written (without
988
gobject.IO_PRI: u"PRI", # There is urgent data to read.
989
gobject.IO_ERR: u"ERR", # Error condition.
990
gobject.IO_HUP: u"HUP" # Hung up (the connection has been
991
# broken, usually for pipes and
994
conditions_string = ' | '.join(name
996
condition_names.iteritems()
998
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
1001
# Turn the pipe file descriptor into a Python file object
1002
if source not in file_objects:
1003
file_objects[source] = os.fdopen(source, u"r", 1)
1005
# Read a line from the file object
1006
cmdline = file_objects[source].readline()
1007
if not cmdline: # Empty line means end of file
1008
# close the IPC pipe
1009
file_objects[source].close()
1010
del file_objects[source]
1012
# Stop calling this function
1015
logger.debug(u"IPC command: %r", cmdline)
1017
# Parse and act on command
1018
cmd, args = cmdline.rstrip(u"\r\n").split(None, 1)
1020
if cmd == u"NOTFOUND":
1021
logger.warning(u"Client not found for fingerprint: %s",
1025
mandos_dbus_service.ClientNotFound(args)
1026
elif cmd == u"INVALID":
1027
for client in self.clients:
1028
if client.name == args:
1029
logger.warning(u"Client %s is invalid", args)
1035
logger.error(u"Unknown client %s is invalid", args)
1036
elif cmd == u"SENDING":
1037
for client in self.clients:
1038
if client.name == args:
1039
logger.info(u"Sending secret to %s", client.name)
1043
client.ReceivedSecret()
1046
logger.error(u"Sending secret to unknown client %s",
1049
logger.error(u"Unknown IPC command: %r", cmdline)
1051
# Keep calling this function
1055
783
def string_to_delta(interval):
1056
784
"""Parse a string and return a datetime.timedelta
1058
>>> string_to_delta(u'7d')
786
>>> string_to_delta('7d')
1059
787
datetime.timedelta(7)
1060
>>> string_to_delta(u'60s')
788
>>> string_to_delta('60s')
1061
789
datetime.timedelta(0, 60)
1062
>>> string_to_delta(u'60m')
790
>>> string_to_delta('60m')
1063
791
datetime.timedelta(0, 3600)
1064
>>> string_to_delta(u'24h')
792
>>> string_to_delta('24h')
1065
793
datetime.timedelta(1)
1066
794
>>> string_to_delta(u'1w')
1067
795
datetime.timedelta(7)
1068
>>> string_to_delta(u'5m 30s')
796
>>> string_to_delta('5m 30s')
1069
797
datetime.timedelta(0, 330)
1071
799
timevalue = datetime.timedelta(0)
1179
923
# Default values for config file for server-global settings
1180
server_defaults = { u"interface": u"",
1185
u"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1186
u"servicename": u"Mandos",
1187
u"use_dbus": u"True",
1188
u"use_ipv6": u"True",
924
server_defaults = { "interface": "",
929
"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
930
"servicename": "Mandos",
1191
934
# Parse config file for server-global settings
1192
server_config = configparser.SafeConfigParser(server_defaults)
935
server_config = ConfigParser.SafeConfigParser(server_defaults)
1193
936
del server_defaults
1194
server_config.read(os.path.join(options.configdir,
937
server_config.read(os.path.join(options.configdir, "mandos.conf"))
1196
938
# Convert the SafeConfigParser object to a dict
1197
939
server_settings = server_config.defaults()
1198
# Use the appropriate methods on the non-string config options
1199
for option in (u"debug", u"use_dbus", u"use_ipv6"):
1200
server_settings[option] = server_config.getboolean(u"DEFAULT",
1202
if server_settings["port"]:
1203
server_settings["port"] = server_config.getint(u"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"))
1205
945
del server_config
1207
947
# Override the settings from the config file with command line
1208
948
# options, if set.
1209
for option in (u"interface", u"address", u"port", u"debug",
1210
u"priority", u"servicename", u"configdir",
1211
u"use_dbus", u"use_ipv6"):
949
for option in ("interface", "address", "port", "debug",
950
"priority", "servicename", "configdir",
1212
952
value = getattr(options, option)
1213
953
if value is not None:
1214
954
server_settings[option] = value
1216
# Force all strings to be unicode
1217
for option in server_settings.keys():
1218
if type(server_settings[option]) is str:
1219
server_settings[option] = unicode(server_settings[option])
1220
956
# Now we have our good server settings in "server_settings"
1222
##################################################################
1224
958
# For convenience
1225
debug = server_settings[u"debug"]
1226
use_dbus = server_settings[u"use_dbus"]
1227
use_ipv6 = server_settings[u"use_ipv6"]
959
debug = server_settings["debug"]
960
use_dbus = server_settings["use_dbus"]
1230
963
syslogger.setLevel(logging.WARNING)
1231
964
console.setLevel(logging.WARNING)
1233
if server_settings[u"servicename"] != u"Mandos":
966
if server_settings["servicename"] != "Mandos":
1234
967
syslogger.setFormatter(logging.Formatter
1235
(u'Mandos (%s) [%%(process)d]:'
1236
u' %%(levelname)s: %%(message)s'
1237
% server_settings[u"servicename"]))
968
('Mandos (%s): %%(levelname)s:'
970
% server_settings["servicename"]))
1239
972
# Parse config file with clients
1240
client_defaults = { u"timeout": u"1h",
1242
u"checker": u"fping -q -- %%(host)s",
973
client_defaults = { "timeout": "1h",
975
"checker": "fping -q -- %%(host)s",
1245
client_config = configparser.SafeConfigParser(client_defaults)
1246
client_config.read(os.path.join(server_settings[u"configdir"],
1249
global mandos_dbus_service
1250
mandos_dbus_service = None
1253
tcp_server = IPv6_TCPServer((server_settings[u"address"],
1254
server_settings[u"port"]),
1257
server_settings[u"interface"],
1261
server_settings[u"priority"],
1263
pidfilename = u"/var/run/mandos.pid"
1265
pidfile = open(pidfilename, u"w")
1267
logger.error(u"Could not open file %r", pidfilename)
1270
uid = pwd.getpwnam(u"_mandos").pw_uid
1271
gid = pwd.getpwnam(u"_mandos").pw_gid
978
client_config = ConfigParser.SafeConfigParser(client_defaults)
979
client_config.read(os.path.join(server_settings["configdir"],
983
tcp_server = IPv6_TCPServer((server_settings["address"],
984
server_settings["port"]),
986
settings=server_settings,
988
pidfilename = "/var/run/mandos.pid"
990
pidfile = open(pidfilename, "w")
991
except IOError, error:
992
logger.error("Could not open file %r", pidfilename)
995
uid = pwd.getpwnam("_mandos").pw_uid
996
gid = pwd.getpwnam("_mandos").pw_gid
1272
997
except KeyError:
1274
uid = pwd.getpwnam(u"mandos").pw_uid
1275
gid = pwd.getpwnam(u"mandos").pw_gid
999
uid = pwd.getpwnam("mandos").pw_uid
1000
gid = pwd.getpwnam("mandos").pw_gid
1276
1001
except KeyError:
1278
uid = pwd.getpwnam(u"nobody").pw_uid
1279
gid = pwd.getpwnam(u"nobody").pw_gid
1003
uid = pwd.getpwnam("nobody").pw_uid
1004
gid = pwd.getpwnam("nogroup").pw_gid
1280
1005
except KeyError:
1286
1011
except OSError, error:
1287
1012
if error[0] != errno.EPERM:
1290
# Enable all possible GnuTLS debugging
1292
# "Use a log level over 10 to enable all debugging options."
1294
gnutls.library.functions.gnutls_global_set_log_level(11)
1296
@gnutls.library.types.gnutls_log_func
1297
def debug_gnutls(level, string):
1298
logger.debug(u"GnuTLS: %s", string[:-1])
1300
(gnutls.library.functions
1301
.gnutls_global_set_log_function(debug_gnutls))
1016
service = AvahiService(name = server_settings["servicename"],
1017
servicetype = "_mandos._tcp", )
1018
if server_settings["interface"]:
1019
service.interface = (if_nametoindex
1020
(server_settings["interface"]))
1303
1022
global main_loop
1304
1025
# From the Avahi example code
1305
1026
DBusGMainLoop(set_as_default=True )
1306
1027
main_loop = gobject.MainLoop()
1307
1028
bus = dbus.SystemBus()
1029
server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
1030
avahi.DBUS_PATH_SERVER),
1031
avahi.DBUS_INTERFACE_SERVER)
1308
1032
# End of Avahi example code
1310
bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1311
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1312
service = AvahiService(name = server_settings[u"servicename"],
1313
servicetype = u"_mandos._tcp",
1314
protocol = protocol, bus = bus)
1315
if server_settings["interface"]:
1316
service.interface = (if_nametoindex
1317
(str(server_settings[u"interface"])))
1034
bus_name = dbus.service.BusName(u"org.mandos-system.Mandos",
1319
client_class = Client
1321
client_class = functools.partial(ClientDBus, bus = bus)
1323
client_class(name = section,
1324
config= dict(client_config.items(section)))
1325
for section in client_config.sections()))
1037
clients.update(Set(Client(name = section,
1039
= dict(client_config.items(section)),
1040
use_dbus = use_dbus)
1041
for section in client_config.sections()))
1326
1042
if not clients:
1327
1043
logger.warning(u"No clients defined")