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