/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 Hogeborn
  • Date: 2019-09-03 18:52:20 UTC
  • mfrom: (237.7.724 trunk)
  • Revision ID: teddy@recompile.se-20190903185220-lsldutcamh5es7pv
MergeĀ fromĀ trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
#!/usr/bin/python
2
 
# -*- mode: python; coding: utf-8 -*-
 
1
#!/usr/bin/python3 -b
 
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.
5
5
#
77
77
import itertools
78
78
import collections
79
79
import codecs
 
80
import unittest
80
81
 
81
82
import dbus
82
83
import dbus.service
91
92
if sys.version_info.major == 2:
92
93
    __metaclass__ = type
93
94
 
 
95
# Show warnings by default
 
96
if not sys.warnoptions:
 
97
    import warnings
 
98
    warnings.simplefilter("default")
 
99
 
94
100
# Try to find the value of SO_BINDTODEVICE:
95
101
try:
96
102
    # This is where SO_BINDTODEVICE is in Python 3.3 (or 3.4?) and
126
132
stored_state_file = "clients.pickle"
127
133
 
128
134
logger = logging.getLogger()
 
135
logging.captureWarnings(True)   # Show warnings via the logging system
129
136
syslogger = None
130
137
 
131
138
try:
196
203
            output = subprocess.check_output(["gpgconf"])
197
204
            for line in output.splitlines():
198
205
                name, text, path = line.split(b":")
199
 
                if name == "gpg":
 
206
                if name == b"gpg":
200
207
                    self.gpg = path
201
208
                    break
202
209
        except OSError as e:
207
214
                          '--force-mdc',
208
215
                          '--quiet']
209
216
        # Only GPG version 1 has the --no-use-agent option.
210
 
        if self.gpg == "gpg" or self.gpg.endswith("/gpg"):
 
217
        if self.gpg == b"gpg" or self.gpg.endswith(b"/gpg"):
211
218
            self.gnupgargs.append("--no-use-agent")
212
219
 
213
220
    def __enter__(self):
1046
1053
        # Read return code from connection (see call_pipe)
1047
1054
        returncode = connection.recv()
1048
1055
        connection.close()
1049
 
        self.checker.join()
 
1056
        if self.checker is not None:
 
1057
            self.checker.join()
1050
1058
        self.checker_callback_tag = None
1051
1059
        self.checker = None
1052
1060
 
1143
1151
                kwargs=popen_args)
1144
1152
            self.checker.start()
1145
1153
            self.checker_callback_tag = GLib.io_add_watch(
1146
 
                pipe[0].fileno(), GLib.IO_IN,
 
1154
                GLib.IOChannel.unix_new(pipe[0].fileno()),
 
1155
                GLib.PRIORITY_DEFAULT, GLib.IO_IN,
1147
1156
                self.checker_callback, pipe[0], command)
1148
1157
        # Re-run this periodically if run by GLib.timeout_add
1149
1158
        return True
2673
2682
    def add_pipe(self, parent_pipe, proc):
2674
2683
        # Call "handle_ipc" for both data and EOF events
2675
2684
        GLib.io_add_watch(
2676
 
            parent_pipe.fileno(),
2677
 
            GLib.IO_IN | GLib.IO_HUP,
 
2685
            GLib.IOChannel.unix_new(parent_pipe.fileno()),
 
2686
            GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
2678
2687
            functools.partial(self.handle_ipc,
2679
2688
                              parent_pipe=parent_pipe,
2680
2689
                              proc=proc))
2718
2727
                return False
2719
2728
 
2720
2729
            GLib.io_add_watch(
2721
 
                parent_pipe.fileno(),
2722
 
                GLib.IO_IN | GLib.IO_HUP,
 
2730
                GLib.IOChannel.unix_new(parent_pipe.fileno()),
 
2731
                GLib.PRIORITY_DEFAULT, GLib.IO_IN | GLib.IO_HUP,
2723
2732
                functools.partial(self.handle_ipc,
2724
2733
                                  parent_pipe=parent_pipe,
2725
2734
                                  proc=proc,
2757
2766
def rfc3339_duration_to_delta(duration):
2758
2767
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2759
2768
 
2760
 
    >>> rfc3339_duration_to_delta("P7D")
2761
 
    datetime.timedelta(7)
2762
 
    >>> rfc3339_duration_to_delta("PT60S")
2763
 
    datetime.timedelta(0, 60)
2764
 
    >>> rfc3339_duration_to_delta("PT60M")
2765
 
    datetime.timedelta(0, 3600)
2766
 
    >>> rfc3339_duration_to_delta("PT24H")
2767
 
    datetime.timedelta(1)
2768
 
    >>> rfc3339_duration_to_delta("P1W")
2769
 
    datetime.timedelta(7)
2770
 
    >>> rfc3339_duration_to_delta("PT5M30S")
2771
 
    datetime.timedelta(0, 330)
2772
 
    >>> rfc3339_duration_to_delta("P1DT3M20S")
2773
 
    datetime.timedelta(1, 200)
 
2769
    >>> rfc3339_duration_to_delta("P7D") == datetime.timedelta(7)
 
2770
    True
 
2771
    >>> rfc3339_duration_to_delta("PT60S") == datetime.timedelta(0, 60)
 
2772
    True
 
2773
    >>> rfc3339_duration_to_delta("PT60M") == datetime.timedelta(0, 3600)
 
2774
    True
 
2775
    >>> rfc3339_duration_to_delta("PT24H") == datetime.timedelta(1)
 
2776
    True
 
2777
    >>> rfc3339_duration_to_delta("P1W") == datetime.timedelta(7)
 
2778
    True
 
2779
    >>> rfc3339_duration_to_delta("PT5M30S") == datetime.timedelta(0, 330)
 
2780
    True
 
2781
    >>> rfc3339_duration_to_delta("P1DT3M20S") == datetime.timedelta(1, 200)
 
2782
    True
2774
2783
    """
2775
2784
 
2776
2785
    # Parsing an RFC 3339 duration with regular expressions is not
2856
2865
def string_to_delta(interval):
2857
2866
    """Parse a string and return a datetime.timedelta
2858
2867
 
2859
 
    >>> string_to_delta('7d')
2860
 
    datetime.timedelta(7)
2861
 
    >>> string_to_delta('60s')
2862
 
    datetime.timedelta(0, 60)
2863
 
    >>> string_to_delta('60m')
2864
 
    datetime.timedelta(0, 3600)
2865
 
    >>> string_to_delta('24h')
2866
 
    datetime.timedelta(1)
2867
 
    >>> string_to_delta('1w')
2868
 
    datetime.timedelta(7)
2869
 
    >>> string_to_delta('5m 30s')
2870
 
    datetime.timedelta(0, 330)
 
2868
    >>> string_to_delta('7d') == datetime.timedelta(7)
 
2869
    True
 
2870
    >>> string_to_delta('60s') == datetime.timedelta(0, 60)
 
2871
    True
 
2872
    >>> string_to_delta('60m') == datetime.timedelta(0, 3600)
 
2873
    True
 
2874
    >>> string_to_delta('24h') == datetime.timedelta(1)
 
2875
    True
 
2876
    >>> string_to_delta('1w') == datetime.timedelta(7)
 
2877
    True
 
2878
    >>> string_to_delta('5m 30s') == datetime.timedelta(0, 330)
 
2879
    True
2871
2880
    """
2872
2881
 
2873
2882
    try:
2975
2984
 
2976
2985
    options = parser.parse_args()
2977
2986
 
2978
 
    if options.check:
2979
 
        import doctest
2980
 
        fail_count, test_count = doctest.testmod()
2981
 
        sys.exit(os.EX_OK if fail_count == 0 else 1)
2982
 
 
2983
2987
    # Default values for config file for server-global settings
2984
2988
    if gnutls.has_rawpk:
2985
2989
        priority = ("SECURE128:!CTYPE-X.509:+CTYPE-RAWPK:!RSA"
3248
3252
                             if isinstance(s, bytes)
3249
3253
                             else s) for s in
3250
3254
                            value["client_structure"]]
3251
 
                        # .name & .host
3252
 
                        for k in ("name", "host"):
 
3255
                        # .name, .host, and .checker_command
 
3256
                        for k in ("name", "host", "checker_command"):
3253
3257
                            if isinstance(value[k], bytes):
3254
3258
                                value[k] = value[k].decode("utf-8")
3255
3259
                        if "key_id" not in value:
3265
3269
                        for key, value in
3266
3270
                        bytes_old_client_settings.items()}
3267
3271
                    del bytes_old_client_settings
3268
 
                    # .host
 
3272
                    # .host and .checker_command
3269
3273
                    for value in old_client_settings.values():
3270
 
                        if isinstance(value["host"], bytes):
3271
 
                            value["host"] = (value["host"]
3272
 
                                             .decode("utf-8"))
 
3274
                        for attribute in ("host", "checker_command"):
 
3275
                            if isinstance(value[attribute], bytes):
 
3276
                                value[attribute] = (value[attribute]
 
3277
                                                    .decode("utf-8"))
3273
3278
            os.remove(stored_state_path)
3274
3279
        except IOError as e:
3275
3280
            if e.errno == errno.ENOENT:
3600
3605
                sys.exit(1)
3601
3606
            # End of Avahi example code
3602
3607
 
3603
 
        GLib.io_add_watch(tcp_server.fileno(), GLib.IO_IN,
3604
 
                          lambda *args, **kwargs:
3605
 
                          (tcp_server.handle_request
3606
 
                           (*args[2:], **kwargs) or True))
 
3608
        GLib.io_add_watch(
 
3609
            GLib.IOChannel.unix_new(tcp_server.fileno()),
 
3610
            GLib.PRIORITY_DEFAULT, GLib.IO_IN,
 
3611
            lambda *args, **kwargs: (tcp_server.handle_request
 
3612
                                     (*args[2:], **kwargs) or True))
3607
3613
 
3608
3614
        logger.debug("Starting main loop")
3609
3615
        main_loop.run()
3619
3625
    # Must run before the D-Bus bus name gets deregistered
3620
3626
    cleanup()
3621
3627
 
 
3628
 
 
3629
def should_only_run_tests():
 
3630
    parser = argparse.ArgumentParser(add_help=False)
 
3631
    parser.add_argument("--check", action='store_true')
 
3632
    args, unknown_args = parser.parse_known_args()
 
3633
    run_tests = args.check
 
3634
    if run_tests:
 
3635
        # Remove --check argument from sys.argv
 
3636
        sys.argv[1:] = unknown_args
 
3637
    return run_tests
 
3638
 
 
3639
# Add all tests from doctest strings
 
3640
def load_tests(loader, tests, none):
 
3641
    import doctest
 
3642
    tests.addTests(doctest.DocTestSuite())
 
3643
    return tests
3622
3644
 
3623
3645
if __name__ == '__main__':
3624
 
    main()
 
3646
    try:
 
3647
        if should_only_run_tests():
 
3648
            # Call using ./mandos --check [--verbose]
 
3649
            unittest.main()
 
3650
        else:
 
3651
            main()
 
3652
    finally:
 
3653
        logging.shutdown()