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
907
super(ForkingMixInWithPipe,
851
908
self).process_request(request, client_address)
852
909
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):
910
self.add_pipe(self.pipe[0])
911
def add_pipe(self, pipe):
858
912
"""Dummy function; override as necessary"""
863
916
class IPv6_TCPServer(ForkingMixInWithPipe,
864
SocketServer.TCPServer, object):
917
socketserver.TCPServer, object):
865
918
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
868
921
enabled: Boolean; whether this server is activated yet
869
922
interface: None or a network interface name (string)
870
923
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
925
def __init__(self, server_address, RequestHandlerClass,
877
interface=None, use_ipv6=True, clients=None,
878
gnutls_priority=None, use_dbus=True):
926
interface=None, use_ipv6=True):
880
927
self.interface = interface
882
929
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,
930
socketserver.TCPServer.__init__(self, server_address,
887
931
RequestHandlerClass)
888
932
def server_bind(self):
889
933
"""This overrides the normal server_bind() function
890
934
to bind to an interface if one was specified, and also NOT to
891
935
bind to an address or port if they were not specified."""
892
936
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",
937
if SO_BINDTODEVICE is None:
938
logger.error(u"SO_BINDTODEVICE does not exist;"
939
u" cannot bind to interface %s",
943
self.socket.setsockopt(socket.SOL_SOCKET,
947
except socket.error, error:
948
if error[0] == errno.EPERM:
949
logger.error(u"No permission to"
950
u" bind to interface %s",
952
elif error[0] == errno.ENOPROTOOPT:
953
logger.error(u"SO_BINDTODEVICE not available;"
954
u" cannot bind to interface %s",
904
958
# Only bind(2) the socket if we really need to.
905
959
if self.server_address[0] or self.server_address[1]:
906
960
if not self.server_address[0]:
907
961
if self.address_family == socket.AF_INET6:
908
any_address = "::" # in6addr_any
962
any_address = u"::" # in6addr_any
910
964
any_address = socket.INADDR_ANY
911
965
self.server_address = (any_address,
921
975
# (self.interface))
922
return SocketServer.TCPServer.server_bind(self)
976
return socketserver.TCPServer.server_bind(self)
979
class MandosServer(IPv6_TCPServer):
983
clients: set of Client objects
984
gnutls_priority GnuTLS priority string
985
use_dbus: Boolean; to emit D-Bus signals or not
986
clients: set of Client objects
987
gnutls_priority GnuTLS priority string
988
use_dbus: Boolean; to emit D-Bus signals or not
990
Assumes a gobject.MainLoop event loop.
992
def __init__(self, server_address, RequestHandlerClass,
993
interface=None, use_ipv6=True, clients=None,
994
gnutls_priority=None, use_dbus=True):
996
self.clients = clients
997
if self.clients is None:
999
self.use_dbus = use_dbus
1000
self.gnutls_priority = gnutls_priority
1001
IPv6_TCPServer.__init__(self, server_address,
1002
RequestHandlerClass,
1003
interface = interface,
1004
use_ipv6 = use_ipv6)
923
1005
def server_activate(self):
924
1006
if self.enabled:
925
return SocketServer.TCPServer.server_activate(self)
1007
return socketserver.TCPServer.server_activate(self)
926
1008
def enable(self):
927
1009
self.enabled = True
1010
def add_pipe(self, pipe):
1011
# Call "handle_ipc" for both data and EOF events
1012
gobject.io_add_watch(pipe, gobject.IO_IN | gobject.IO_HUP,
928
1014
def handle_ipc(self, source, condition, file_objects={}):
929
1015
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
1016
gobject.IO_IN: u"IN", # There is data to read.
1017
gobject.IO_OUT: u"OUT", # Data can be written (without
1019
gobject.IO_PRI: u"PRI", # There is urgent data to read.
1020
gobject.IO_ERR: u"ERR", # Error condition.
1021
gobject.IO_HUP: u"HUP" # Hung up (the connection has been
1022
# broken, usually for pipes and
939
1025
conditions_string = ' | '.join(name
940
1026
for cond, name in
941
1027
condition_names.iteritems()
942
1028
if cond & condition)
943
logger.debug("Handling IPC: FD = %d, condition = %s", source,
1029
logger.debug(u"Handling IPC: FD = %d, condition = %s", source,
944
1030
conditions_string)
946
1032
# Turn the pipe file descriptor into a Python file object
947
1033
if source not in file_objects:
948
file_objects[source] = os.fdopen(source, "r", 1)
1034
file_objects[source] = os.fdopen(source, u"r", 1)
950
1036
# Read a line from the file object
951
1037
cmdline = file_objects[source].readline()
1036
1122
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
1125
def if_nametoindex(interface):
1063
"""Call the C function if_nametoindex(), or equivalent"""
1126
"""Call the C function if_nametoindex(), or equivalent
1128
Note: This function cannot accept a unicode string."""
1064
1129
global if_nametoindex
1066
1131
if_nametoindex = (ctypes.cdll.LoadLibrary
1067
(ctypes.util.find_library("c"))
1132
(ctypes.util.find_library(u"c"))
1068
1133
.if_nametoindex)
1069
1134
except (OSError, AttributeError):
1070
if "struct" not in sys.modules:
1072
if "fcntl" not in sys.modules:
1135
logger.warning(u"Doing if_nametoindex the hard way")
1074
1136
def if_nametoindex(interface):
1075
1137
"Get an interface index the hard way, i.e. using fcntl()"
1076
1138
SIOCGIFINDEX = 0x8933 # From /usr/include/linux/sockios.h
1077
1139
with closing(socket.socket()) as s:
1078
1140
ifreq = fcntl.ioctl(s, SIOCGIFINDEX,
1079
struct.pack("16s16x", interface))
1080
interface_index = struct.unpack("I", ifreq[16:20])[0]
1141
struct.pack(str(u"16s16x"),
1143
interface_index = struct.unpack(str(u"I"),
1081
1145
return interface_index
1082
1146
return if_nametoindex(interface)
1112
1176
# Parsing of options, both command line and config file
1114
1178
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")
1179
parser.add_option("-i", u"--interface", type=u"string",
1180
metavar="IF", help=u"Bind to interface IF")
1181
parser.add_option("-a", u"--address", type=u"string",
1182
help=u"Address to listen for requests on")
1183
parser.add_option("-p", u"--port", type=u"int",
1184
help=u"Port number to receive requests on")
1185
parser.add_option("--check", action=u"store_true",
1186
help=u"Run self-test")
1187
parser.add_option("--debug", action=u"store_true",
1188
help=u"Debug mode; run in foreground and log to"
1190
parser.add_option("--priority", type=u"string", help=u"GnuTLS"
1191
u" priority string (see GnuTLS documentation)")
1192
parser.add_option("--servicename", type=u"string",
1193
metavar=u"NAME", help=u"Zeroconf service name")
1194
parser.add_option("--configdir", type=u"string",
1195
default=u"/etc/mandos", metavar=u"DIR",
1196
help=u"Directory to search for configuration"
1198
parser.add_option("--no-dbus", action=u"store_false",
1199
dest=u"use_dbus", help=u"Do not provide D-Bus"
1200
u" system bus interface")
1201
parser.add_option("--no-ipv6", action=u"store_false",
1202
dest=u"use_ipv6", help=u"Do not use IPv6")
1140
1203
options = parser.parse_args()[0]
1142
1205
if options.check:
1147
1210
# Default values for config file for server-global settings
1148
server_defaults = { "interface": "",
1153
"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1154
"servicename": "Mandos",
1211
server_defaults = { u"interface": u"",
1216
u"SECURE256:!CTYPE-X.509:+CTYPE-OPENPGP",
1217
u"servicename": u"Mandos",
1218
u"use_dbus": u"True",
1219
u"use_ipv6": u"True",
1159
1222
# Parse config file for server-global settings
1160
server_config = ConfigParser.SafeConfigParser(server_defaults)
1223
server_config = configparser.SafeConfigParser(server_defaults)
1161
1224
del server_defaults
1162
server_config.read(os.path.join(options.configdir, "mandos.conf"))
1225
server_config.read(os.path.join(options.configdir,
1163
1227
# Convert the SafeConfigParser object to a dict
1164
1228
server_settings = server_config.defaults()
1165
1229
# 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",
1230
for option in (u"debug", u"use_dbus", u"use_ipv6"):
1231
server_settings[option] = server_config.getboolean(u"DEFAULT",
1172
1233
if server_settings["port"]:
1173
server_settings["port"] = server_config.getint("DEFAULT",
1234
server_settings["port"] = server_config.getint(u"DEFAULT",
1175
1236
del server_config
1177
1238
# Override the settings from the config file with command line
1178
1239
# options, if set.
1179
for option in ("interface", "address", "port", "debug",
1180
"priority", "servicename", "configdir",
1181
"use_dbus", "use_ipv6"):
1240
for option in (u"interface", u"address", u"port", u"debug",
1241
u"priority", u"servicename", u"configdir",
1242
u"use_dbus", u"use_ipv6"):
1182
1243
value = getattr(options, option)
1183
1244
if value is not None:
1184
1245
server_settings[option] = value
1247
# Force all strings to be unicode
1248
for option in server_settings.keys():
1249
if type(server_settings[option]) is str:
1250
server_settings[option] = unicode(server_settings[option])
1186
1251
# Now we have our good server settings in "server_settings"
1188
1253
##################################################################
1190
1255
# For convenience
1191
debug = server_settings["debug"]
1192
use_dbus = server_settings["use_dbus"]
1193
use_ipv6 = server_settings["use_ipv6"]
1256
debug = server_settings[u"debug"]
1257
use_dbus = server_settings[u"use_dbus"]
1258
use_ipv6 = server_settings[u"use_ipv6"]
1196
1261
syslogger.setLevel(logging.WARNING)
1197
1262
console.setLevel(logging.WARNING)
1199
if server_settings["servicename"] != "Mandos":
1264
if server_settings[u"servicename"] != u"Mandos":
1200
1265
syslogger.setFormatter(logging.Formatter
1201
('Mandos (%s) [%%(process)d]:'
1202
' %%(levelname)s: %%(message)s'
1203
% server_settings["servicename"]))
1266
(u'Mandos (%s) [%%(process)d]:'
1267
u' %%(levelname)s: %%(message)s'
1268
% server_settings[u"servicename"]))
1205
1270
# Parse config file with clients
1206
client_defaults = { "timeout": "1h",
1208
"checker": "fping -q -- %%(host)s",
1271
client_defaults = { u"timeout": u"1h",
1273
u"checker": u"fping -q -- %%(host)s",
1211
client_config = ConfigParser.SafeConfigParser(client_defaults)
1212
client_config.read(os.path.join(server_settings["configdir"],
1276
client_config = configparser.SafeConfigParser(client_defaults)
1277
client_config.read(os.path.join(server_settings[u"configdir"],
1215
1280
global mandos_dbus_service
1216
1281
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"
1283
tcp_server = MandosServer((server_settings[u"address"],
1284
server_settings[u"port"]),
1286
interface=server_settings[u"interface"],
1289
server_settings[u"priority"],
1291
pidfilename = u"/var/run/mandos.pid"
1231
pidfile = open(pidfilename, "w")
1293
pidfile = open(pidfilename, u"w")
1232
1294
except IOError:
1233
logger.error("Could not open file %r", pidfilename)
1295
logger.error(u"Could not open file %r", pidfilename)
1236
uid = pwd.getpwnam("_mandos").pw_uid
1237
gid = pwd.getpwnam("_mandos").pw_gid
1298
uid = pwd.getpwnam(u"_mandos").pw_uid
1299
gid = pwd.getpwnam(u"_mandos").pw_gid
1238
1300
except KeyError:
1240
uid = pwd.getpwnam("mandos").pw_uid
1241
gid = pwd.getpwnam("mandos").pw_gid
1302
uid = pwd.getpwnam(u"mandos").pw_uid
1303
gid = pwd.getpwnam(u"mandos").pw_gid
1242
1304
except KeyError:
1244
uid = pwd.getpwnam("nobody").pw_uid
1245
gid = pwd.getpwnam("nogroup").pw_gid
1306
uid = pwd.getpwnam(u"nobody").pw_uid
1307
gid = pwd.getpwnam(u"nobody").pw_gid
1246
1308
except KeyError:
1262
1324
@gnutls.library.types.gnutls_log_func
1263
1325
def debug_gnutls(level, string):
1264
logger.debug("GnuTLS: %s", string[:-1])
1326
logger.debug(u"GnuTLS: %s", string[:-1])
1266
1328
(gnutls.library.functions
1267
1329
.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
1331
global main_loop
1281
1332
# From the Avahi example code
1282
1333
DBusGMainLoop(set_as_default=True )
1283
1334
main_loop = gobject.MainLoop()
1284
1335
bus = dbus.SystemBus()
1285
server = dbus.Interface(bus.get_object(avahi.DBUS_NAME,
1286
avahi.DBUS_PATH_SERVER),
1287
avahi.DBUS_INTERFACE_SERVER)
1288
1336
# End of Avahi example code
1290
1338
bus_name = dbus.service.BusName(u"se.bsnet.fukt.Mandos", bus)
1339
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
1340
service = AvahiService(name = server_settings[u"servicename"],
1341
servicetype = u"_mandos._tcp",
1342
protocol = protocol, bus = bus)
1343
if server_settings["interface"]:
1344
service.interface = (if_nametoindex
1345
(str(server_settings[u"interface"])))
1292
1347
client_class = Client
1294
client_class = ClientDBus
1349
client_class = functools.partial(ClientDBus, bus = bus)
1350
tcp_server.clients.update(set(
1296
1351
client_class(name = section,
1297
1352
config= dict(client_config.items(section)))
1298
1353
for section in client_config.sections()))
1354
if not tcp_server.clients:
1300
1355
logger.warning(u"No clients defined")
1349
1399
class MandosDBusService(dbus.service.Object):
1350
1400
"""A D-Bus proxy object"""
1351
1401
def __init__(self):
1352
dbus.service.Object.__init__(self, bus, "/")
1402
dbus.service.Object.__init__(self, bus, u"/")
1353
1403
_interface = u"se.bsnet.fukt.Mandos"
1355
@dbus.service.signal(_interface, signature="oa{sv}")
1405
@dbus.service.signal(_interface, signature=u"oa{sv}")
1356
1406
def ClientAdded(self, objpath, properties):
1360
@dbus.service.signal(_interface, signature="s")
1410
@dbus.service.signal(_interface, signature=u"s")
1361
1411
def ClientNotFound(self, fingerprint):
1365
@dbus.service.signal(_interface, signature="os")
1415
@dbus.service.signal(_interface, signature=u"os")
1366
1416
def ClientRemoved(self, objpath, name):
1370
@dbus.service.method(_interface, out_signature="ao")
1420
@dbus.service.method(_interface, out_signature=u"ao")
1371
1421
def GetAllClients(self):
1373
return dbus.Array(c.dbus_object_path for c in clients)
1423
return dbus.Array(c.dbus_object_path
1424
for c in tcp_server.clients)
1375
@dbus.service.method(_interface, out_signature="a{oa{sv}}")
1426
@dbus.service.method(_interface,
1427
out_signature=u"a{oa{sv}}")
1376
1428
def GetAllClientsWithProperties(self):
1378
1430
return dbus.Dictionary(
1379
1431
((c.dbus_object_path, c.GetAllProperties())
1432
for c in tcp_server.clients),
1433
signature=u"oa{sv}")
1383
@dbus.service.method(_interface, in_signature="o")
1435
@dbus.service.method(_interface, in_signature=u"o")
1384
1436
def RemoveClient(self, object_path):
1438
for c in tcp_server.clients:
1387
1439
if c.dbus_object_path == object_path:
1440
tcp_server.clients.remove(c)
1389
1441
c.remove_from_connection()
1390
1442
# Don't signal anything except ClientRemoved
1391
1443
c.disable(signal=False)