189
189
facility=logging.handlers.SysLogHandler.LOG_DAEMON,
190
190
address="/dev/log"))
191
191
syslogger.setFormatter(logging.Formatter
192
("Mandos [%(process)d]: %(levelname)s:"
192
('Mandos [%(process)d]: %(levelname)s:'
194
194
logger.addHandler(syslogger)
197
197
console = logging.StreamHandler()
198
console.setFormatter(logging.Formatter("%(asctime)s %(name)s"
198
console.setFormatter(logging.Formatter('%(asctime)s %(name)s'
202
202
logger.addHandler(console)
203
203
logger.setLevel(level)
224
224
except OSError as e:
225
225
if e.errno != errno.ENOENT:
227
self.gnupgargs = ["--batch",
228
"--homedir", self.tempdir,
227
self.gnupgargs = ['--batch',
228
'--homedir', self.tempdir,
231
231
# Only GPG version 1 has the --no-use-agent option.
232
232
if self.gpg == b"gpg" or self.gpg.endswith(b"/gpg"):
233
233
self.gnupgargs.append("--no-use-agent")
272
272
dir=self.tempdir) as passfile:
273
273
passfile.write(passphrase)
275
proc = subprocess.Popen([self.gpg, "--symmetric",
275
proc = subprocess.Popen([self.gpg, '--symmetric',
278
278
+ self.gnupgargs,
279
279
stdin=subprocess.PIPE,
290
290
dir=self.tempdir) as passfile:
291
291
passfile.write(passphrase)
293
proc = subprocess.Popen([self.gpg, "--decrypt",
293
proc = subprocess.Popen([self.gpg, '--decrypt',
296
296
+ self.gnupgargs,
297
297
stdin=subprocess.PIPE,
351
351
interface: integer; avahi.IF_UNSPEC or an interface index.
352
352
Used to optionally bind to the specified interface.
353
name: string; Example: "Mandos"
354
type: string; Example: "_mandos._tcp".
353
name: string; Example: 'Mandos'
354
type: string; Example: '_mandos._tcp'.
355
355
See <https://www.iana.org/assignments/service-names-port-numbers>
356
356
port: integer; what port to announce
357
357
TXT: list of strings; TXT record for the service
435
435
avahi.DBUS_INTERFACE_ENTRY_GROUP)
436
436
self.entry_group_state_changed_match = (
437
437
self.group.connect_to_signal(
438
"StateChanged", self.entry_group_state_changed))
438
'StateChanged', self.entry_group_state_changed))
439
439
logger.debug("Adding Zeroconf service '%s' of type '%s' ...",
440
440
self.name, self.type)
441
441
self.group.AddService(
527
527
ret = super(AvahiServiceToSyslog, self).rename(*args,
529
529
syslogger.setFormatter(logging.Formatter(
530
"Mandos ({}) [%(process)d]: %(levelname)s: %(message)s"
530
'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
531
531
.format(self.name)))
574
574
certificate_type_t = ctypes.c_int
576
576
class datum_t(ctypes.Structure):
577
_fields_ = [("data", ctypes.POINTER(ctypes.c_ubyte)),
578
("size", ctypes.c_uint)]
577
_fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
578
('size', ctypes.c_uint)]
580
580
class _openpgp_crt_int(ctypes.Structure):
676
676
# Error handling functions
677
677
def _error_code(result):
678
678
"""A function to raise exceptions on errors, suitable
679
for the "restype" attribute on ctypes functions"""
679
for the 'restype' attribute on ctypes functions"""
680
680
if result >= gnutls.E_SUCCESS:
682
682
if result == gnutls.E_NO_CERTIFICATE_FOUND:
686
686
def _retry_on_error(result, func, arguments,
687
687
_error_code=_error_code):
688
688
"""A function to retry on some errors, suitable
689
for the "errcheck" attribute on ctypes functions"""
689
for the 'errcheck' attribute on ctypes functions"""
690
690
while result < gnutls.E_SUCCESS:
691
691
if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
692
692
return _error_code(result)
876
876
"""A representation of a client host served by this server.
879
approved: bool(); None if not yet approved/disapproved
879
approved: bool(); 'None' if not yet approved/disapproved
880
880
approval_delay: datetime.timedelta(); Time to wait for approval
881
881
approval_duration: datetime.timedelta(); Duration of one approval
882
882
checker: multiprocessing.Process(); a running checker process used
883
to see if the client lives. None if no process is
883
to see if the client lives. 'None' if no process is
885
885
checker_callback_tag: a GLib event source tag, or None
886
886
checker_command: string; External command which is run to check
1242
1242
func._dbus_name = func.__name__
1243
1243
if func._dbus_name.endswith("_dbus_property"):
1244
1244
func._dbus_name = func._dbus_name[:-14]
1245
func._dbus_get_args_options = {"byte_arrays": byte_arrays}
1245
func._dbus_get_args_options = {'byte_arrays': byte_arrays}
1248
1248
return decorator
1338
1338
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1339
1339
out_signature="s",
1340
path_keyword="object_path",
1341
connection_keyword="connection")
1340
path_keyword='object_path',
1341
connection_keyword='connection')
1342
1342
def Introspect(self, object_path, connection):
1343
1343
"""Overloading of standard D-Bus method.
1498
1498
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1499
1499
out_signature="s",
1500
path_keyword="object_path",
1501
connection_keyword="connection")
1500
path_keyword='object_path',
1501
connection_keyword='connection')
1502
1502
def Introspect(self, object_path, connection):
1503
1503
"""Overloading of standard D-Bus method.
1600
1600
@dbus.service.method(dbus.INTROSPECTABLE_IFACE,
1601
1601
out_signature="s",
1602
path_keyword="object_path",
1603
connection_keyword="connection")
1602
path_keyword='object_path',
1603
connection_keyword='connection')
1604
1604
def Introspect(self, object_path, connection):
1605
1605
"""Overloading of standard D-Bus method.
2272
2272
class ProxyClient:
2273
2273
def __init__(self, child_pipe, key_id, fpr, address):
2274
2274
self._pipe = child_pipe
2275
self._pipe.send(("init", key_id, fpr, address))
2275
self._pipe.send(('init', key_id, fpr, address))
2276
2276
if not self._pipe.recv():
2277
2277
raise KeyError(key_id or fpr)
2279
2279
def __getattribute__(self, name):
2281
2281
return super(ProxyClient, self).__getattribute__(name)
2282
self._pipe.send(("getattr", name))
2282
self._pipe.send(('getattr', name))
2283
2283
data = self._pipe.recv()
2284
if data[0] == "data":
2284
if data[0] == 'data':
2286
if data[0] == "function":
2286
if data[0] == 'function':
2288
2288
def func(*args, **kwargs):
2289
self._pipe.send(("funcall", name, args, kwargs))
2289
self._pipe.send(('funcall', name, args, kwargs))
2290
2290
return self._pipe.recv()[1]
2294
2294
def __setattr__(self, name, value):
2296
2296
return super(ProxyClient, self).__setattr__(name, value)
2297
self._pipe.send(("setattr", name, value))
2297
self._pipe.send(('setattr', name, value))
2300
2300
class ClientHandler(socketserver.BaseRequestHandler, object):
2313
2313
session = gnutls.ClientSession(self.request)
2315
# priority = ":".join(("NONE", "+VERS-TLS1.1",
2315
# priority = ':'.join(("NONE", "+VERS-TLS1.1",
2316
2316
# "+AES-256-CBC", "+SHA1",
2317
2317
# "+COMP-NULL", "+CTYPE-OPENPGP",
2591
2591
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2592
2592
socketserver.TCPServer):
2593
"""IPv6-capable TCP server. Accepts None as address and/or port
2593
"""IPv6-capable TCP server. Accepts 'None' as address and/or port
2596
2596
enabled: Boolean; whether this server is activated yet
2784
2784
# remove the old hook in favor of the new above hook on
2787
if command == "funcall":
2787
if command == 'funcall':
2788
2788
funcname = request[1]
2789
2789
args = request[2]
2790
2790
kwargs = request[3]
2792
parent_pipe.send(("data", getattr(client_object,
2792
parent_pipe.send(('data', getattr(client_object,
2793
2793
funcname)(*args,
2796
if command == "getattr":
2796
if command == 'getattr':
2797
2797
attrname = request[1]
2798
2798
if isinstance(client_object.__getattribute__(attrname),
2799
2799
collections.abc.Callable):
2800
parent_pipe.send(("function", ))
2800
parent_pipe.send(('function', ))
2802
2802
parent_pipe.send((
2803
"data", client_object.__getattribute__(attrname)))
2803
'data', client_object.__getattribute__(attrname)))
2805
if command == "setattr":
2805
if command == 'setattr':
2806
2806
attrname = request[1]
2807
2807
value = request[2]
2808
2808
setattr(client_object, attrname, value)
2914
2914
def string_to_delta(interval):
2915
2915
"""Parse a string and return a datetime.timedelta
2917
>>> string_to_delta("7d") == datetime.timedelta(7)
2919
>>> string_to_delta("60s") == datetime.timedelta(0, 60)
2921
>>> string_to_delta("60m") == datetime.timedelta(0, 3600)
2923
>>> string_to_delta("24h") == datetime.timedelta(1)
2925
>>> string_to_delta("1w") == datetime.timedelta(7)
2927
>>> string_to_delta("5m 30s") == datetime.timedelta(0, 330)
2917
>>> string_to_delta('7d') == datetime.timedelta(7)
2919
>>> string_to_delta('60s') == datetime.timedelta(0, 60)
2921
>>> string_to_delta('60m') == datetime.timedelta(0, 3600)
2923
>>> string_to_delta('24h') == datetime.timedelta(1)
2925
>>> string_to_delta('1w') == datetime.timedelta(7)
2927
>>> string_to_delta('5m 30s') == datetime.timedelta(0, 330)
3135
3135
if server_settings["servicename"] != "Mandos":
3136
3136
syslogger.setFormatter(
3137
logging.Formatter("Mandos ({}) [%(process)d]:"
3138
" %(levelname)s: %(message)s".format(
3137
logging.Formatter('Mandos ({}) [%(process)d]:'
3138
' %(levelname)s: %(message)s'.format(
3139
3139
server_settings["servicename"])))
3141
3141
# Parse config file with clients
3586
3586
with tempfile.NamedTemporaryFile(
3588
3588
suffix=".pickle",
3590
3590
dir=os.path.dirname(stored_state_path),
3591
3591
delete=False) as stored_state:
3592
3592
pickle.dump((clients, client_settings), stored_state,
3680
3680
def should_only_run_tests():
3681
3681
parser = argparse.ArgumentParser(add_help=False)
3682
parser.add_argument("--check", action="store_true")
3682
parser.add_argument("--check", action='store_true')
3683
3683
args, unknown_args = parser.parse_known_args()
3684
3684
run_tests = args.check
3693
3693
tests.addTests(doctest.DocTestSuite())
3696
if __name__ == "__main__":
3696
if __name__ == '__main__':
3698
3698
if should_only_run_tests():
3699
3699
# Call using ./mandos --check [--verbose]