11
11
# "AvahiService" class, and some lines in "main".
13
13
# Everything else is
14
# Copyright © 2008-2012 Teddy Hogeborn
15
# Copyright © 2008-2012 Björn Påhlsson
14
# Copyright © 2008-2014 Teddy Hogeborn
15
# Copyright © 2008-2014 Björn Påhlsson
17
17
# This program is free software: you can redistribute it and/or modify
18
18
# it under the terms of the GNU General Public License as published by
88
88
except ImportError:
89
89
SO_BINDTODEVICE = None
92
92
stored_state_file = "clients.pickle"
94
94
logger = logging.getLogger()
95
syslogger = (logging.handlers.SysLogHandler
96
(facility = logging.handlers.SysLogHandler.LOG_DAEMON,
97
address = str("/dev/log")))
100
98
if_nametoindex = (ctypes.cdll.LoadLibrary
116
114
def initlogger(debug, level=logging.WARNING):
117
115
"""init logger and add loglevel"""
118
syslogger = (logging.handlers.SysLogHandler
120
logging.handlers.SysLogHandler.LOG_DAEMON,
121
address = str("/dev/log")))
119
122
syslogger.setFormatter(logging.Formatter
120
123
('Mandos [%(process)d]: %(levelname)s:'
172
175
def password_encode(self, password):
173
176
# Passphrase can not be empty and can not contain newlines or
174
177
# NUL bytes. So we prefix it and hex encode it.
175
return b"mandos" + binascii.hexlify(password)
178
encoded = b"mandos" + binascii.hexlify(password)
179
if len(encoded) > 2048:
180
# GnuPG can't handle long passwords, so encode differently
181
encoded = (b"mandos" + password.replace(b"\\", b"\\\\")
182
.replace(b"\n", b"\\n")
183
.replace(b"\0", b"\\x00"))
177
186
def encrypt(self, data, password):
178
187
passphrase = self.password_encode(password)
684
693
# If a checker exists, make sure it is not a zombie
686
695
pid, status = os.waitpid(self.checker.pid, os.WNOHANG)
687
except (AttributeError, OSError) as error:
688
if (isinstance(error, OSError)
689
and error.errno != errno.ECHILD):
696
except AttributeError:
698
except OSError as error:
699
if error.errno != errno.ECHILD:
693
703
logger.warning("Checker was a zombie")
927
937
# The byte_arrays option is not supported yet on
928
938
# signatures other than "ay".
929
939
if prop._dbus_signature != "ay":
940
raise ValueError("Byte arrays not supported for non-"
941
"'ay' signature {0!r}"
942
.format(prop._dbus_signature))
931
943
value = dbus.ByteArray(b''.join(chr(byte)
932
944
for byte in value))
1341
1353
*args, **kwargs)
1343
1355
def start_checker(self, *args, **kwargs):
1344
old_checker = self.checker
1345
if self.checker is not None:
1346
old_checker_pid = self.checker.pid
1348
old_checker_pid = None
1356
old_checker_pid = getattr(self.checker, "pid", None)
1349
1357
r = Client.start_checker(self, *args, **kwargs)
1350
1358
# Only if new checker process was started
1351
1359
if (self.checker is not None
1696
1704
logger.debug("Protocol version: %r", line)
1698
1706
if int(line.strip().split()[0]) > 1:
1707
raise RuntimeError(line)
1700
1708
except (ValueError, IndexError, RuntimeError) as error:
1701
1709
logger.error("Unknown protocol version: %s", error)
1910
1918
def add_pipe(self, parent_pipe, proc):
1911
1919
"""Dummy function; override as necessary"""
1912
raise NotImplementedError
1920
raise NotImplementedError()
1915
1923
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
1991
1999
if self.address_family == socket.AF_INET6:
1992
2000
any_address = "::" # in6addr_any
1994
any_address = socket.INADDR_ANY
2002
any_address = "0.0.0.0" # INADDR_ANY
1995
2003
self.server_address = (any_address,
1996
2004
self.server_address[1])
1997
2005
elif not self.server_address[1]:
2302
2310
help="Run self-test")
2303
2311
parser.add_argument("--debug", action="store_true",
2304
2312
help="Debug mode; run in foreground and log"
2313
" to terminal", default=None)
2306
2314
parser.add_argument("--debuglevel", metavar="LEVEL",
2307
2315
help="Debug level for stdout output")
2308
2316
parser.add_argument("--priority", help="GnuTLS"
2316
2324
parser.add_argument("--no-dbus", action="store_false",
2317
2325
dest="use_dbus", help="Do not provide D-Bus"
2318
" system bus interface")
2326
" system bus interface", default=None)
2319
2327
parser.add_argument("--no-ipv6", action="store_false",
2320
dest="use_ipv6", help="Do not use IPv6")
2328
dest="use_ipv6", help="Do not use IPv6",
2321
2330
parser.add_argument("--no-restore", action="store_false",
2322
2331
dest="restore", help="Do not restore stored"
2332
" state", default=None)
2324
2333
parser.add_argument("--socket", type=int,
2325
2334
help="Specify a file descriptor to a network"
2326
2335
" socket to use instead of creating one")
2327
2336
parser.add_argument("--statedir", metavar="DIR",
2328
2337
help="Directory to save/restore state in")
2329
2338
parser.add_argument("--foreground", action="store_true",
2330
help="Run in foreground")
2339
help="Run in foreground", default=None)
2340
parser.add_argument("--no-zeroconf", action="store_false",
2341
dest="zeroconf", help="Do not use Zeroconf",
2332
2344
options = parser.parse_args()
2334
2346
if options.check:
2348
fail_count, test_count = doctest.testmod()
2349
sys.exit(os.EX_OK if fail_count == 0 else 1)
2339
2351
# Default values for config file for server-global settings
2340
2352
server_defaults = { "interface": "",
2383
2396
for option in ("interface", "address", "port", "debug",
2384
2397
"priority", "servicename", "configdir",
2385
2398
"use_dbus", "use_ipv6", "debuglevel", "restore",
2386
"statedir", "socket", "foreground"):
2399
"statedir", "socket", "foreground", "zeroconf"):
2387
2400
value = getattr(options, option)
2388
2401
if value is not None:
2389
2402
server_settings[option] = value
2392
2405
for option in server_settings.keys():
2393
2406
if type(server_settings[option]) is str:
2394
2407
server_settings[option] = unicode(server_settings[option])
2408
# Force all boolean options to be boolean
2409
for option in ("debug", "use_dbus", "use_ipv6", "restore",
2410
"foreground", "zeroconf"):
2411
server_settings[option] = bool(server_settings[option])
2395
2412
# Debug implies foreground
2396
2413
if server_settings["debug"]:
2397
2414
server_settings["foreground"] = True
2400
2417
##################################################################
2419
if (not server_settings["zeroconf"] and
2420
not (server_settings["port"]
2421
or server_settings["socket"] != "")):
2422
parser.error("Needs port or socket to work without"
2402
2425
# For convenience
2403
2426
debug = server_settings["debug"]
2404
2427
debuglevel = server_settings["debuglevel"]
2407
2430
stored_state_path = os.path.join(server_settings["statedir"],
2408
2431
stored_state_file)
2409
2432
foreground = server_settings["foreground"]
2433
zeroconf = server_settings["zeroconf"]
2412
2436
initlogger(debug, logging.DEBUG)
2433
2457
global mandos_dbus_service
2434
2458
mandos_dbus_service = None
2461
if server_settings["socket"] != "":
2462
socketfd = server_settings["socket"]
2436
2463
tcp_server = MandosServer((server_settings["address"],
2437
2464
server_settings["port"]),
2442
2469
gnutls_priority=
2443
2470
server_settings["priority"],
2444
2471
use_dbus=use_dbus,
2445
socketfd=(server_settings["socket"]
2447
2473
if not foreground:
2448
pidfilename = "/var/run/mandos.pid"
2474
pidfilename = "/run/mandos.pid"
2475
if not os.path.isdir("/run/."):
2476
pidfilename = "/var/run/mandos.pid"
2451
2479
pidfile = open(pidfilename, "w")
2517
2545
use_dbus = False
2518
2546
server_settings["use_dbus"] = False
2519
2547
tcp_server.use_dbus = False
2520
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
2521
service = AvahiServiceToSyslog(name =
2522
server_settings["servicename"],
2523
servicetype = "_mandos._tcp",
2524
protocol = protocol, bus = bus)
2525
if server_settings["interface"]:
2526
service.interface = (if_nametoindex
2527
(str(server_settings["interface"])))
2549
protocol = avahi.PROTO_INET6 if use_ipv6 else avahi.PROTO_INET
2550
service = AvahiServiceToSyslog(name =
2551
server_settings["servicename"],
2552
servicetype = "_mandos._tcp",
2553
protocol = protocol, bus = bus)
2554
if server_settings["interface"]:
2555
service.interface = (if_nametoindex
2556
(str(server_settings["interface"])))
2529
2558
global multiprocessing_manager
2530
2559
multiprocessing_manager = multiprocessing.Manager()
2809
2839
tcp_server.server_activate()
2811
2841
# Find out what port we got
2812
service.port = tcp_server.socket.getsockname()[1]
2843
service.port = tcp_server.socket.getsockname()[1]
2814
2845
logger.info("Now listening on address %r, port %d,"
2815
2846
" flowinfo %d, scope_id %d",
2821
2852
#service.interface = tcp_server.socket.getsockname()[3]
2824
# From the Avahi example code
2827
except dbus.exceptions.DBusException as error:
2828
logger.critical("D-Bus Exception", exc_info=error)
2831
# End of Avahi example code
2856
# From the Avahi example code
2859
except dbus.exceptions.DBusException as error:
2860
logger.critical("D-Bus Exception", exc_info=error)
2863
# End of Avahi example code
2833
2865
gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN,
2834
2866
lambda *args, **kwargs: