/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: 2019-08-24 15:33:58 UTC
  • Revision ID: teddy@recompile.se-20190824153358-o69zprg8yiub1t0d
mandos-monitor: Use new GLib.io_add_watch() call signature

* mandos-monitor: When calling GLib.io_add_watch(), always pass a
                  channel as the first argument instead of a file
                  descriptor, and pass priority as the second
                  argument.  This is supported by PyGObject 3.8 or
                  later.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python3 -bI
 
1
#!/usr/bin/python
2
2
# -*- mode: python; after-save-hook: (lambda () (let ((command (if (fboundp 'file-local-name) (file-local-name (buffer-file-name)) (or (file-remote-p (buffer-file-name) 'localname) (buffer-file-name))))) (if (= (progn (if (get-buffer "*Test*") (kill-buffer "*Test*")) (process-file-shell-command (format "%s --check" (shell-quote-argument command)) nil "*Test*")) 0) (let ((w (get-buffer-window "*Test*"))) (if w (delete-window w))) (progn (with-current-buffer "*Test*" (compilation-mode)) (display-buffer "*Test*" '(display-buffer-in-side-window)))))); coding: utf-8 -*-
3
3
#
4
4
# Mandos server - give out binary blobs to connecting clients.
78
78
import collections
79
79
import codecs
80
80
import unittest
81
 
import random
82
 
import shlex
83
81
 
84
82
import dbus
85
83
import dbus.service
93
91
 
94
92
if sys.version_info.major == 2:
95
93
    __metaclass__ = type
96
 
    str = unicode
97
 
 
98
 
# Add collections.abc.Callable if it does not exist
99
 
try:
100
 
    collections.abc.Callable
101
 
except AttributeError:
102
 
    class abc:
103
 
        Callable = collections.Callable
104
 
    collections.abc = abc
105
 
    del abc
106
 
 
107
 
# Add shlex.quote if it does not exist
108
 
try:
109
 
    shlex.quote
110
 
except AttributeError:
111
 
    shlex.quote = re.escape
112
94
 
113
95
# Show warnings by default
114
96
if not sys.warnoptions:
140
122
            # No value found
141
123
            SO_BINDTODEVICE = None
142
124
 
 
125
if sys.version_info.major == 2:
 
126
    str = unicode
 
127
 
143
128
if sys.version_info < (3, 2):
144
129
    configparser.Configparser = configparser.SafeConfigParser
145
130
 
146
 
version = "1.8.9"
 
131
version = "1.8.8"
147
132
stored_state_file = "clients.pickle"
148
133
 
149
134
logger = logging.getLogger()
218
203
            output = subprocess.check_output(["gpgconf"])
219
204
            for line in output.splitlines():
220
205
                name, text, path = line.split(b":")
221
 
                if name == b"gpg":
 
206
                if name == "gpg":
222
207
                    self.gpg = path
223
208
                    break
224
209
        except OSError as e:
229
214
                          '--force-mdc',
230
215
                          '--quiet']
231
216
        # Only GPG version 1 has the --no-use-agent option.
232
 
        if self.gpg == b"gpg" or self.gpg.endswith(b"/gpg"):
 
217
        if self.gpg == "gpg" or self.gpg.endswith("/gpg"):
233
218
            self.gnupgargs.append("--no-use-agent")
234
219
 
235
220
    def __enter__(self):
1052
1037
        if self.checker_initiator_tag is not None:
1053
1038
            GLib.source_remove(self.checker_initiator_tag)
1054
1039
        self.checker_initiator_tag = GLib.timeout_add(
1055
 
            random.randrange(int(self.interval.total_seconds() * 1000
1056
 
                                 + 1)),
 
1040
            int(self.interval.total_seconds() * 1000),
1057
1041
            self.start_checker)
1058
1042
        # Schedule a disable() when 'timeout' has passed
1059
1043
        if self.disable_initiator_tag is not None:
1069
1053
        # Read return code from connection (see call_pipe)
1070
1054
        returncode = connection.recv()
1071
1055
        connection.close()
1072
 
        if self.checker is not None:
1073
 
            self.checker.join()
 
1056
        self.checker.join()
1074
1057
        self.checker_callback_tag = None
1075
1058
        self.checker = None
1076
1059
 
1134
1117
        if self.checker is None:
1135
1118
            # Escape attributes for the shell
1136
1119
            escaped_attrs = {
1137
 
                attr: shlex.quote(str(getattr(self, attr)))
 
1120
                attr: re.escape(str(getattr(self, attr)))
1138
1121
                for attr in self.runtime_expansions}
1139
1122
            try:
1140
1123
                command = self.checker_command % escaped_attrs
1429
1412
                raise ValueError("Byte arrays not supported for non-"
1430
1413
                                 "'ay' signature {!r}"
1431
1414
                                 .format(prop._dbus_signature))
1432
 
            value = dbus.ByteArray(bytes(value))
 
1415
            value = dbus.ByteArray(b''.join(chr(byte)
 
1416
                                            for byte in value))
1433
1417
        prop(value)
1434
1418
 
1435
1419
    @dbus.service.method(dbus.PROPERTIES_IFACE,
2764
2748
        if command == 'getattr':
2765
2749
            attrname = request[1]
2766
2750
            if isinstance(client_object.__getattribute__(attrname),
2767
 
                          collections.abc.Callable):
 
2751
                          collections.Callable):
2768
2752
                parent_pipe.send(('function', ))
2769
2753
            else:
2770
2754
                parent_pipe.send((
2781
2765
def rfc3339_duration_to_delta(duration):
2782
2766
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2783
2767
 
2784
 
    >>> rfc3339_duration_to_delta("P7D") == datetime.timedelta(7)
2785
 
    True
2786
 
    >>> rfc3339_duration_to_delta("PT60S") == datetime.timedelta(0, 60)
2787
 
    True
2788
 
    >>> rfc3339_duration_to_delta("PT60M") == datetime.timedelta(0, 3600)
2789
 
    True
2790
 
    >>> rfc3339_duration_to_delta("PT24H") == datetime.timedelta(1)
2791
 
    True
2792
 
    >>> rfc3339_duration_to_delta("P1W") == datetime.timedelta(7)
2793
 
    True
2794
 
    >>> rfc3339_duration_to_delta("PT5M30S") == datetime.timedelta(0, 330)
2795
 
    True
2796
 
    >>> rfc3339_duration_to_delta("P1DT3M20S") == datetime.timedelta(1, 200)
2797
 
    True
 
2768
    >>> rfc3339_duration_to_delta("P7D")
 
2769
    datetime.timedelta(7)
 
2770
    >>> rfc3339_duration_to_delta("PT60S")
 
2771
    datetime.timedelta(0, 60)
 
2772
    >>> rfc3339_duration_to_delta("PT60M")
 
2773
    datetime.timedelta(0, 3600)
 
2774
    >>> rfc3339_duration_to_delta("PT24H")
 
2775
    datetime.timedelta(1)
 
2776
    >>> rfc3339_duration_to_delta("P1W")
 
2777
    datetime.timedelta(7)
 
2778
    >>> rfc3339_duration_to_delta("PT5M30S")
 
2779
    datetime.timedelta(0, 330)
 
2780
    >>> rfc3339_duration_to_delta("P1DT3M20S")
 
2781
    datetime.timedelta(1, 200)
2798
2782
    """
2799
2783
 
2800
2784
    # Parsing an RFC 3339 duration with regular expressions is not
2880
2864
def string_to_delta(interval):
2881
2865
    """Parse a string and return a datetime.timedelta
2882
2866
 
2883
 
    >>> string_to_delta('7d') == datetime.timedelta(7)
2884
 
    True
2885
 
    >>> string_to_delta('60s') == datetime.timedelta(0, 60)
2886
 
    True
2887
 
    >>> string_to_delta('60m') == datetime.timedelta(0, 3600)
2888
 
    True
2889
 
    >>> string_to_delta('24h') == datetime.timedelta(1)
2890
 
    True
2891
 
    >>> string_to_delta('1w') == datetime.timedelta(7)
2892
 
    True
2893
 
    >>> string_to_delta('5m 30s') == datetime.timedelta(0, 330)
2894
 
    True
 
2867
    >>> string_to_delta('7d')
 
2868
    datetime.timedelta(7)
 
2869
    >>> string_to_delta('60s')
 
2870
    datetime.timedelta(0, 60)
 
2871
    >>> string_to_delta('60m')
 
2872
    datetime.timedelta(0, 3600)
 
2873
    >>> string_to_delta('24h')
 
2874
    datetime.timedelta(1)
 
2875
    >>> string_to_delta('1w')
 
2876
    datetime.timedelta(7)
 
2877
    >>> string_to_delta('5m 30s')
 
2878
    datetime.timedelta(0, 330)
2895
2879
    """
2896
2880
 
2897
2881
    try:
3267
3251
                             if isinstance(s, bytes)
3268
3252
                             else s) for s in
3269
3253
                            value["client_structure"]]
3270
 
                        # .name, .host, and .checker_command
3271
 
                        for k in ("name", "host", "checker_command"):
 
3254
                        # .name & .host
 
3255
                        for k in ("name", "host"):
3272
3256
                            if isinstance(value[k], bytes):
3273
3257
                                value[k] = value[k].decode("utf-8")
3274
3258
                        if "key_id" not in value:
3284
3268
                        for key, value in
3285
3269
                        bytes_old_client_settings.items()}
3286
3270
                    del bytes_old_client_settings
3287
 
                    # .host and .checker_command
 
3271
                    # .host
3288
3272
                    for value in old_client_settings.values():
3289
 
                        for attribute in ("host", "checker_command"):
3290
 
                            if isinstance(value[attribute], bytes):
3291
 
                                value[attribute] = (value[attribute]
3292
 
                                                    .decode("utf-8"))
 
3273
                        if isinstance(value["host"], bytes):
 
3274
                            value["host"] = (value["host"]
 
3275
                                             .decode("utf-8"))
3293
3276
            os.remove(stored_state_path)
3294
3277
        except IOError as e:
3295
3278
            if e.errno == errno.ENOENT: