11
11
# "AvahiService" class, and some lines in "main".
13
13
# Everything else is
14
# Copyright © 2008-2015 Teddy Hogeborn
15
# Copyright © 2008-2015 Björn Påhlsson
14
# Copyright © 2008-2016 Teddy Hogeborn
15
# Copyright © 2008-2016 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
34
34
from __future__ import (division, absolute_import, print_function,
37
from future_builtins import *
38
from future_builtins import *
40
43
import SocketServer as socketserver
78
81
import dbus.service
82
from gi.repository import GObject as gobject
82
from gi.repository import GLib
84
83
from dbus.mainloop.glib import DBusGMainLoop
87
86
import xml.dom.minidom
89
# Try to find the value of SO_BINDTODEVICE:
91
# This is where SO_BINDTODEVICE is in Python 3.3 (or 3.4?) and
92
# newer, and it is also the most natural place for it:
91
93
SO_BINDTODEVICE = socket.SO_BINDTODEVICE
92
94
except AttributeError:
96
# This is where SO_BINDTODEVICE was up to and including Python
94
98
from IN import SO_BINDTODEVICE
95
99
except ImportError:
96
SO_BINDTODEVICE = None
100
# In Python 2.7 it seems to have been removed entirely.
101
# Try running the C preprocessor:
103
cc = subprocess.Popen(["cc", "--language=c", "-E",
105
stdin=subprocess.PIPE,
106
stdout=subprocess.PIPE)
107
stdout = cc.communicate(
108
"#include <sys/socket.h>\nSO_BINDTODEVICE\n")[0]
109
SO_BINDTODEVICE = int(stdout.splitlines()[-1])
110
except (OSError, ValueError, IndexError):
112
SO_BINDTODEVICE = None
98
114
if sys.version_info.major == 2:
102
118
stored_state_file = "clients.pickle"
104
120
logger = logging.getLogger()
119
135
return interface_index
138
def copy_function(func):
139
"""Make a copy of a function"""
140
if sys.version_info.major == 2:
141
return types.FunctionType(func.func_code,
147
return types.FunctionType(func.__code__,
122
154
def initlogger(debug, level=logging.WARNING):
123
155
"""init logger and add loglevel"""
152
184
def __init__(self):
153
185
self.tempdir = tempfile.mkdtemp(prefix="mandos-")
188
output = subprocess.check_output(["gpgconf"])
189
for line in output.splitlines():
190
name, text, path = line.split(b":")
195
if e.errno != errno.ENOENT:
154
197
self.gnupgargs = ['--batch',
155
'--home', self.tempdir,
198
'--homedir', self.tempdir,
201
# Only GPG version 1 has the --no-use-agent option.
202
if self.gpg == "gpg" or self.gpg.endswith("/gpg"):
203
self.gnupgargs.append("--no-use-agent")
160
205
def __enter__(self):
197
242
dir=self.tempdir) as passfile:
198
243
passfile.write(passphrase)
200
proc = subprocess.Popen(['gpg', '--symmetric',
245
proc = subprocess.Popen([self.gpg, '--symmetric',
201
246
'--passphrase-file',
203
248
+ self.gnupgargs,
215
260
dir = self.tempdir) as passfile:
216
261
passfile.write(passphrase)
218
proc = subprocess.Popen(['gpg', '--decrypt',
263
proc = subprocess.Popen([self.gpg, '--decrypt',
219
264
'--passphrase-file',
221
266
+ self.gnupgargs,
227
272
raise PGPError(err)
228
273
return decrypted_plaintext
275
# Pretend that we have an Avahi module
277
"""This isn't so much a class as it is a module-like namespace.
278
It is instantiated once, and simulates having an Avahi module."""
279
IF_UNSPEC = -1 # avahi-common/address.h
280
PROTO_UNSPEC = -1 # avahi-common/address.h
281
PROTO_INET = 0 # avahi-common/address.h
282
PROTO_INET6 = 1 # avahi-common/address.h
283
DBUS_NAME = "org.freedesktop.Avahi"
284
DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + ".EntryGroup"
285
DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server"
286
DBUS_PATH_SERVER = "/"
287
def string_array_to_txt_array(self, t):
288
return dbus.Array((dbus.ByteArray(s.encode("utf-8"))
289
for s in t), signature="ay")
290
ENTRY_GROUP_ESTABLISHED = 2 # avahi-common/defs.h
291
ENTRY_GROUP_COLLISION = 3 # avahi-common/defs.h
292
ENTRY_GROUP_FAILURE = 4 # avahi-common/defs.h
293
SERVER_INVALID = 0 # avahi-common/defs.h
294
SERVER_REGISTERING = 1 # avahi-common/defs.h
295
SERVER_RUNNING = 2 # avahi-common/defs.h
296
SERVER_COLLISION = 3 # avahi-common/defs.h
297
SERVER_FAILURE = 4 # avahi-common/defs.h
231
300
class AvahiError(Exception):
232
301
def __init__(self, value, *args, **kwargs):
474
545
openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
475
546
openpgp_crt_fmt_t = ctypes.c_int # gnutls/openpgp.h
476
547
log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
477
credentials_type_t = ctypes.c_int #
548
credentials_type_t = ctypes.c_int
478
549
transport_ptr_t = ctypes.c_void_p
479
550
close_request_t = ctypes.c_int
483
554
# We need to use the class name "GnuTLS" here, since this
484
555
# exception might be raised from within GnuTLS.__init__,
485
556
# which is called before the assignment to the "gnutls"
486
# global variable happens.
557
# global variable has happened.
487
558
def __init__(self, message = None, code = None, args=()):
488
559
# Default usage is by a message string, but if a return
489
560
# code is passed, convert it to a string with
490
561
# gnutls.strerror()
491
563
if message is None and code is not None:
492
564
message = GnuTLS.strerror(code)
493
565
return super(GnuTLS.Error, self).__init__(
532
604
def send(self, data):
533
605
data = bytes(data)
536
return gnutls.record_send(self._c_object, data, len(data))
608
data_len -= gnutls.record_send(self._c_object,
539
613
return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
541
# Error handling function
615
# Error handling functions
542
616
def _error_code(result):
543
617
"""A function to raise exceptions on errors, suitable
544
618
for the 'restype' attribute on ctypes functions"""
548
622
raise gnutls.CertificateSecurityError(code = result)
549
623
raise gnutls.Error(code = result)
625
def _retry_on_error(result, func, arguments):
626
"""A function to retry on some errors, suitable
627
for the 'errcheck' attribute on ctypes functions"""
629
if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
630
return _error_code(result)
631
result = func(*arguments)
551
634
# Unless otherwise indicated, the function declarations below are
552
635
# all from the gnutls/gnutls.h C header file.
569
652
record_send.argtypes = [session_t, ctypes.c_void_p,
571
654
record_send.restype = ctypes.c_ssize_t
655
record_send.errcheck = _retry_on_error
573
657
certificate_allocate_credentials = (
574
658
_library.gnutls_certificate_allocate_credentials)
620
704
handshake = _library.gnutls_handshake
621
705
handshake.argtypes = [session_t]
622
706
handshake.restype = _error_code
707
handshake.errcheck = _retry_on_error
624
709
transport_set_ptr = _library.gnutls_transport_set_ptr
625
710
transport_set_ptr.argtypes = [session_t, transport_ptr_t]
628
713
bye = _library.gnutls_bye
629
714
bye.argtypes = [session_t, close_request_t]
630
715
bye.restype = _error_code
716
bye.errcheck = _retry_on_error
632
718
check_version = _library.gnutls_check_version
633
719
check_version.argtypes = [ctypes.c_char_p]
662
748
ctypes.c_size_t)]
663
749
openpgp_crt_get_fingerprint.restype = _error_code
665
# Remove non-public function
751
# Remove non-public functions
752
del _error_code, _retry_on_error
667
753
# Create the global "gnutls" object, simulating a module
668
754
gnutls = GnuTLS()
687
773
checker: subprocess.Popen(); a running checker process used
688
774
to see if the client lives.
689
775
'None' if no process is running.
690
checker_callback_tag: a gobject event source tag, or None
776
checker_callback_tag: a GLib event source tag, or None
691
777
checker_command: string; External command which is run to check
692
778
if client lives. %() expansions are done at
693
779
runtime with vars(self) as dict, so that for
694
780
instance %(name)s can be used in the command.
695
checker_initiator_tag: a gobject event source tag, or None
781
checker_initiator_tag: a GLib event source tag, or None
696
782
created: datetime.datetime(); (UTC) object creation
697
783
client_structure: Object describing what attributes a client has
698
784
and is used for storing the client at exit
699
785
current_checker_command: string; current running checker_command
700
disable_initiator_tag: a gobject event source tag, or None
786
disable_initiator_tag: a GLib event source tag, or None
702
788
fingerprint: string (40 or 32 hexadecimal digits); used to
703
789
uniquely identify the client
766
852
client["fingerprint"] = (section["fingerprint"].upper()
767
853
.replace(" ", ""))
768
854
if "secret" in section:
769
client["secret"] = section["secret"].decode("base64")
855
client["secret"] = codecs.decode(section["secret"]
770
858
elif "secfile" in section:
771
859
with open(os.path.expanduser(os.path.expandvars
772
860
(section["secfile"])),
825
913
self.changedstate = multiprocessing_manager.Condition(
826
914
multiprocessing_manager.Lock())
827
915
self.client_structure = [attr
828
for attr in self.__dict__.iterkeys()
916
for attr in self.__dict__.keys()
829
917
if not attr.startswith("_")]
830
918
self.client_structure.append("client_structure")
858
946
logger.info("Disabling client %s", self.name)
859
947
if getattr(self, "disable_initiator_tag", None) is not None:
860
gobject.source_remove(self.disable_initiator_tag)
948
GLib.source_remove(self.disable_initiator_tag)
861
949
self.disable_initiator_tag = None
862
950
self.expires = None
863
951
if getattr(self, "checker_initiator_tag", None) is not None:
864
gobject.source_remove(self.checker_initiator_tag)
952
GLib.source_remove(self.checker_initiator_tag)
865
953
self.checker_initiator_tag = None
866
954
self.stop_checker()
867
955
self.enabled = False
869
957
self.send_changedstate()
870
# Do not run this again if called by a gobject.timeout_add
958
# Do not run this again if called by a GLib.timeout_add
873
961
def __del__(self):
877
965
# Schedule a new checker to be started an 'interval' from now,
878
966
# and every interval from then on.
879
967
if self.checker_initiator_tag is not None:
880
gobject.source_remove(self.checker_initiator_tag)
881
self.checker_initiator_tag = gobject.timeout_add(
968
GLib.source_remove(self.checker_initiator_tag)
969
self.checker_initiator_tag = GLib.timeout_add(
882
970
int(self.interval.total_seconds() * 1000),
883
971
self.start_checker)
884
972
# Schedule a disable() when 'timeout' has passed
885
973
if self.disable_initiator_tag is not None:
886
gobject.source_remove(self.disable_initiator_tag)
887
self.disable_initiator_tag = gobject.timeout_add(
974
GLib.source_remove(self.disable_initiator_tag)
975
self.disable_initiator_tag = GLib.timeout_add(
888
976
int(self.timeout.total_seconds() * 1000), self.disable)
889
977
# Also start a new checker *right now*.
890
978
self.start_checker()
926
1014
if timeout is None:
927
1015
timeout = self.timeout
928
1016
if self.disable_initiator_tag is not None:
929
gobject.source_remove(self.disable_initiator_tag)
1017
GLib.source_remove(self.disable_initiator_tag)
930
1018
self.disable_initiator_tag = None
931
1019
if getattr(self, "enabled", False):
932
self.disable_initiator_tag = gobject.timeout_add(
1020
self.disable_initiator_tag = GLib.timeout_add(
933
1021
int(timeout.total_seconds() * 1000), self.disable)
934
1022
self.expires = datetime.datetime.utcnow() + timeout
990
1078
args = (pipe[1], subprocess.call, command),
991
1079
kwargs = popen_args)
992
1080
self.checker.start()
993
self.checker_callback_tag = gobject.io_add_watch(
994
pipe[0].fileno(), gobject.IO_IN,
1081
self.checker_callback_tag = GLib.io_add_watch(
1082
pipe[0].fileno(), GLib.IO_IN,
995
1083
self.checker_callback, pipe[0], command)
996
# Re-run this periodically if run by gobject.timeout_add
1084
# Re-run this periodically if run by GLib.timeout_add
999
1087
def stop_checker(self):
1000
1088
"""Force the checker process, if any, to stop."""
1001
1089
if self.checker_callback_tag:
1002
gobject.source_remove(self.checker_callback_tag)
1090
GLib.source_remove(self.checker_callback_tag)
1003
1091
self.checker_callback_tag = None
1004
1092
if getattr(self, "checker", None) is None:
1479
1567
interface_names.add(alt_interface)
1480
1568
# Is this a D-Bus signal?
1481
1569
if getattr(attribute, "_dbus_is_signal", False):
1570
# Extract the original non-method undecorated
1571
# function by black magic
1482
1572
if sys.version_info.major == 2:
1483
# Extract the original non-method undecorated
1484
# function by black magic
1485
1573
nonmethod_func = (dict(
1486
1574
zip(attribute.func_code.co_freevars,
1487
1575
attribute.__closure__))
1488
1576
["func"].cell_contents)
1490
nonmethod_func = attribute
1578
nonmethod_func = (dict(
1579
zip(attribute.__code__.co_freevars,
1580
attribute.__closure__))
1581
["func"].cell_contents)
1491
1582
# Create a new, but exactly alike, function
1492
1583
# object, and decorate it to be a new D-Bus signal
1493
1584
# with the alternate D-Bus interface name
1494
if sys.version_info.major == 2:
1495
new_function = types.FunctionType(
1496
nonmethod_func.func_code,
1497
nonmethod_func.func_globals,
1498
nonmethod_func.func_name,
1499
nonmethod_func.func_defaults,
1500
nonmethod_func.func_closure)
1502
new_function = types.FunctionType(
1503
nonmethod_func.__code__,
1504
nonmethod_func.__globals__,
1505
nonmethod_func.__name__,
1506
nonmethod_func.__defaults__,
1507
nonmethod_func.__closure__)
1585
new_function = copy_function(nonmethod_func)
1508
1586
new_function = (dbus.service.signal(
1510
1588
attribute._dbus_signature)(new_function))
1550
1628
attribute._dbus_in_signature,
1551
1629
attribute._dbus_out_signature)
1552
(types.FunctionType(attribute.func_code,
1553
attribute.func_globals,
1554
attribute.func_name,
1555
attribute.func_defaults,
1556
attribute.func_closure)))
1630
(copy_function(attribute)))
1557
1631
# Copy annotations, if any
1559
1633
attr[attrname]._dbus_annotations = dict(
1571
1645
attribute._dbus_access,
1572
1646
attribute._dbus_get_args_options
1573
1647
["byte_arrays"])
1574
(types.FunctionType(
1575
attribute.func_code,
1576
attribute.func_globals,
1577
attribute.func_name,
1578
attribute.func_defaults,
1579
attribute.func_closure)))
1648
(copy_function(attribute)))
1580
1649
# Copy annotations, if any
1582
1651
attr[attrname]._dbus_annotations = dict(
1591
1660
# to the class.
1592
1661
attr[attrname] = (
1593
1662
dbus_interface_annotations(alt_interface)
1594
(types.FunctionType(attribute.func_code,
1595
attribute.func_globals,
1596
attribute.func_name,
1597
attribute.func_defaults,
1598
attribute.func_closure)))
1663
(copy_function(attribute)))
1600
1665
# Deprecate all alternate interfaces
1601
1666
iname="_AlternateDBusNames_interface_annotation{}"
1614
1679
if interface_names:
1615
1680
# Replace the class with a new subclass of it with
1616
1681
# methods, signals, etc. as created above.
1617
cls = type(b"{}Alternate".format(cls.__name__),
1682
if sys.version_info.major == 2:
1683
cls = type(b"{}Alternate".format(cls.__name__),
1686
cls = type("{}Alternate".format(cls.__name__),
1780
1849
def approve(self, value=True):
1781
1850
self.approved = value
1782
gobject.timeout_add(int(self.approval_duration.total_seconds()
1783
* 1000), self._reset_approved)
1851
GLib.timeout_add(int(self.approval_duration.total_seconds()
1852
* 1000), self._reset_approved)
1784
1853
self.send_changedstate()
1786
1855
## D-Bus methods, signals & properties
1996
2065
if (getattr(self, "disable_initiator_tag", None)
1999
gobject.source_remove(self.disable_initiator_tag)
2000
self.disable_initiator_tag = gobject.timeout_add(
2068
GLib.source_remove(self.disable_initiator_tag)
2069
self.disable_initiator_tag = GLib.timeout_add(
2001
2070
int((self.expires - now).total_seconds() * 1000),
2024
2093
if self.enabled:
2025
2094
# Reschedule checker run
2026
gobject.source_remove(self.checker_initiator_tag)
2027
self.checker_initiator_tag = gobject.timeout_add(
2095
GLib.source_remove(self.checker_initiator_tag)
2096
self.checker_initiator_tag = GLib.timeout_add(
2028
2097
value, self.start_checker)
2029
2098
self.start_checker() # Start one now, too
2122
2191
priority = self.server.gnutls_priority
2123
2192
if priority is None:
2124
2193
priority = "NORMAL"
2125
gnutls.priority_set_direct(session._c_object, priority,
2194
gnutls.priority_set_direct(session._c_object,
2195
priority.encode("utf-8"),
2128
2198
# Start communication using the Mandos protocol
2216
2286
delay -= time2 - time
2219
while sent_size < len(client.secret):
2221
sent = session.send(client.secret[sent_size:])
2222
except gnutls.Error as error:
2223
logger.warning("gnutls send failed",
2226
logger.debug("Sent: %d, remaining: %d", sent,
2227
len(client.secret) - (sent_size
2289
session.send(client.secret)
2290
except gnutls.Error as error:
2291
logger.warning("gnutls send failed",
2231
2295
logger.info("Sending secret to %s", client.name)
2232
2296
# bump the timeout using extended_timeout
2389
2453
"""This overrides the normal server_bind() function
2390
2454
to bind to an interface if one was specified, and also NOT to
2391
2455
bind to an address or port if they were not specified."""
2456
global SO_BINDTODEVICE
2392
2457
if self.interface is not None:
2393
2458
if SO_BINDTODEVICE is None:
2394
logger.error("SO_BINDTODEVICE does not exist;"
2395
" cannot bind to interface %s",
2399
self.socket.setsockopt(
2400
socket.SOL_SOCKET, SO_BINDTODEVICE,
2401
(self.interface + "\0").encode("utf-8"))
2402
except socket.error as error:
2403
if error.errno == errno.EPERM:
2404
logger.error("No permission to bind to"
2405
" interface %s", self.interface)
2406
elif error.errno == errno.ENOPROTOOPT:
2407
logger.error("SO_BINDTODEVICE not available;"
2408
" cannot bind to interface %s",
2410
elif error.errno == errno.ENODEV:
2411
logger.error("Interface %s does not exist,"
2412
" cannot bind", self.interface)
2459
# Fall back to a hard-coded value which seems to be
2461
logger.warning("SO_BINDTODEVICE not found, trying 25")
2462
SO_BINDTODEVICE = 25
2464
self.socket.setsockopt(
2465
socket.SOL_SOCKET, SO_BINDTODEVICE,
2466
(self.interface + "\0").encode("utf-8"))
2467
except socket.error as error:
2468
if error.errno == errno.EPERM:
2469
logger.error("No permission to bind to"
2470
" interface %s", self.interface)
2471
elif error.errno == errno.ENOPROTOOPT:
2472
logger.error("SO_BINDTODEVICE not available;"
2473
" cannot bind to interface %s",
2475
elif error.errno == errno.ENODEV:
2476
logger.error("Interface %s does not exist,"
2477
" cannot bind", self.interface)
2415
2480
# Only bind(2) the socket if we really need to.
2416
2481
if self.server_address[0] or self.server_address[1]:
2417
2482
if not self.server_address[0]:
2440
2505
gnutls_priority GnuTLS priority string
2441
2506
use_dbus: Boolean; to emit D-Bus signals or not
2443
Assumes a gobject.MainLoop event loop.
2508
Assumes a GLib.MainLoop event loop.
2446
2511
def __init__(self, server_address, RequestHandlerClass,
2472
2537
def add_pipe(self, parent_pipe, proc):
2473
2538
# Call "handle_ipc" for both data and EOF events
2474
gobject.io_add_watch(
2475
2540
parent_pipe.fileno(),
2476
gobject.IO_IN | gobject.IO_HUP,
2541
GLib.IO_IN | GLib.IO_HUP,
2477
2542
functools.partial(self.handle_ipc,
2478
2543
parent_pipe = parent_pipe,
2510
2575
parent_pipe.send(False)
2513
gobject.io_add_watch(
2514
2579
parent_pipe.fileno(),
2515
gobject.IO_IN | gobject.IO_HUP,
2580
GLib.IO_IN | GLib.IO_HUP,
2516
2581
functools.partial(self.handle_ipc,
2517
2582
parent_pipe = parent_pipe,
2900
2965
logger.error("Could not open file %r", pidfilename,
2903
for name in ("_mandos", "mandos", "nobody"):
2968
for name, group in (("_mandos", "_mandos"),
2969
("mandos", "mandos"),
2970
("nobody", "nogroup")):
2905
2972
uid = pwd.getpwnam(name).pw_uid
2906
gid = pwd.getpwnam(name).pw_gid
2973
gid = pwd.getpwnam(group).pw_gid
2908
2975
except KeyError:
2984
logger.debug("Did setuid/setgid to {}:{}".format(uid,
2916
2986
except OSError as error:
2987
logger.warning("Failed to setuid/setgid to {}:{}: {}"
2988
.format(uid, gid, os.strerror(error.errno)))
2917
2989
if error.errno != errno.EPERM:
2941
3013
# Close all input and output, do double fork, etc.
2944
# multiprocessing will use threads, so before we use gobject we
2945
# need to inform gobject that threads will be used.
2946
gobject.threads_init()
3016
# multiprocessing will use threads, so before we use GLib we need
3017
# to inform GLib that threads will be used.
2948
3020
global main_loop
2949
3021
# From the Avahi example code
2950
3022
DBusGMainLoop(set_as_default=True)
2951
main_loop = gobject.MainLoop()
3023
main_loop = GLib.MainLoop()
2952
3024
bus = dbus.SystemBus()
2953
3025
# End of Avahi example code
2998
3070
if server_settings["restore"]:
3000
3072
with open(stored_state_path, "rb") as stored_state:
3001
clients_data, old_client_settings = pickle.load(
3073
if sys.version_info.major == 2:
3074
clients_data, old_client_settings = pickle.load(
3077
bytes_clients_data, bytes_old_client_settings = (
3078
pickle.load(stored_state, encoding = "bytes"))
3079
### Fix bytes to strings
3082
clients_data = { (key.decode("utf-8")
3083
if isinstance(key, bytes)
3086
bytes_clients_data.items() }
3087
del bytes_clients_data
3088
for key in clients_data:
3089
value = { (k.decode("utf-8")
3090
if isinstance(k, bytes) else k): v
3092
clients_data[key].items() }
3093
clients_data[key] = value
3095
value["client_structure"] = [
3097
if isinstance(s, bytes)
3099
value["client_structure"] ]
3101
for k in ("name", "host"):
3102
if isinstance(value[k], bytes):
3103
value[k] = value[k].decode("utf-8")
3104
## old_client_settings
3106
old_client_settings = {
3107
(key.decode("utf-8")
3108
if isinstance(key, bytes)
3111
bytes_old_client_settings.items() }
3112
del bytes_old_client_settings
3114
for value in old_client_settings.values():
3115
if isinstance(value["host"], bytes):
3116
value["host"] = (value["host"]
3003
3118
os.remove(stored_state_path)
3004
3119
except IOError as e:
3005
3120
if e.errno == errno.ENOENT:
3107
3222
del pidfilename
3109
signal.signal(signal.SIGHUP, lambda signum, frame: sys.exit())
3110
signal.signal(signal.SIGTERM, lambda signum, frame: sys.exit())
3224
for termsig in (signal.SIGHUP, signal.SIGTERM):
3225
GLib.unix_signal_add(GLib.PRIORITY_HIGH, termsig,
3226
lambda: main_loop.quit() and False)
3155
3271
return dbus.Dictionary(
3156
3272
{ c.dbus_object_path: c.GetAll(
3157
3273
"se.recompile.Mandos.Client")
3158
for c in tcp_server.clients.itervalues() },
3274
for c in tcp_server.clients.values() },
3159
3275
signature="oa{sv}")
3161
3277
@dbus.service.method(_interface, in_signature="o")
3162
3278
def RemoveClient(self, object_path):
3164
for c in tcp_server.clients.itervalues():
3280
for c in tcp_server.clients.values():
3165
3281
if c.dbus_object_path == object_path:
3166
3282
del tcp_server.clients[c.name]
3167
3283
c.remove_from_connection()
3213
3329
mandos_dbus_service = MandosDBusService()
3331
# Save modules to variables to exempt the modules from being
3332
# unloaded before the function registered with atexit() is run.
3333
mp = multiprocessing
3216
3336
"Cleanup function; run on exit"
3218
3338
service.cleanup()
3220
multiprocessing.active_children()
3340
mp.active_children()
3222
3342
if not (tcp_server.clients or client_settings):
3227
3347
# removed/edited, old secret will thus be unrecovable.
3229
3349
with PGPEngine() as pgp:
3230
for client in tcp_server.clients.itervalues():
3350
for client in tcp_server.clients.values():
3231
3351
key = client_settings[client.name]["secret"]
3232
3352
client.encrypted_secret = pgp.encrypt(client.secret,
3257
3377
prefix='clients-',
3258
3378
dir=os.path.dirname(stored_state_path),
3259
3379
delete=False) as stored_state:
3260
pickle.dump((clients, client_settings), stored_state)
3380
pickle.dump((clients, client_settings), stored_state,
3261
3382
tempname = stored_state.name
3262
3383
os.rename(tempname, stored_state_path)
3263
3384
except (IOError, OSError) as e:
3324
3445
# End of Avahi example code
3326
gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN,
3327
lambda *args, **kwargs:
3328
(tcp_server.handle_request
3329
(*args[2:], **kwargs) or True))
3447
GLib.io_add_watch(tcp_server.fileno(), GLib.IO_IN,
3448
lambda *args, **kwargs:
3449
(tcp_server.handle_request
3450
(*args[2:], **kwargs) or True))
3331
3452
logger.debug("Starting main loop")
3332
3453
main_loop.run()