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