144
152
u" after %i retries, exiting.",
145
153
self.rename_count)
146
154
raise AvahiServiceError(u"Too many renames")
147
self.name = server.GetAlternativeServiceName(self.name)
155
self.name = self.server.GetAlternativeServiceName(self.name)
148
156
logger.info(u"Changing Zeroconf service name to %r ...",
150
158
syslogger.setFormatter(logging.Formatter
151
('Mandos (%s) [%%(process)d]:'
152
' %%(levelname)s: %%(message)s'
159
(u'Mandos (%s) [%%(process)d]:'
160
u' %%(levelname)s: %%(message)s'
156
164
self.rename_count += 1
157
165
def remove(self):
158
166
"""Derived from the Avahi example code"""
159
if group is not None:
167
if self.group is not None:
162
170
"""Derived from the Avahi example code"""
165
group = dbus.Interface(bus.get_object
167
server.EntryGroupNew()),
168
avahi.DBUS_INTERFACE_ENTRY_GROUP)
169
group.connect_to_signal('StateChanged',
170
entry_group_state_changed)
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)
171
178
logger.debug(u"Adding Zeroconf service '%s' of type '%s' ...",
172
service.name, service.type)
174
self.interface, # interface
175
self.protocol, # protocol
176
dbus.UInt32(0), # flags
177
self.name, self.type,
178
self.domain, self.host,
179
dbus.UInt16(self.port),
180
avahi.string_array_to_txt_array(self.TXT))
183
# From the Avahi example code:
184
group = None # our entry group
185
# End of Avahi example code
188
def _datetime_to_dbus(dt, variant_level=0):
189
"""Convert a UTC datetime.datetime() to a D-Bus type."""
190
return dbus.String(dt.isoformat(), variant_level=variant_level)
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())
193
227
class Client(object):
220
254
instance %(name)s can be used in the command.
221
255
current_checker_command: string; current running checker_command
259
def _datetime_to_milliseconds(dt):
260
"Convert a datetime.datetime() to milliseconds"
261
return ((dt.days * 24 * 60 * 60 * 1000)
262
+ (dt.seconds * 1000)
263
+ (dt.microseconds // 1000))
223
265
def timeout_milliseconds(self):
224
266
"Return the 'timeout' attribute in milliseconds"
225
return ((self.timeout.days * 24 * 60 * 60 * 1000)
226
+ (self.timeout.seconds * 1000)
227
+ (self.timeout.microseconds // 1000))
267
return self._datetime_to_milliseconds(self.timeout)
229
269
def interval_milliseconds(self):
230
270
"Return the 'interval' attribute in milliseconds"
231
return ((self.interval.days * 24 * 60 * 60 * 1000)
232
+ (self.interval.seconds * 1000)
233
+ (self.interval.microseconds // 1000))
271
return self._datetime_to_milliseconds(self.interval)
235
273
def __init__(self, name = None, disable_hook=None, config=None):
236
274
"""Note: the 'checker' key in 'config' sets the
243
281
# Uppercase and remove spaces from fingerprint for later
244
282
# comparison purposes with return value from the fingerprint()
246
self.fingerprint = (config["fingerprint"].upper()
284
self.fingerprint = (config[u"fingerprint"].upper()
247
285
.replace(u" ", u""))
248
286
logger.debug(u" Fingerprint: %s", self.fingerprint)
249
if "secret" in config:
250
self.secret = config["secret"].decode(u"base64")
251
elif "secfile" in config:
287
if u"secret" in config:
288
self.secret = config[u"secret"].decode(u"base64")
289
elif u"secfile" in config:
252
290
with closing(open(os.path.expanduser
253
291
(os.path.expandvars
254
(config["secfile"])))) as secfile:
292
(config[u"secfile"])))) as secfile:
255
293
self.secret = secfile.read()
257
295
raise TypeError(u"No secret or secfile for client %s"
259
self.host = config.get("host", "")
297
self.host = config.get(u"host", u"")
260
298
self.created = datetime.datetime.utcnow()
261
299
self.enabled = False
262
300
self.last_enabled = None
263
301
self.last_checked_ok = None
264
self.timeout = string_to_delta(config["timeout"])
265
self.interval = string_to_delta(config["interval"])
302
self.timeout = string_to_delta(config[u"timeout"])
303
self.interval = string_to_delta(config[u"interval"])
266
304
self.disable_hook = disable_hook
267
305
self.checker = None
268
306
self.checker_initiator_tag = None
269
307
self.disable_initiator_tag = None
270
308
self.checker_callback_tag = None
271
self.checker_command = config["checker"]
309
self.checker_command = config[u"checker"]
272
310
self.current_checker_command = None
273
311
self.last_connect = None
275
313
def enable(self):
276
314
"""Start this client's checker and timeout hooks"""
315
if getattr(self, u"enabled", False):
277
318
self.last_enabled = datetime.datetime.utcnow()
278
319
# Schedule a new checker to be started an 'interval' from now,
279
320
# and every interval from then on.
437
481
"""A Client class using D-Bus
440
dbus_object_path: dbus.ObjectPath ; only set if self.use_dbus
484
dbus_object_path: dbus.ObjectPath
485
bus: dbus.SystemBus()
442
487
# dbus.service.Object doesn't use super(), so we can't either.
444
def __init__(self, *args, **kwargs):
489
def __init__(self, bus = None, *args, **kwargs):
445
491
Client.__init__(self, *args, **kwargs)
446
492
# Only now, when this client is initialized, can it show up on
448
494
self.dbus_object_path = (dbus.ObjectPath
450
+ self.name.replace(".", "_")))
451
dbus.service.Object.__init__(self, bus,
496
+ self.name.replace(u".", u"_")))
497
dbus.service.Object.__init__(self, self.bus,
452
498
self.dbus_object_path)
501
def _datetime_to_dbus(dt, variant_level=0):
502
"""Convert a UTC datetime.datetime() to a D-Bus type."""
503
return dbus.String(dt.isoformat(),
504
variant_level=variant_level)
453
506
def enable(self):
454
oldstate = getattr(self, "enabled", False)
507
oldstate = getattr(self, u"enabled", False)
455
508
r = Client.enable(self)
456
509
if oldstate != self.enabled:
457
510
# Emit D-Bus signals
458
511
self.PropertyChanged(dbus.String(u"enabled"),
459
512
dbus.Boolean(True, variant_level=1))
460
self.PropertyChanged(dbus.String(u"last_enabled"),
461
(_datetime_to_dbus(self.last_enabled,
513
self.PropertyChanged(
514
dbus.String(u"last_enabled"),
515
self._datetime_to_dbus(self.last_enabled,
465
519
def disable(self, signal = True):
466
oldstate = getattr(self, "enabled", False)
520
oldstate = getattr(self, u"enabled", False)
467
521
r = Client.disable(self)
468
522
if signal and oldstate != self.enabled:
469
523
# Emit D-Bus signal
524
578
# Emit D-Bus signal
525
579
self.CheckerStarted(self.current_checker_command)
526
580
self.PropertyChanged(
527
dbus.String("checker_running"),
581
dbus.String(u"checker_running"),
528
582
dbus.Boolean(True, variant_level=1))
531
585
def stop_checker(self, *args, **kwargs):
532
old_checker = getattr(self, "checker", None)
586
old_checker = getattr(self, u"checker", None)
533
587
r = Client.stop_checker(self, *args, **kwargs)
534
588
if (old_checker is not None
535
and getattr(self, "checker", None) is None):
589
and getattr(self, u"checker", None) is None):
536
590
self.PropertyChanged(dbus.String(u"checker_running"),
537
591
dbus.Boolean(False, variant_level=1))
541
595
_interface = u"se.bsnet.fukt.Mandos.Client"
543
597
# CheckedOK - method
544
CheckedOK = dbus.service.method(_interface)(checked_ok)
545
CheckedOK.__name__ = "CheckedOK"
598
@dbus.service.method(_interface)
600
return self.checked_ok()
547
602
# CheckerCompleted - signal
548
@dbus.service.signal(_interface, signature="nxs")
603
@dbus.service.signal(_interface, signature=u"nxs")
549
604
def CheckerCompleted(self, exitcode, waitstatus, command):
553
608
# CheckerStarted - signal
554
@dbus.service.signal(_interface, signature="s")
609
@dbus.service.signal(_interface, signature=u"s")
555
610
def CheckerStarted(self, command):
559
614
# GetAllProperties - method
560
@dbus.service.method(_interface, out_signature="a{sv}")
615
@dbus.service.method(_interface, out_signature=u"a{sv}")
561
616
def GetAllProperties(self):
563
618
return dbus.Dictionary({
619
dbus.String(u"name"):
565
620
dbus.String(self.name, variant_level=1),
566
dbus.String("fingerprint"):
621
dbus.String(u"fingerprint"):
567
622
dbus.String(self.fingerprint, variant_level=1),
623
dbus.String(u"host"):
569
624
dbus.String(self.host, variant_level=1),
570
dbus.String("created"):
571
_datetime_to_dbus(self.created, variant_level=1),
572
dbus.String("last_enabled"):
573
(_datetime_to_dbus(self.last_enabled,
625
dbus.String(u"created"):
626
self._datetime_to_dbus(self.created,
628
dbus.String(u"last_enabled"):
629
(self._datetime_to_dbus(self.last_enabled,
575
631
if self.last_enabled is not None
576
632
else dbus.Boolean(False, variant_level=1)),
577
dbus.String("enabled"):
633
dbus.String(u"enabled"):
578
634
dbus.Boolean(self.enabled, variant_level=1),
579
dbus.String("last_checked_ok"):
580
(_datetime_to_dbus(self.last_checked_ok,
635
dbus.String(u"last_checked_ok"):
636
(self._datetime_to_dbus(self.last_checked_ok,
582
638
if self.last_checked_ok is not None
583
639
else dbus.Boolean (False, variant_level=1)),
584
dbus.String("timeout"):
640
dbus.String(u"timeout"):
585
641
dbus.UInt64(self.timeout_milliseconds(),
586
642
variant_level=1),
587
dbus.String("interval"):
643
dbus.String(u"interval"):
588
644
dbus.UInt64(self.interval_milliseconds(),
589
645
variant_level=1),
590
dbus.String("checker"):
646
dbus.String(u"checker"):
591
647
dbus.String(self.checker_command,
592
648
variant_level=1),
593
dbus.String("checker_running"):
649
dbus.String(u"checker_running"):
594
650
dbus.Boolean(self.checker is not None,
595
651
variant_level=1),
596
dbus.String("object_path"):
652
dbus.String(u"object_path"):
597
653
dbus.ObjectPath(self.dbus_object_path,
601
657
# IsStillValid - method
602
@dbus.service.method(_interface, out_signature="b")
658
@dbus.service.method(_interface, out_signature=u"b")
603
659
def IsStillValid(self):
604
660
return self.still_valid()
606
662
# PropertyChanged - signal
607
@dbus.service.signal(_interface, signature="sv")
663
@dbus.service.signal(_interface, signature=u"sv")
608
664
def PropertyChanged(self, property, value):
850
906
super(ForkingMixInWithPipe,
851
907
self).process_request(request, client_address)
852
908
os.close(self.pipe[1]) # close write end
853
# Call "handle_ipc" for both data and EOF events
854
gobject.io_add_watch(self.pipe[0],
855
gobject.IO_IN | gobject.IO_HUP,
857
def handle_ipc(source, condition):
909
self.add_pipe(self.pipe[0])
910
def add_pipe(self, pipe):
858
911
"""Dummy function; override as necessary"""
863
915
class IPv6_TCPServer(ForkingMixInWithPipe,
864
SocketServer.TCPServer, object):
916
socketserver.TCPServer, object):
865
917
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
868
920
enabled: Boolean; whether this server is activated yet
869
921
interface: None or a network interface name (string)
870
922
use_ipv6: Boolean; to use IPv6 or not
872
clients: Set() of Client objects
873
gnutls_priority GnuTLS priority string
874
use_dbus: Boolean; to emit D-Bus signals or not
876
924
def __init__(self, server_address, RequestHandlerClass,
877
interface=None, use_ipv6=True, clients=None,
878
gnutls_priority=None, use_dbus=True):
925
interface=None, use_ipv6=True):
880
926
self.interface = interface
882
928
self.address_family = socket.AF_INET6
883
self.clients = clients
884
self.use_dbus = use_dbus
885
self.gnutls_priority = gnutls_priority
886
SocketServer.TCPServer.__init__(self, server_address,
929
socketserver.TCPServer.__init__(self, server_address,
887
930
RequestHandlerClass)
888
931
def server_bind(self):
889
932
"""This overrides the normal server_bind() function
890
933
to bind to an interface if one was specified, and also NOT to
891
934
bind to an address or port if they were not specified."""
892
935
if self.interface is not None:
894
self.socket.setsockopt(socket.SOL_SOCKET,
896
self.interface + '\0')
897
except socket.error, error:
898
if error[0] == errno.EPERM:
899
logger.error(u"No permission to"
900
u" bind to interface %s",
936
if SO_BINDTODEVICE is None:
937
logger.error(u"SO_BINDTODEVICE does not exist;"
938
u" cannot bind to interface %s",
942
self.socket.setsockopt(socket.SOL_SOCKET,
946
except socket.error, error:
947
if error[0] == errno.EPERM:
948
logger.error(u"No permission to"
949
u" bind to interface %s",
951
elif error[0] == errno.ENOPROTOOPT:
952
logger.error(u"SO_BINDTODEVICE not available;"
953
u" cannot bind to interface %s",
904
957
# Only bind(2) the socket if we really need to.
905
958
if self.server_address[0] or self.server_address[1]:
906
959
if not self.server_address[0]:
907
960
if self.address_family == socket.AF_INET6:
908
any_address = "::" # in6addr_any
961
any_address = u"::" # in6addr_any
910
963
any_address = socket.INADDR_ANY
911
964
self.server_address = (any_address,
921
974
# (self.interface))
922
return SocketServer.TCPServer.server_bind(self)
975
return socketserver.TCPServer.server_bind(self)
978
class MandosServer(IPv6_TCPServer):
982
clients: set of Client objects
983
gnutls_priority GnuTLS priority string
984
use_dbus: Boolean; to emit D-Bus signals or not
985
clients: set of Client objects
986
gnutls_priority GnuTLS priority string
987
use_dbus: Boolean; to emit D-Bus signals or not
989
Assumes a gobject.MainLoop event loop.
991
def __init__(self, server_address, RequestHandlerClass,
992
interface=None, use_ipv6=True, clients=None,
993
gnutls_priority=None, use_dbus=True):
995
self.clients = clients
996
if self.clients is None:
998
self.use_dbus = use_dbus
999
self.gnutls_priority = gnutls_priority
1000
IPv6_TCPServer.__init__(self, server_address,
1001
RequestHandlerClass,
1002
interface = interface,
1003
use_ipv6 = use_ipv6)
923
1004
def server_activate(self):
924
1005
if self.enabled:
925
return SocketServer.TCPServer.server_activate(self)
1006
return socketserver.TCPServer.server_activate(self)
926
1007
def enable(self):
927
1008
self.enabled = True
1009
def add_pipe(self, pipe):
1010
# Call "handle_ipc" for both data and EOF events
1011
gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
928
1013
def handle_ipc(self, source, condition, file_objects={}):
929
1014
condition_names = {
930
gobject.IO_IN: "IN", # There is data to read.
931
gobject.IO_OUT: "OUT", # Data can be written (without
933
gobject.IO_PRI: "PRI", # There is urgent data to read.
934
gobject.IO_ERR: "ERR", # Error condition.
935
gobject.IO_HUP: "HUP" # Hung up (the connection has been
936
# broken, usually for pipes and
1015
gobject.IO_IN: u"IN", # There is data to read.
1016
gobject.IO_OUT: u"OUT", # Data can be written (without
1018
gobject.IO_PRI: u"PRI", # There is urgent data to read.
1019
gobject.IO_ERR: u"ERR", # Error condition.
1020
gobject.IO_HUP: u"HUP" # Hung up (the connection has been
1021
# broken, usually for pipes and
939
1024
conditions_string = ' | '.join(name
940
1025
for cond, name in
941
1026
condition_names.iteritems()
942
1027
if cond & condition)
943
logger.debug("Handling IPC: FD = %d, condition = %s", source,
1028
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
944
1029
conditions_string)
946
1031
# Turn the pipe file descriptor into a Python file object
947
1032
if source not in file_objects:
948
file_objects[source] = os.fdopen(source, "r", 1)
1033
file_objects[source] = os.fdopen(source, u"r", 1)
950
1035
# Read a line from the file object
951
1036
cmdline = file_objects[source].readline()
1036
1121
return timevalue
1039
def server_state_changed(state):
1040
"""Derived from the Avahi example code"""
1041
if state == avahi.SERVER_COLLISION:
1042
logger.error(u"Zeroconf server name collision")
1044
elif state == avahi.SERVER_RUNNING:
1048
def entry_group_state_changed(state, error):
1049
"""Derived from the Avahi example code"""
1050
logger.debug(u"Avahi state change: %i", state)
1052
if state == avahi.ENTRY_GROUP_ESTABLISHED:
1053
logger.debug(u"Zeroconf service established.")
1054
elif state == avahi.ENTRY_GROUP_COLLISION:
1055
logger.warning(u"Zeroconf service name collision.")
1057
elif state == avahi.ENTRY_GROUP_FAILURE:
1058
logger.critical(u"Avahi: Error in group state changed %s",
1060
raise AvahiGroupError(u"State changed: %s" % unicode(error))
1062
1124
def if_nametoindex(interface):
1063
"""Call the C function if_nametoindex(), or equivalent"""
1125
"""Call the C function if_nametoindex(), or equivalent
1127
Note: This function cannot accept a unicode string."""
1064
1128
global if_nametoindex
1066
1130
if_nametoindex = (ctypes.cdll.LoadLibrary
1067
(ctypes.util.find_library("c"))
1131
(ctypes.util.find_library(u"c"))
1068
1132
.if_nametoindex)
1069
1133
except (OSError, AttributeError):
1070
if "struct" not in sys.modules:
1072
if "fcntl" not in sys.modules:
1134
logger.warning(u"Doing if_nametoindex the hard way")
1074
1135
def if_nametoindex(interface):
1075
1136
"Get an interface index the hard way, i.e. using fcntl()"
1076
1137
SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h
1077
1138
with closing(socket.socket()) as s:
1078
1139
ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
1079
struct.pack("16s16x", interface))
1080
interface_index = struct.unpack("I", ifreq[16:20])[0]
1140
struct.pack(str(u"16s16x"),
1142
interface_index = struct.unpack(str(u"I"),
1081
1144
return interface_index
1082
1145
return if_nametoindex(interface)
1112
1175
# Parsing of options, both command line and config file
1114
1177
parser = optparse.OptionParser(version = "%%prog %s" % version)
1115
parser.add_option("-i", "--interface", type="string",
1116
metavar="IF", help="Bind to interface IF")
1117
parser.add_option("-a", "--address", type="string",
1118
help="Address to listen for requests on")
1119
parser.add_option("-p", "--port", type="int",
1120
help="Port number to receive requests on")
1121
parser.add_option("--check", action="store_true",
1122
help="Run self-test")
1123
parser.add_option("--debug", action="store_true",
1124
help="Debug mode; run in foreground and log to"
1126
parser.add_option("--priority", type="string", help="GnuTLS"
1127
" priority string (see GnuTLS documentation)")
1128
parser.add_option("--servicename", type="string", metavar="NAME",
1129
help="Zeroconf service name")
1130
parser.add_option("--configdir", type="string",
1131
default="/etc/mandos", metavar="DIR",
1132
help="Directory to search for configuration"
1134
parser.add_option("--no-dbus", action="store_false",
1136
help="Do not provide D-Bus system bus"
1138
parser.add_option("--no-ipv6", action="store_false",
1139
dest="use_ipv6", help="Do not use IPv6")
1178
parser.add_option("-i", u"--interface", type=u"string",
1179
metavar="IF", help=u"Bind to interface IF")
1180
parser.add_option("-a", u"--address", type=u"string",
1181
help=u"Address to listen for requests on")
1182
parser.add_option("-p", u"--port", type=u"int",
1183
help=u"Port number to receive requests on")
1184
parser.add_option("--check", action=u"store_true",
1185
help=u"Run self-test")
1186
parser.add_option("--debug", action=u"store_true",
1187
help=u"Debug mode; run in foreground and log to"
1189
parser.add_option("--priority", type=u"string", help=u"GnuTLS"
1190
u" priority string (see GnuTLS documentation)")
1191
parser.add_option("--servicename", type=u"string",
1192
metavar=u"NAME", help=u"Zeroconf service name")
1193
parser.add_option("--configdir", type=u"string",
1194
default=u"/etc/mandos", metavar=u"DIR",
1195
help=u"Directory to search for configuration"
1197
parser.add_option("--no-dbus", action=u"store_false",
1198
dest=u"use_dbus", help=u"Do not provide D-Bus"
1199
u" system bus interface")
1200
parser.add_option("--no-ipv6", action=u"store_false",
1201
dest=u"use_ipv6", help=u"Do not use IPv6")
1140
1202
options = parser.parse_args()[0]
1142
1204
if options.check:
1147
1209
# Default values for config file for server-global settings
1148
server_defaults = { "interface": "",
1153
"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1154
"servicename": "Mandos",
1210
server_defaults = { u"interface": u"",
1215
u"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1216
u"servicename": u"Mandos",
1217
u"use_dbus": u"True",
1218
u"use_ipv6": u"True",
1159
1221
# Parse config file for server-global settings
1160
server_config = ConfigParser.SafeConfigParser(server_defaults)
1222
server_config = configparser.SafeConfigParser(server_defaults)
1161
1223
del server_defaults
1162
server_config.read(os.path.join(options.configdir, "mandos.conf"))
1224
server_config.read(os.path.join(options.configdir,
1163
1226
# Convert the SafeConfigParser object to a dict
1164
1227
server_settings = server_config.defaults()
1165
1228
# Use the appropriate methods on the non-string config options
1166
server_settings["debug"] = server_config.getboolean("DEFAULT",
1168
server_settings["use_dbus"] = server_config.getboolean("DEFAULT",
1170
server_settings["use_ipv6"] = server_config.getboolean("DEFAULT",
1229
for option in (u"debug", u"use_dbus", u"use_ipv6"):
1230
server_settings[option] = server_config.getboolean(u"DEFAULT",
1172
1232
if server_settings["port"]:
1173
server_settings["port"] = server_config.getint("DEFAULT",
1233
server_settings["port"] = server_config.getint(u"DEFAULT",
1175
1235
del server_config
1177
1237
# Override the settings from the config file with command line
1178
1238
# options, if set.
1179
for option in ("interface", "address", "port", "debug",
1180
"priority", "servicename", "configdir",
1181
"use_dbus", "use_ipv6"):
1239
for option in (u"interface", u"address", u"port", u"debug",
1240
u"priority", u"servicename", u"configdir",
1241
u"use_dbus", u"use_ipv6"):
1182
1242
value = getattr(options, option)
1183
1243
if value is not None:
1184
1244
server_settings[option] = value
1246
# Force all strings to be unicode
1247
for option in server_settings.keys():
1248
if type(server_settings[option]) is str:
1249
server_settings[option] = unicode(server_settings[option])
1186
1250
# Now we have our good server settings in "server_settings"
1188
1252
##################################################################
1190
1254
# For convenience
1191
debug = server_settings["debug"]
1192
use_dbus = server_settings["use_dbus"]
1193
use_ipv6 = server_settings["use_ipv6"]
1255
debug = server_settings[u"debug"]
1256
use_dbus = server_settings[u"use_dbus"]
1257
use_ipv6 = server_settings[u"use_ipv6"]
1196
1260
syslogger.setLevel(logging.WARNING)
1197
1261
console.setLevel(logging.WARNING)
1199
if server_settings["servicename"] != "Mandos":
1263
if server_settings[u"servicename"] != u"Mandos":
1200
1264
syslogger.setFormatter(logging.Formatter
1201
('Mandos (%s) [%%(process)d]:'
1202
' %%(levelname)s: %%(message)s'
1203
% server_settings["servicename"]))
1265
(u'Mandos (%s) [%%(process)d]:'
1266
u' %%(levelname)s: %%(message)s'
1267
% server_settings[u"servicename"]))
1205
1269
# Parse config file with clients
1206
client_defaults = { "timeout": "1h",
1208
"checker": "fping -q -- %%(host)s",
1270
client_defaults = { u"timeout": u"1h",
1272
u"checker": u"fping -q -- %%(host)s",
1211
client_config = ConfigParser.SafeConfigParser(client_defaults)
1212
client_config.read(os.path.join(server_settings["configdir"],
1275
client_config = configparser.SafeConfigParser(client_defaults)
1276
client_config.read(os.path.join(server_settings[u"configdir"],
1215
1279
global mandos_dbus_service
1216
1280
mandos_dbus_service = None
1219
tcp_server = IPv6_TCPServer((server_settings["address"],
1220
server_settings["port"]),
1223
server_settings["interface"],
1227
server_settings["priority"],
1229
pidfilename = "/var/run/mandos.pid"
1282
tcp_server = MandosServer((server_settings[u"address"],
1283
server_settings[u"port"]),
1285
interface=server_settings[u"interface"],
1288
server_settings[u"priority"],
1290
pidfilename = u"/var/run/mandos.pid"
1231
pidfile = open(pidfilename, "w")
1292
pidfile = open(pidfilename, u"w")
1232
1293
except IOError:
1233
logger.error("Could not open file %r", pidfilename)
1294
logger.error(u"Could not open file %r", pidfilename)
1236
uid = pwd.getpwnam("_mandos").pw_uid
1237
gid = pwd.getpwnam("_mandos").pw_gid
1297
uid = pwd.getpwnam(u"_mandos").pw_uid
1298
gid = pwd.getpwnam(u"_mandos").pw_gid
1238
1299
except KeyError:
1240
uid = pwd.getpwnam("mandos").pw_uid
1241
gid = pwd.getpwnam("mandos").pw_gid
1301
uid = pwd.getpwnam(u"mandos").pw_uid
1302
gid = pwd.getpwnam(u"mandos").pw_gid
1242
1303
except KeyError:
1244
uid = pwd.getpwnam("nobody").pw_uid
1245
gid = pwd.getpwnam("nogroup").pw_gid
1305
uid = pwd.getpwnam(u"nobody").pw_uid
1306
gid = pwd.getpwnam(u"nobody").pw_gid
1246
1307
except KeyError:
1262
1323
@gnutls.library.types.gnutls_log_func
1263
1324
def debug_gnutls(level, string):
1264
logger.debug("GnuTLS: %s", string[:-1])
1325
logger.debug(u"GnuTLS: %s", string[:-1])
1266
1327
(gnutls.library.functions
1267
1328
.gnutls_global_set_log_function(debug_gnutls))
1270
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1271
service = AvahiService(name = server_settings["servicename"],
1272
servicetype = "_mandos._tcp",
1273
protocol = protocol)
1274
if server_settings["interface"]:
1275
service.interface = (if_nametoindex
1276
(server_settings["interface"]))
1278
1330
global main_loop
1281
1331
# From the Avahi example code
1282
1332
DBusGMainLoop(set_as_default=True )
1283
1333
main_loop = gobject.MainLoop()
1284
1334
bus = dbus.SystemBus()
1285
server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
1286
avahi.DBUS_PATH_SERVER),
1287
avahi.DBUS_INTERFACE_SERVER)
1288
1335
# End of Avahi example code
1290
1337
bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1338
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1339
service = AvahiService(name = server_settings[u"servicename"],
1340
servicetype = u"_mandos._tcp",
1341
protocol = protocol, bus = bus)
1342
if server_settings["interface"]:
1343
service.interface = (if_nametoindex
1344
(str(server_settings[u"interface"])))
1292
1346
client_class = Client
1294
client_class = ClientDBus
1348
client_class = functools.partial(ClientDBus, bus = bus)
1349
tcp_server.clients.update(set(
1296
1350
client_class(name = section,
1297
1351
config= dict(client_config.items(section)))
1298
1352
for section in client_config.sections()))
1353
if not tcp_server.clients:
1300
1354
logger.warning(u"No clients defined")
1349
1398
class MandosDBusService(dbus.service.Object):
1350
1399
"""A D-Bus proxy object"""
1351
1400
def __init__(self):
1352
dbus.service.Object.__init__(self, bus, "/")
1401
dbus.service.Object.__init__(self, bus, u"/")
1353
1402
_interface = u"se.bsnet.fukt.Mandos"
1355
@dbus.service.signal(_interface, signature="oa{sv}")
1404
@dbus.service.signal(_interface, signature=u"oa{sv}")
1356
1405
def ClientAdded(self, objpath, properties):
1360
@dbus.service.signal(_interface, signature="s")
1409
@dbus.service.signal(_interface, signature=u"s")
1361
1410
def ClientNotFound(self, fingerprint):
1365
@dbus.service.signal(_interface, signature="os")
1414
@dbus.service.signal(_interface, signature=u"os")
1366
1415
def ClientRemoved(self, objpath, name):
1370
@dbus.service.method(_interface, out_signature="ao")
1419
@dbus.service.method(_interface, out_signature=u"ao")
1371
1420
def GetAllClients(self):
1373
return dbus.Array(c.dbus_object_path for c in clients)
1422
return dbus.Array(c.dbus_object_path
1423
for c in tcp_server.clients)
1375
@dbus.service.method(_interface, out_signature="a{oa{sv}}")
1425
@dbus.service.method(_interface,
1426
out_signature=u"a{oa{sv}}")
1376
1427
def GetAllClientsWithProperties(self):
1378
1429
return dbus.Dictionary(
1379
1430
((c.dbus_object_path, c.GetAllProperties())
1431
for c in tcp_server.clients),
1432
signature=u"oa{sv}")
1383
@dbus.service.method(_interface, in_signature="o")
1434
@dbus.service.method(_interface, in_signature=u"o")
1384
1435
def RemoveClient(self, object_path):
1437
for c in tcp_server.clients:
1387
1438
if c.dbus_object_path == object_path:
1439
tcp_server.clients.remove(c)
1389
1440
c.remove_from_connection()
1390
1441
# Don't signal anything except ClientRemoved
1391
1442
c.disable(signal=False)