/mandos/trunk

To get this branch, use:
bzr branch http://bzr.recompile.se/loggerhead/mandos/trunk

« back to all changes in this revision

Viewing changes to mandos

  • Committer: Teddy Hogeborn
  • Date: 2016-03-12 20:23:15 UTC
  • Revision ID: teddy@recompile.se-20160312202315-hu7b87ivetlxqbw3
Server: Fix minor thing with Python 3 compatibility

Fix another small thing with unpickling string values.

* mandos (main): When restoring pickled client data, only decode byte
                 string for "host" key if it really is a byte string.

Show diffs side-by-side

added added

removed removed

Lines of Context:
34
34
from __future__ import (division, absolute_import, print_function,
35
35
                        unicode_literals)
36
36
 
37
 
from future_builtins import *
 
37
try:
 
38
    from future_builtins import *
 
39
except ImportError:
 
40
    pass
38
41
 
39
42
try:
40
43
    import SocketServer as socketserver
77
80
import dbus
78
81
import dbus.service
79
82
try:
80
 
    import gobject
 
83
    from gi.repository import GObject
81
84
except ImportError:
82
 
    from gi.repository import GObject as gobject
83
 
import avahi
 
85
    import gobject as GObject
84
86
from dbus.mainloop.glib import DBusGMainLoop
85
87
import ctypes
86
88
import ctypes.util
98
100
if sys.version_info.major == 2:
99
101
    str = unicode
100
102
 
101
 
version = "1.7.2"
 
103
version = "1.7.5"
102
104
stored_state_file = "clients.pickle"
103
105
 
104
106
logger = logging.getLogger()
119
121
        return interface_index
120
122
 
121
123
 
 
124
def copy_function(func):
 
125
    """Make a copy of a function"""
 
126
    if sys.version_info.major == 2:
 
127
        return types.FunctionType(func.func_code,
 
128
                                  func.func_globals,
 
129
                                  func.func_name,
 
130
                                  func.func_defaults,
 
131
                                  func.func_closure)
 
132
    else:
 
133
        return types.FunctionType(func.__code__,
 
134
                                  func.__globals__,
 
135
                                  func.__name__,
 
136
                                  func.__defaults__,
 
137
                                  func.__closure__)
 
138
 
 
139
 
122
140
def initlogger(debug, level=logging.WARNING):
123
141
    """init logger and add loglevel"""
124
142
    
155
173
        try:
156
174
            output = subprocess.check_output(["gpgconf"])
157
175
            for line in output.splitlines():
158
 
                name, text, path = line.split(":")
 
176
                name, text, path = line.split(b":")
159
177
                if name == "gpg":
160
178
                    self.gpg = path
161
179
                    break
238
256
            raise PGPError(err)
239
257
        return decrypted_plaintext
240
258
 
 
259
# Pretend that we have an Avahi module
 
260
class Avahi(object):
 
261
    """This isn't so much a class as it is a module-like namespace.
 
262
    It is instantiated once, and simulates having an Avahi module."""
 
263
    IF_UNSPEC = -1              # avahi-common/address.h
 
264
    PROTO_UNSPEC = -1           # avahi-common/address.h
 
265
    PROTO_INET = 0              # avahi-common/address.h
 
266
    PROTO_INET6 = 1             # avahi-common/address.h
 
267
    DBUS_NAME = "org.freedesktop.Avahi"
 
268
    DBUS_INTERFACE_ENTRY_GROUP = DBUS_NAME + ".EntryGroup"
 
269
    DBUS_INTERFACE_SERVER = DBUS_NAME + ".Server"
 
270
    DBUS_PATH_SERVER = "/"
 
271
    def string_array_to_txt_array(self, t):
 
272
        return dbus.Array((dbus.ByteArray(s.encode("utf-8"))
 
273
                           for s in t), signature="ay")
 
274
    ENTRY_GROUP_ESTABLISHED = 2 # avahi-common/defs.h
 
275
    ENTRY_GROUP_COLLISION = 3   # avahi-common/defs.h
 
276
    ENTRY_GROUP_FAILURE = 4     # avahi-common/defs.h
 
277
    SERVER_INVALID = 0          # avahi-common/defs.h
 
278
    SERVER_REGISTERING = 1      # avahi-common/defs.h
 
279
    SERVER_RUNNING = 2          # avahi-common/defs.h
 
280
    SERVER_COLLISION = 3        # avahi-common/defs.h
 
281
    SERVER_FAILURE = 4          # avahi-common/defs.h
 
282
avahi = Avahi()
241
283
 
242
284
class AvahiError(Exception):
243
285
    def __init__(self, value, *args, **kwargs):
447
489
    
448
490
    _library = ctypes.cdll.LoadLibrary(
449
491
        ctypes.util.find_library("gnutls"))
450
 
    _need_version = "3.3.0"
 
492
    _need_version = b"3.3.0"
451
493
    def __init__(self):
452
494
        # Need to use class name "GnuTLS" here, since this method is
453
495
        # called before the assignment to the "gnutls" global variable
487
529
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
488
530
    openpgp_crt_fmt_t = ctypes.c_int # gnutls/openpgp.h
489
531
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
490
 
    credentials_type_t = ctypes.c_int # 
 
532
    credentials_type_t = ctypes.c_int
491
533
    transport_ptr_t = ctypes.c_void_p
492
534
    close_request_t = ctypes.c_int
493
535
    
715
757
    checker:    subprocess.Popen(); a running checker process used
716
758
                                    to see if the client lives.
717
759
                                    'None' if no process is running.
718
 
    checker_callback_tag: a gobject event source tag, or None
 
760
    checker_callback_tag: a GObject event source tag, or None
719
761
    checker_command: string; External command which is run to check
720
762
                     if client lives.  %() expansions are done at
721
763
                     runtime with vars(self) as dict, so that for
722
764
                     instance %(name)s can be used in the command.
723
 
    checker_initiator_tag: a gobject event source tag, or None
 
765
    checker_initiator_tag: a GObject event source tag, or None
724
766
    created:    datetime.datetime(); (UTC) object creation
725
767
    client_structure: Object describing what attributes a client has
726
768
                      and is used for storing the client at exit
727
769
    current_checker_command: string; current running checker_command
728
 
    disable_initiator_tag: a gobject event source tag, or None
 
770
    disable_initiator_tag: a GObject event source tag, or None
729
771
    enabled:    bool()
730
772
    fingerprint: string (40 or 32 hexadecimal digits); used to
731
773
                 uniquely identify the client
794
836
            client["fingerprint"] = (section["fingerprint"].upper()
795
837
                                     .replace(" ", ""))
796
838
            if "secret" in section:
797
 
                client["secret"] = section["secret"].decode("base64")
 
839
                client["secret"] = codecs.decode(section["secret"]
 
840
                                                 .encode("utf-8"),
 
841
                                                 "base64")
798
842
            elif "secfile" in section:
799
843
                with open(os.path.expanduser(os.path.expandvars
800
844
                                             (section["secfile"])),
853
897
        self.changedstate = multiprocessing_manager.Condition(
854
898
            multiprocessing_manager.Lock())
855
899
        self.client_structure = [attr
856
 
                                 for attr in self.__dict__.iterkeys()
 
900
                                 for attr in self.__dict__.keys()
857
901
                                 if not attr.startswith("_")]
858
902
        self.client_structure.append("client_structure")
859
903
        
885
929
        if not quiet:
886
930
            logger.info("Disabling client %s", self.name)
887
931
        if getattr(self, "disable_initiator_tag", None) is not None:
888
 
            gobject.source_remove(self.disable_initiator_tag)
 
932
            GObject.source_remove(self.disable_initiator_tag)
889
933
            self.disable_initiator_tag = None
890
934
        self.expires = None
891
935
        if getattr(self, "checker_initiator_tag", None) is not None:
892
 
            gobject.source_remove(self.checker_initiator_tag)
 
936
            GObject.source_remove(self.checker_initiator_tag)
893
937
            self.checker_initiator_tag = None
894
938
        self.stop_checker()
895
939
        self.enabled = False
896
940
        if not quiet:
897
941
            self.send_changedstate()
898
 
        # Do not run this again if called by a gobject.timeout_add
 
942
        # Do not run this again if called by a GObject.timeout_add
899
943
        return False
900
944
    
901
945
    def __del__(self):
905
949
        # Schedule a new checker to be started an 'interval' from now,
906
950
        # and every interval from then on.
907
951
        if self.checker_initiator_tag is not None:
908
 
            gobject.source_remove(self.checker_initiator_tag)
909
 
        self.checker_initiator_tag = gobject.timeout_add(
 
952
            GObject.source_remove(self.checker_initiator_tag)
 
953
        self.checker_initiator_tag = GObject.timeout_add(
910
954
            int(self.interval.total_seconds() * 1000),
911
955
            self.start_checker)
912
956
        # Schedule a disable() when 'timeout' has passed
913
957
        if self.disable_initiator_tag is not None:
914
 
            gobject.source_remove(self.disable_initiator_tag)
915
 
        self.disable_initiator_tag = gobject.timeout_add(
 
958
            GObject.source_remove(self.disable_initiator_tag)
 
959
        self.disable_initiator_tag = GObject.timeout_add(
916
960
            int(self.timeout.total_seconds() * 1000), self.disable)
917
961
        # Also start a new checker *right now*.
918
962
        self.start_checker()
954
998
        if timeout is None:
955
999
            timeout = self.timeout
956
1000
        if self.disable_initiator_tag is not None:
957
 
            gobject.source_remove(self.disable_initiator_tag)
 
1001
            GObject.source_remove(self.disable_initiator_tag)
958
1002
            self.disable_initiator_tag = None
959
1003
        if getattr(self, "enabled", False):
960
 
            self.disable_initiator_tag = gobject.timeout_add(
 
1004
            self.disable_initiator_tag = GObject.timeout_add(
961
1005
                int(timeout.total_seconds() * 1000), self.disable)
962
1006
            self.expires = datetime.datetime.utcnow() + timeout
963
1007
    
1018
1062
                args = (pipe[1], subprocess.call, command),
1019
1063
                kwargs = popen_args)
1020
1064
            self.checker.start()
1021
 
            self.checker_callback_tag = gobject.io_add_watch(
1022
 
                pipe[0].fileno(), gobject.IO_IN,
 
1065
            self.checker_callback_tag = GObject.io_add_watch(
 
1066
                pipe[0].fileno(), GObject.IO_IN,
1023
1067
                self.checker_callback, pipe[0], command)
1024
 
        # Re-run this periodically if run by gobject.timeout_add
 
1068
        # Re-run this periodically if run by GObject.timeout_add
1025
1069
        return True
1026
1070
    
1027
1071
    def stop_checker(self):
1028
1072
        """Force the checker process, if any, to stop."""
1029
1073
        if self.checker_callback_tag:
1030
 
            gobject.source_remove(self.checker_callback_tag)
 
1074
            GObject.source_remove(self.checker_callback_tag)
1031
1075
            self.checker_callback_tag = None
1032
1076
        if getattr(self, "checker", None) is None:
1033
1077
            return
1507
1551
                interface_names.add(alt_interface)
1508
1552
                # Is this a D-Bus signal?
1509
1553
                if getattr(attribute, "_dbus_is_signal", False):
 
1554
                    # Extract the original non-method undecorated
 
1555
                    # function by black magic
1510
1556
                    if sys.version_info.major == 2:
1511
 
                        # Extract the original non-method undecorated
1512
 
                        # function by black magic
1513
1557
                        nonmethod_func = (dict(
1514
1558
                            zip(attribute.func_code.co_freevars,
1515
1559
                                attribute.__closure__))
1516
1560
                                          ["func"].cell_contents)
1517
1561
                    else:
1518
 
                        nonmethod_func = attribute
 
1562
                        nonmethod_func = (dict(
 
1563
                            zip(attribute.__code__.co_freevars,
 
1564
                                attribute.__closure__))
 
1565
                                          ["func"].cell_contents)
1519
1566
                    # Create a new, but exactly alike, function
1520
1567
                    # object, and decorate it to be a new D-Bus signal
1521
1568
                    # with the alternate D-Bus interface name
1522
 
                    if sys.version_info.major == 2:
1523
 
                        new_function = types.FunctionType(
1524
 
                            nonmethod_func.func_code,
1525
 
                            nonmethod_func.func_globals,
1526
 
                            nonmethod_func.func_name,
1527
 
                            nonmethod_func.func_defaults,
1528
 
                            nonmethod_func.func_closure)
1529
 
                    else:
1530
 
                        new_function = types.FunctionType(
1531
 
                            nonmethod_func.__code__,
1532
 
                            nonmethod_func.__globals__,
1533
 
                            nonmethod_func.__name__,
1534
 
                            nonmethod_func.__defaults__,
1535
 
                            nonmethod_func.__closure__)
 
1569
                    new_function = copy_function(nonmethod_func)
1536
1570
                    new_function = (dbus.service.signal(
1537
1571
                        alt_interface,
1538
1572
                        attribute._dbus_signature)(new_function))
1577
1611
                            alt_interface,
1578
1612
                            attribute._dbus_in_signature,
1579
1613
                            attribute._dbus_out_signature)
1580
 
                        (types.FunctionType(attribute.func_code,
1581
 
                                            attribute.func_globals,
1582
 
                                            attribute.func_name,
1583
 
                                            attribute.func_defaults,
1584
 
                                            attribute.func_closure)))
 
1614
                        (copy_function(attribute)))
1585
1615
                    # Copy annotations, if any
1586
1616
                    try:
1587
1617
                        attr[attrname]._dbus_annotations = dict(
1599
1629
                        attribute._dbus_access,
1600
1630
                        attribute._dbus_get_args_options
1601
1631
                        ["byte_arrays"])
1602
 
                                      (types.FunctionType(
1603
 
                                          attribute.func_code,
1604
 
                                          attribute.func_globals,
1605
 
                                          attribute.func_name,
1606
 
                                          attribute.func_defaults,
1607
 
                                          attribute.func_closure)))
 
1632
                                      (copy_function(attribute)))
1608
1633
                    # Copy annotations, if any
1609
1634
                    try:
1610
1635
                        attr[attrname]._dbus_annotations = dict(
1619
1644
                    # to the class.
1620
1645
                    attr[attrname] = (
1621
1646
                        dbus_interface_annotations(alt_interface)
1622
 
                        (types.FunctionType(attribute.func_code,
1623
 
                                            attribute.func_globals,
1624
 
                                            attribute.func_name,
1625
 
                                            attribute.func_defaults,
1626
 
                                            attribute.func_closure)))
 
1647
                        (copy_function(attribute)))
1627
1648
            if deprecate:
1628
1649
                # Deprecate all alternate interfaces
1629
1650
                iname="_AlternateDBusNames_interface_annotation{}"
1642
1663
            if interface_names:
1643
1664
                # Replace the class with a new subclass of it with
1644
1665
                # methods, signals, etc. as created above.
1645
 
                cls = type(b"{}Alternate".format(cls.__name__),
1646
 
                           (cls, ), attr)
 
1666
                if sys.version_info.major == 2:
 
1667
                    cls = type(b"{}Alternate".format(cls.__name__),
 
1668
                               (cls, ), attr)
 
1669
                else:
 
1670
                    cls = type("{}Alternate".format(cls.__name__),
 
1671
                               (cls, ), attr)
1647
1672
        return cls
1648
1673
    
1649
1674
    return wrapper
1807
1832
    
1808
1833
    def approve(self, value=True):
1809
1834
        self.approved = value
1810
 
        gobject.timeout_add(int(self.approval_duration.total_seconds()
 
1835
        GObject.timeout_add(int(self.approval_duration.total_seconds()
1811
1836
                                * 1000), self._reset_approved)
1812
1837
        self.send_changedstate()
1813
1838
    
2024
2049
                if (getattr(self, "disable_initiator_tag", None)
2025
2050
                    is None):
2026
2051
                    return
2027
 
                gobject.source_remove(self.disable_initiator_tag)
2028
 
                self.disable_initiator_tag = gobject.timeout_add(
 
2052
                GObject.source_remove(self.disable_initiator_tag)
 
2053
                self.disable_initiator_tag = GObject.timeout_add(
2029
2054
                    int((self.expires - now).total_seconds() * 1000),
2030
2055
                    self.disable)
2031
2056
    
2051
2076
            return
2052
2077
        if self.enabled:
2053
2078
            # Reschedule checker run
2054
 
            gobject.source_remove(self.checker_initiator_tag)
2055
 
            self.checker_initiator_tag = gobject.timeout_add(
 
2079
            GObject.source_remove(self.checker_initiator_tag)
 
2080
            self.checker_initiator_tag = GObject.timeout_add(
2056
2081
                value, self.start_checker)
2057
2082
            self.start_checker() # Start one now, too
2058
2083
    
2462
2487
        gnutls_priority GnuTLS priority string
2463
2488
        use_dbus:       Boolean; to emit D-Bus signals or not
2464
2489
    
2465
 
    Assumes a gobject.MainLoop event loop.
 
2490
    Assumes a GObject.MainLoop event loop.
2466
2491
    """
2467
2492
    
2468
2493
    def __init__(self, server_address, RequestHandlerClass,
2493
2518
    
2494
2519
    def add_pipe(self, parent_pipe, proc):
2495
2520
        # Call "handle_ipc" for both data and EOF events
2496
 
        gobject.io_add_watch(
 
2521
        GObject.io_add_watch(
2497
2522
            parent_pipe.fileno(),
2498
 
            gobject.IO_IN | gobject.IO_HUP,
 
2523
            GObject.IO_IN | GObject.IO_HUP,
2499
2524
            functools.partial(self.handle_ipc,
2500
2525
                              parent_pipe = parent_pipe,
2501
2526
                              proc = proc))
2505
2530
                   proc = None,
2506
2531
                   client_object=None):
2507
2532
        # error, or the other end of multiprocessing.Pipe has closed
2508
 
        if condition & (gobject.IO_ERR | gobject.IO_HUP):
 
2533
        if condition & (GObject.IO_ERR | GObject.IO_HUP):
2509
2534
            # Wait for other process to exit
2510
2535
            proc.join()
2511
2536
            return False
2518
2543
            fpr = request[1]
2519
2544
            address = request[2]
2520
2545
            
2521
 
            for c in self.clients.itervalues():
 
2546
            for c in self.clients.values():
2522
2547
                if c.fingerprint == fpr:
2523
2548
                    client = c
2524
2549
                    break
2532
2557
                parent_pipe.send(False)
2533
2558
                return False
2534
2559
            
2535
 
            gobject.io_add_watch(
 
2560
            GObject.io_add_watch(
2536
2561
                parent_pipe.fileno(),
2537
 
                gobject.IO_IN | gobject.IO_HUP,
 
2562
                GObject.IO_IN | GObject.IO_HUP,
2538
2563
                functools.partial(self.handle_ipc,
2539
2564
                                  parent_pipe = parent_pipe,
2540
2565
                                  proc = proc,
2922
2947
            logger.error("Could not open file %r", pidfilename,
2923
2948
                         exc_info=e)
2924
2949
    
2925
 
    for name in ("_mandos", "mandos", "nobody"):
 
2950
    for name, group in (("_mandos", "_mandos"),
 
2951
                        ("mandos", "mandos"),
 
2952
                        ("nobody", "nogroup")):
2926
2953
        try:
2927
2954
            uid = pwd.getpwnam(name).pw_uid
2928
 
            gid = pwd.getpwnam(name).pw_gid
 
2955
            gid = pwd.getpwnam(group).pw_gid
2929
2956
            break
2930
2957
        except KeyError:
2931
2958
            continue
2935
2962
    try:
2936
2963
        os.setgid(gid)
2937
2964
        os.setuid(uid)
 
2965
        if debug:
 
2966
            logger.debug("Did setuid/setgid to {}:{}".format(uid,
 
2967
                                                             gid))
2938
2968
    except OSError as error:
 
2969
        logger.warning("Failed to setuid/setgid to {}:{}: {}"
 
2970
                       .format(uid, gid, os.strerror(error.errno)))
2939
2971
        if error.errno != errno.EPERM:
2940
2972
            raise
2941
2973
    
2963
2995
        # Close all input and output, do double fork, etc.
2964
2996
        daemon()
2965
2997
    
2966
 
    # multiprocessing will use threads, so before we use gobject we
2967
 
    # need to inform gobject that threads will be used.
2968
 
    gobject.threads_init()
 
2998
    # multiprocessing will use threads, so before we use GObject we
 
2999
    # need to inform GObject that threads will be used.
 
3000
    GObject.threads_init()
2969
3001
    
2970
3002
    global main_loop
2971
3003
    # From the Avahi example code
2972
3004
    DBusGMainLoop(set_as_default=True)
2973
 
    main_loop = gobject.MainLoop()
 
3005
    main_loop = GObject.MainLoop()
2974
3006
    bus = dbus.SystemBus()
2975
3007
    # End of Avahi example code
2976
3008
    if use_dbus:
3020
3052
    if server_settings["restore"]:
3021
3053
        try:
3022
3054
            with open(stored_state_path, "rb") as stored_state:
3023
 
                clients_data, old_client_settings = pickle.load(
3024
 
                    stored_state)
 
3055
                if sys.version_info.major == 2:                
 
3056
                    clients_data, old_client_settings = pickle.load(
 
3057
                        stored_state)
 
3058
                else:
 
3059
                    bytes_clients_data, bytes_old_client_settings = (
 
3060
                        pickle.load(stored_state, encoding = "bytes"))
 
3061
                    ### Fix bytes to strings
 
3062
                    ## clients_data
 
3063
                    # .keys()
 
3064
                    clients_data = { (key.decode("utf-8")
 
3065
                                      if isinstance(key, bytes)
 
3066
                                      else key): value
 
3067
                                     for key, value in
 
3068
                                     bytes_clients_data.items() }
 
3069
                    del bytes_clients_data
 
3070
                    for key in clients_data:
 
3071
                        value = { (k.decode("utf-8")
 
3072
                                   if isinstance(k, bytes) else k): v
 
3073
                                  for k, v in
 
3074
                                  clients_data[key].items() }
 
3075
                        clients_data[key] = value
 
3076
                        # .client_structure
 
3077
                        value["client_structure"] = [
 
3078
                            (s.decode("utf-8")
 
3079
                             if isinstance(s, bytes)
 
3080
                             else s) for s in
 
3081
                            value["client_structure"] ]
 
3082
                        # .name & .host
 
3083
                        for k in ("name", "host"):
 
3084
                            if isinstance(value[k], bytes):
 
3085
                                value[k] = value[k].decode("utf-8")
 
3086
                    ## old_client_settings
 
3087
                    # .keys()
 
3088
                    old_client_settings = {
 
3089
                        (key.decode("utf-8")
 
3090
                         if isinstance(key, bytes)
 
3091
                         else key): value
 
3092
                        for key, value in
 
3093
                        bytes_old_client_settings.items() }
 
3094
                    del bytes_old_client_settings
 
3095
                    # .host
 
3096
                    for value in old_client_settings.values():
 
3097
                        if isinstance(value["host"], bytes):
 
3098
                            value["host"] = (value["host"]
 
3099
                                             .decode("utf-8"))
3025
3100
            os.remove(stored_state_path)
3026
3101
        except IOError as e:
3027
3102
            if e.errno == errno.ENOENT:
3166
3241
            def GetAllClients(self):
3167
3242
                "D-Bus method"
3168
3243
                return dbus.Array(c.dbus_object_path for c in
3169
 
                                  tcp_server.clients.itervalues())
 
3244
                                  tcp_server.clients.values())
3170
3245
            
3171
3246
            @dbus_annotations({"org.freedesktop.DBus.Deprecated":
3172
3247
                               "true"})
3177
3252
                return dbus.Dictionary(
3178
3253
                    { c.dbus_object_path: c.GetAll(
3179
3254
                        "se.recompile.Mandos.Client")
3180
 
                      for c in tcp_server.clients.itervalues() },
 
3255
                      for c in tcp_server.clients.values() },
3181
3256
                    signature="oa{sv}")
3182
3257
            
3183
3258
            @dbus.service.method(_interface, in_signature="o")
3184
3259
            def RemoveClient(self, object_path):
3185
3260
                "D-Bus method"
3186
 
                for c in tcp_server.clients.itervalues():
 
3261
                for c in tcp_server.clients.values():
3187
3262
                    if c.dbus_object_path == object_path:
3188
3263
                        del tcp_server.clients[c.name]
3189
3264
                        c.remove_from_connection()
3249
3324
        # removed/edited, old secret will thus be unrecovable.
3250
3325
        clients = {}
3251
3326
        with PGPEngine() as pgp:
3252
 
            for client in tcp_server.clients.itervalues():
 
3327
            for client in tcp_server.clients.values():
3253
3328
                key = client_settings[client.name]["secret"]
3254
3329
                client.encrypted_secret = pgp.encrypt(client.secret,
3255
3330
                                                      key)
3279
3354
                    prefix='clients-',
3280
3355
                    dir=os.path.dirname(stored_state_path),
3281
3356
                    delete=False) as stored_state:
3282
 
                pickle.dump((clients, client_settings), stored_state)
 
3357
                pickle.dump((clients, client_settings), stored_state,
 
3358
                            protocol = 2)
3283
3359
                tempname = stored_state.name
3284
3360
            os.rename(tempname, stored_state_path)
3285
3361
        except (IOError, OSError) as e:
3310
3386
    
3311
3387
    atexit.register(cleanup)
3312
3388
    
3313
 
    for client in tcp_server.clients.itervalues():
 
3389
    for client in tcp_server.clients.values():
3314
3390
        if use_dbus:
3315
3391
            # Emit D-Bus signal for adding
3316
3392
            mandos_dbus_service.client_added_signal(client)
3345
3421
                sys.exit(1)
3346
3422
            # End of Avahi example code
3347
3423
        
3348
 
        gobject.io_add_watch(tcp_server.fileno(), gobject.IO_IN,
 
3424
        GObject.io_add_watch(tcp_server.fileno(), GObject.IO_IN,
3349
3425
                             lambda *args, **kwargs:
3350
3426
                             (tcp_server.handle_request
3351
3427
                              (*args[2:], **kwargs) or True))