/mandos/release

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

« back to all changes in this revision

Viewing changes to mandos

  • Committer: teddy at recompile
  • Date: 2020-02-09 03:54:46 UTC
  • mto: This revision was merged to the branch mainline in revision 396.
  • Revision ID: teddy@recompile.se-20200209035446-kud6h0l6u30lo10h
Makefile: fix targets run-server & run-client with GnuTLS 3.5.9

* Makefile (keydir/tls-privkey.pem keydir/tls-pubkey.pem): If the TLS
  session keys were not generated by mandos-keygen (which will happen
  with GnuTLS version 3.5.9 or older), create dummy empty unused files
  to avoid confusing make(1), which would otherwise re-run this target
  and create new OpenPGP key files which would not match the key
  fingerprint in the confdir/clients.conf file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
 
1
#!/usr/bin/python3 -bI
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
81
83
 
82
84
import dbus
83
85
import dbus.service
91
93
 
92
94
if sys.version_info.major == 2:
93
95
    __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
 
 
113
# Show warnings by default
 
114
if not sys.warnoptions:
 
115
    import warnings
 
116
    warnings.simplefilter("default")
94
117
 
95
118
# Try to find the value of SO_BINDTODEVICE:
96
119
try:
117
140
            # No value found
118
141
            SO_BINDTODEVICE = None
119
142
 
120
 
if sys.version_info.major == 2:
121
 
    str = unicode
122
 
 
123
143
if sys.version_info < (3, 2):
124
144
    configparser.Configparser = configparser.SafeConfigParser
125
145
 
126
 
version = "1.8.8"
 
146
version = "1.8.9"
127
147
stored_state_file = "clients.pickle"
128
148
 
129
149
logger = logging.getLogger()
 
150
logging.captureWarnings(True)   # Show warnings via the logging system
130
151
syslogger = None
131
152
 
132
153
try:
197
218
            output = subprocess.check_output(["gpgconf"])
198
219
            for line in output.splitlines():
199
220
                name, text, path = line.split(b":")
200
 
                if name == "gpg":
 
221
                if name == b"gpg":
201
222
                    self.gpg = path
202
223
                    break
203
224
        except OSError as e:
208
229
                          '--force-mdc',
209
230
                          '--quiet']
210
231
        # Only GPG version 1 has the --no-use-agent option.
211
 
        if self.gpg == "gpg" or self.gpg.endswith("/gpg"):
 
232
        if self.gpg == b"gpg" or self.gpg.endswith(b"/gpg"):
212
233
            self.gnupgargs.append("--no-use-agent")
213
234
 
214
235
    def __enter__(self):
1031
1052
        if self.checker_initiator_tag is not None:
1032
1053
            GLib.source_remove(self.checker_initiator_tag)
1033
1054
        self.checker_initiator_tag = GLib.timeout_add(
1034
 
            int(self.interval.total_seconds() * 1000),
 
1055
            random.randrange(int(self.interval.total_seconds() * 1000
 
1056
                                 + 1)),
1035
1057
            self.start_checker)
1036
1058
        # Schedule a disable() when 'timeout' has passed
1037
1059
        if self.disable_initiator_tag is not None:
1047
1069
        # Read return code from connection (see call_pipe)
1048
1070
        returncode = connection.recv()
1049
1071
        connection.close()
1050
 
        self.checker.join()
 
1072
        if self.checker is not None:
 
1073
            self.checker.join()
1051
1074
        self.checker_callback_tag = None
1052
1075
        self.checker = None
1053
1076
 
1111
1134
        if self.checker is None:
1112
1135
            # Escape attributes for the shell
1113
1136
            escaped_attrs = {
1114
 
                attr: re.escape(str(getattr(self, attr)))
 
1137
                attr: shlex.quote(str(getattr(self, attr)))
1115
1138
                for attr in self.runtime_expansions}
1116
1139
            try:
1117
1140
                command = self.checker_command % escaped_attrs
1144
1167
                kwargs=popen_args)
1145
1168
            self.checker.start()
1146
1169
            self.checker_callback_tag = GLib.io_add_watch(
1147
 
                pipe[0].fileno(), GLib.IO_IN,
 
1170
                GLib.IOChannel.unix_new(pipe[0].fileno()),
 
1171
                GLib.PRIORITY_DEFAULT, GLib.IO_IN,
1148
1172
                self.checker_callback, pipe[0], command)
1149
1173
        # Re-run this periodically if run by GLib.timeout_add
1150
1174
        return True
1405
1429
                raise ValueError("Byte arrays not supported for non-"
1406
1430
                                 "'ay' signature {!r}"
1407
1431
                                 .format(prop._dbus_signature))
1408
 
            value = dbus.ByteArray(b''.join(chr(byte)
1409
 
                                            for byte in value))
 
1432
            value = dbus.ByteArray(bytes(value))
1410
1433
        prop(value)
1411
1434
 
1412
1435
    @dbus.service.method(dbus.PROPERTIES_IFACE,
2674
2697
    def add_pipe(self, parent_pipe, proc):
2675
2698
        # Call "handle_ipc" for both data and EOF events
2676
2699
        GLib.io_add_watch(
2677
 
            parent_pipe.fileno(),
2678
 
            GLib.IO_IN | GLib.IO_HUP,
 
2700
            GLib.IOChannel.unix_new(parent_pipe.fileno()),
 
2701
            GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
2679
2702
            functools.partial(self.handle_ipc,
2680
2703
                              parent_pipe=parent_pipe,
2681
2704
                              proc=proc))
2719
2742
                return False
2720
2743
 
2721
2744
            GLib.io_add_watch(
2722
 
                parent_pipe.fileno(),
2723
 
                GLib.IO_IN | GLib.IO_HUP,
 
2745
                GLib.IOChannel.unix_new(parent_pipe.fileno()),
 
2746
                GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
2724
2747
                functools.partial(self.handle_ipc,
2725
2748
                                  parent_pipe=parent_pipe,
2726
2749
                                  proc=proc,
2741
2764
        if command == 'getattr':
2742
2765
            attrname = request[1]
2743
2766
            if isinstance(client_object.__getattribute__(attrname),
2744
 
                          collections.Callable):
 
2767
                          collections.abc.Callable):
2745
2768
                parent_pipe.send(('function', ))
2746
2769
            else:
2747
2770
                parent_pipe.send((
2758
2781
def rfc3339_duration_to_delta(duration):
2759
2782
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2760
2783
 
2761
 
    >>> rfc3339_duration_to_delta("P7D")
2762
 
    datetime.timedelta(7)
2763
 
    >>> rfc3339_duration_to_delta("PT60S")
2764
 
    datetime.timedelta(0, 60)
2765
 
    >>> rfc3339_duration_to_delta("PT60M")
2766
 
    datetime.timedelta(0, 3600)
2767
 
    >>> rfc3339_duration_to_delta("PT24H")
2768
 
    datetime.timedelta(1)
2769
 
    >>> rfc3339_duration_to_delta("P1W")
2770
 
    datetime.timedelta(7)
2771
 
    >>> rfc3339_duration_to_delta("PT5M30S")
2772
 
    datetime.timedelta(0, 330)
2773
 
    >>> rfc3339_duration_to_delta("P1DT3M20S")
2774
 
    datetime.timedelta(1, 200)
 
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
2775
2798
    """
2776
2799
 
2777
2800
    # Parsing an RFC 3339 duration with regular expressions is not
2857
2880
def string_to_delta(interval):
2858
2881
    """Parse a string and return a datetime.timedelta
2859
2882
 
2860
 
    >>> string_to_delta('7d')
2861
 
    datetime.timedelta(7)
2862
 
    >>> string_to_delta('60s')
2863
 
    datetime.timedelta(0, 60)
2864
 
    >>> string_to_delta('60m')
2865
 
    datetime.timedelta(0, 3600)
2866
 
    >>> string_to_delta('24h')
2867
 
    datetime.timedelta(1)
2868
 
    >>> string_to_delta('1w')
2869
 
    datetime.timedelta(7)
2870
 
    >>> string_to_delta('5m 30s')
2871
 
    datetime.timedelta(0, 330)
 
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
2872
2895
    """
2873
2896
 
2874
2897
    try:
3244
3267
                             if isinstance(s, bytes)
3245
3268
                             else s) for s in
3246
3269
                            value["client_structure"]]
3247
 
                        # .name & .host
3248
 
                        for k in ("name", "host"):
 
3270
                        # .name, .host, and .checker_command
 
3271
                        for k in ("name", "host", "checker_command"):
3249
3272
                            if isinstance(value[k], bytes):
3250
3273
                                value[k] = value[k].decode("utf-8")
3251
3274
                        if "key_id" not in value:
3261
3284
                        for key, value in
3262
3285
                        bytes_old_client_settings.items()}
3263
3286
                    del bytes_old_client_settings
3264
 
                    # .host
 
3287
                    # .host and .checker_command
3265
3288
                    for value in old_client_settings.values():
3266
 
                        if isinstance(value["host"], bytes):
3267
 
                            value["host"] = (value["host"]
3268
 
                                             .decode("utf-8"))
 
3289
                        for attribute in ("host", "checker_command"):
 
3290
                            if isinstance(value[attribute], bytes):
 
3291
                                value[attribute] = (value[attribute]
 
3292
                                                    .decode("utf-8"))
3269
3293
            os.remove(stored_state_path)
3270
3294
        except IOError as e:
3271
3295
            if e.errno == errno.ENOENT:
3596
3620
                sys.exit(1)
3597
3621
            # End of Avahi example code
3598
3622
 
3599
 
        GLib.io_add_watch(tcp_server.fileno(), GLib.IO_IN,
3600
 
                          lambda *args, **kwargs:
3601
 
                          (tcp_server.handle_request
3602
 
                           (*args[2:], **kwargs) or True))
 
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))
3603
3628
 
3604
3629
        logger.debug("Starting main loop")
3605
3630
        main_loop.run()