/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 14:46:13 UTC
  • Revision ID: teddy@recompile.se-20190824144613-z46mn4m8v5x2ifnj
Server: Show Python warnings

* mandos: Show Python warnings, and use the logging system to do it.

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
1167
1150
                kwargs=popen_args)
1168
1151
            self.checker.start()
1169
1152
            self.checker_callback_tag = GLib.io_add_watch(
1170
 
                GLib.IOChannel.unix_new(pipe[0].fileno()),
1171
 
                GLib.PRIORITY_DEFAULT, GLib.IO_IN,
 
1153
                pipe[0].fileno(), GLib.IO_IN,
1172
1154
                self.checker_callback, pipe[0], command)
1173
1155
        # Re-run this periodically if run by GLib.timeout_add
1174
1156
        return True
1429
1411
                raise ValueError("Byte arrays not supported for non-"
1430
1412
                                 "'ay' signature {!r}"
1431
1413
                                 .format(prop._dbus_signature))
1432
 
            value = dbus.ByteArray(bytes(value))
 
1414
            value = dbus.ByteArray(b''.join(chr(byte)
 
1415
                                            for byte in value))
1433
1416
        prop(value)
1434
1417
 
1435
1418
    @dbus.service.method(dbus.PROPERTIES_IFACE,
2697
2680
    def add_pipe(self, parent_pipe, proc):
2698
2681
        # Call "handle_ipc" for both data and EOF events
2699
2682
        GLib.io_add_watch(
2700
 
            GLib.IOChannel.unix_new(parent_pipe.fileno()),
2701
 
            GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
 
2683
            parent_pipe.fileno(),
 
2684
            GLib.IO_IN | GLib.IO_HUP,
2702
2685
            functools.partial(self.handle_ipc,
2703
2686
                              parent_pipe=parent_pipe,
2704
2687
                              proc=proc))
2742
2725
                return False
2743
2726
 
2744
2727
            GLib.io_add_watch(
2745
 
                GLib.IOChannel.unix_new(parent_pipe.fileno()),
2746
 
                GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
 
2728
                parent_pipe.fileno(),
 
2729
                GLib.IO_IN | GLib.IO_HUP,
2747
2730
                functools.partial(self.handle_ipc,
2748
2731
                                  parent_pipe=parent_pipe,
2749
2732
                                  proc=proc,
2764
2747
        if command == 'getattr':
2765
2748
            attrname = request[1]
2766
2749
            if isinstance(client_object.__getattribute__(attrname),
2767
 
                          collections.abc.Callable):
 
2750
                          collections.Callable):
2768
2751
                parent_pipe.send(('function', ))
2769
2752
            else:
2770
2753
                parent_pipe.send((
2781
2764
def rfc3339_duration_to_delta(duration):
2782
2765
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2783
2766
 
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
 
2767
    >>> rfc3339_duration_to_delta("P7D")
 
2768
    datetime.timedelta(7)
 
2769
    >>> rfc3339_duration_to_delta("PT60S")
 
2770
    datetime.timedelta(0, 60)
 
2771
    >>> rfc3339_duration_to_delta("PT60M")
 
2772
    datetime.timedelta(0, 3600)
 
2773
    >>> rfc3339_duration_to_delta("PT24H")
 
2774
    datetime.timedelta(1)
 
2775
    >>> rfc3339_duration_to_delta("P1W")
 
2776
    datetime.timedelta(7)
 
2777
    >>> rfc3339_duration_to_delta("PT5M30S")
 
2778
    datetime.timedelta(0, 330)
 
2779
    >>> rfc3339_duration_to_delta("P1DT3M20S")
 
2780
    datetime.timedelta(1, 200)
2798
2781
    """
2799
2782
 
2800
2783
    # Parsing an RFC 3339 duration with regular expressions is not
2880
2863
def string_to_delta(interval):
2881
2864
    """Parse a string and return a datetime.timedelta
2882
2865
 
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
 
2866
    >>> string_to_delta('7d')
 
2867
    datetime.timedelta(7)
 
2868
    >>> string_to_delta('60s')
 
2869
    datetime.timedelta(0, 60)
 
2870
    >>> string_to_delta('60m')
 
2871
    datetime.timedelta(0, 3600)
 
2872
    >>> string_to_delta('24h')
 
2873
    datetime.timedelta(1)
 
2874
    >>> string_to_delta('1w')
 
2875
    datetime.timedelta(7)
 
2876
    >>> string_to_delta('5m 30s')
 
2877
    datetime.timedelta(0, 330)
2895
2878
    """
2896
2879
 
2897
2880
    try:
3267
3250
                             if isinstance(s, bytes)
3268
3251
                             else s) for s in
3269
3252
                            value["client_structure"]]
3270
 
                        # .name, .host, and .checker_command
3271
 
                        for k in ("name", "host", "checker_command"):
 
3253
                        # .name & .host
 
3254
                        for k in ("name", "host"):
3272
3255
                            if isinstance(value[k], bytes):
3273
3256
                                value[k] = value[k].decode("utf-8")
3274
3257
                        if "key_id" not in value:
3284
3267
                        for key, value in
3285
3268
                        bytes_old_client_settings.items()}
3286
3269
                    del bytes_old_client_settings
3287
 
                    # .host and .checker_command
 
3270
                    # .host
3288
3271
                    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"))
 
3272
                        if isinstance(value["host"], bytes):
 
3273
                            value["host"] = (value["host"]
 
3274
                                             .decode("utf-8"))
3293
3275
            os.remove(stored_state_path)
3294
3276
        except IOError as e:
3295
3277
            if e.errno == errno.ENOENT:
3620
3602
                sys.exit(1)
3621
3603
            # End of Avahi example code
3622
3604
 
3623
 
        GLib.io_add_watch(
3624
 
            GLib.IOChannel.unix_new(tcp_server.fileno()),
3625
 
            GLib.PRIORITY_DEFAULT, GLib.IO_IN,
3626
 
            lambda *args, **kwargs: (tcp_server.handle_request
3627
 
                                     (*args[2:], **kwargs) or True))
 
3605
        GLib.io_add_watch(tcp_server.fileno(), GLib.IO_IN,
 
3606
                          lambda *args, **kwargs:
 
3607
                          (tcp_server.handle_request
 
3608
                           (*args[2:], **kwargs) or True))
3628
3609
 
3629
3610
        logger.debug("Starting main loop")
3630
3611
        main_loop.run()