/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-04-09 13:50:57 UTC
  • mto: This revision was merged to the branch mainline in revision 382.
  • Revision ID: teddy@recompile.se-20190409135057-5di780wouddap7tf
mandos-ctl: Fix --secret when using the dbus-python module

* mandos-ctl (dbus_python_adapter.SystemBus.set_client_property): New;
  force ByteArray type to be sent for the client property "Secret".
  (Test_dbus_python_adapter_SystemBus.MockDBusPython_func
  .mock_dbus_python.SystemBus.get_object.DBusObject.Set): New.
  (Test_dbus_python_adapter_SystemBus.MockDBusPython_func
  .mock_dbus_python.SystemBus.get_object.set_property): - '' -
  (Test_dbus_python_adapter.SystemBus.MockDBusPython_func
  .mock_dbus_python.ByteArray): - '' -
  (Test_dbus_python_adapter_SystemBus
  .test_Set_Secret_sends_bytearray): - '' -

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
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 -*-
 
2
# -*- mode: python; 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
81
80
 
82
81
import dbus
83
82
import dbus.service
84
 
import gi
85
83
from gi.repository import GLib
86
84
from dbus.mainloop.glib import DBusGMainLoop
87
85
import ctypes
89
87
import xml.dom.minidom
90
88
import inspect
91
89
 
92
 
if sys.version_info.major == 2:
93
 
    __metaclass__ = type
94
 
 
95
90
# Try to find the value of SO_BINDTODEVICE:
96
91
try:
97
92
    # This is where SO_BINDTODEVICE is in Python 3.3 (or 3.4?) and
120
115
if sys.version_info.major == 2:
121
116
    str = unicode
122
117
 
123
 
if sys.version_info < (3, 2):
124
 
    configparser.Configparser = configparser.SafeConfigParser
125
 
 
126
 
version = "1.8.8"
 
118
version = "1.8.3"
127
119
stored_state_file = "clients.pickle"
128
120
 
129
121
logger = logging.getLogger()
187
179
    pass
188
180
 
189
181
 
190
 
class PGPEngine:
 
182
class PGPEngine(object):
191
183
    """A simple class for OpenPGP symmetric encryption & decryption"""
192
184
 
193
185
    def __init__(self):
283
275
 
284
276
 
285
277
# Pretend that we have an Avahi module
286
 
class avahi:
 
278
class avahi(object):
287
279
    """This isn't so much a class as it is a module-like namespace."""
288
280
    IF_UNSPEC = -1               # avahi-common/address.h
289
281
    PROTO_UNSPEC = -1            # avahi-common/address.h
323
315
    pass
324
316
 
325
317
 
326
 
class AvahiService:
 
318
class AvahiService(object):
327
319
    """An Avahi (Zeroconf) service.
328
320
 
329
321
    Attributes:
511
503
 
512
504
 
513
505
# Pretend that we have a GnuTLS module
514
 
class gnutls:
 
506
class gnutls(object):
515
507
    """This isn't so much a class as it is a module-like namespace."""
516
508
 
517
509
    library = ctypes.util.find_library("gnutls")
580
572
        pass
581
573
 
582
574
    # Classes
583
 
    class Credentials:
 
575
    class Credentials(object):
584
576
        def __init__(self):
585
577
            self._c_object = gnutls.certificate_credentials_t()
586
578
            gnutls.certificate_allocate_credentials(
590
582
        def __del__(self):
591
583
            gnutls.certificate_free_credentials(self._c_object)
592
584
 
593
 
    class ClientSession:
 
585
    class ClientSession(object):
594
586
        def __init__(self, socket, credentials=None):
595
587
            self._c_object = gnutls.session_t()
596
588
            gnutls_flags = gnutls.CLIENT
597
 
            if gnutls.check_version(b"3.5.6"):
 
589
            if gnutls.check_version("3.5.6"):
598
590
                gnutls_flags |= gnutls.NO_TICKETS
599
591
            if gnutls.has_rawpk:
600
592
                gnutls_flags |= gnutls.ENABLE_RAWPK
802
794
                                                    ctypes.c_size_t)]
803
795
        openpgp_crt_get_fingerprint.restype = _error_code
804
796
 
805
 
    if check_version(b"3.6.4"):
 
797
    if check_version("3.6.4"):
806
798
        certificate_type_get2 = _library.gnutls_certificate_type_get2
807
799
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
808
800
        certificate_type_get2.restype = _error_code
822
814
    connection.close()
823
815
 
824
816
 
825
 
class Client:
 
817
class Client(object):
826
818
    """A representation of a client host served by this server.
827
819
 
828
820
    Attributes:
829
821
    approved:   bool(); 'None' if not yet approved/disapproved
830
822
    approval_delay: datetime.timedelta(); Time to wait for approval
831
823
    approval_duration: datetime.timedelta(); Duration of one approval
832
 
    checker: multiprocessing.Process(); a running checker process used
833
 
             to see if the client lives. 'None' if no process is
834
 
             running.
 
824
    checker:    subprocess.Popen(); a running checker process used
 
825
                                    to see if the client lives.
 
826
                                    'None' if no process is running.
835
827
    checker_callback_tag: a GLib event source tag, or None
836
828
    checker_command: string; External command which is run to check
837
829
                     if client lives.  %() expansions are done at
1044
1036
    def checker_callback(self, source, condition, connection,
1045
1037
                         command):
1046
1038
        """The checker has completed, so take appropriate actions."""
 
1039
        self.checker_callback_tag = None
 
1040
        self.checker = None
1047
1041
        # Read return code from connection (see call_pipe)
1048
1042
        returncode = connection.recv()
1049
1043
        connection.close()
1050
 
        self.checker.join()
1051
 
        self.checker_callback_tag = None
1052
 
        self.checker = None
1053
1044
 
1054
1045
        if returncode >= 0:
1055
1046
            self.last_checker_status = returncode
2217
2208
    del _interface
2218
2209
 
2219
2210
 
2220
 
class ProxyClient:
 
2211
class ProxyClient(object):
2221
2212
    def __init__(self, child_pipe, key_id, fpr, address):
2222
2213
        self._pipe = child_pipe
2223
2214
        self._pipe.send(('init', key_id, fpr, address))
2296
2287
            approval_required = False
2297
2288
            try:
2298
2289
                if gnutls.has_rawpk:
2299
 
                    fpr = b""
 
2290
                    fpr = ""
2300
2291
                    try:
2301
2292
                        key_id = self.key_id(
2302
2293
                            self.peer_certificate(session))
2306
2297
                    logger.debug("Key ID: %s", key_id)
2307
2298
 
2308
2299
                else:
2309
 
                    key_id = b""
 
2300
                    key_id = ""
2310
2301
                    try:
2311
2302
                        fpr = self.fingerprint(
2312
2303
                            self.peer_certificate(session))
2496
2487
        return hex_fpr
2497
2488
 
2498
2489
 
2499
 
class MultiprocessingMixIn:
 
2490
class MultiprocessingMixIn(object):
2500
2491
    """Like socketserver.ThreadingMixIn, but with multiprocessing"""
2501
2492
 
2502
2493
    def sub_process_main(self, request, address):
2514
2505
        return proc
2515
2506
 
2516
2507
 
2517
 
class MultiprocessingMixInWithPipe(MultiprocessingMixIn):
 
2508
class MultiprocessingMixInWithPipe(MultiprocessingMixIn, object):
2518
2509
    """ adds a pipe to the MixIn """
2519
2510
 
2520
2511
    def process_request(self, request, client_address):
2535
2526
 
2536
2527
 
2537
2528
class IPv6_TCPServer(MultiprocessingMixInWithPipe,
2538
 
                     socketserver.TCPServer):
 
2529
                     socketserver.TCPServer, object):
2539
2530
    """IPv6-capable TCP server.  Accepts 'None' as address and/or port
2540
2531
 
2541
2532
    Attributes:
2614
2605
                    raise
2615
2606
        # Only bind(2) the socket if we really need to.
2616
2607
        if self.server_address[0] or self.server_address[1]:
2617
 
            if self.server_address[1]:
2618
 
                self.allow_reuse_address = True
2619
2608
            if not self.server_address[0]:
2620
2609
                if self.address_family == socket.AF_INET6:
2621
2610
                    any_address = "::"  # in6addr_any
2976
2965
 
2977
2966
    options = parser.parse_args()
2978
2967
 
 
2968
    if options.check:
 
2969
        import doctest
 
2970
        fail_count, test_count = doctest.testmod()
 
2971
        sys.exit(os.EX_OK if fail_count == 0 else 1)
 
2972
 
2979
2973
    # Default values for config file for server-global settings
2980
2974
    if gnutls.has_rawpk:
2981
2975
        priority = ("SECURE128:!CTYPE-X.509:+CTYPE-RAWPK:!RSA"
3001
2995
    del priority
3002
2996
 
3003
2997
    # Parse config file for server-global settings
3004
 
    server_config = configparser.ConfigParser(server_defaults)
 
2998
    server_config = configparser.SafeConfigParser(server_defaults)
3005
2999
    del server_defaults
3006
3000
    server_config.read(os.path.join(options.configdir, "mandos.conf"))
3007
 
    # Convert the ConfigParser object to a dict
 
3001
    # Convert the SafeConfigParser object to a dict
3008
3002
    server_settings = server_config.defaults()
3009
3003
    # Use the appropriate methods on the non-string config options
3010
3004
    for option in ("debug", "use_dbus", "use_ipv6", "restore",
3082
3076
                                  server_settings["servicename"])))
3083
3077
 
3084
3078
    # Parse config file with clients
3085
 
    client_config = configparser.ConfigParser(Client.client_defaults)
 
3079
    client_config = configparser.SafeConfigParser(Client
 
3080
                                                  .client_defaults)
3086
3081
    client_config.read(os.path.join(server_settings["configdir"],
3087
3082
                                    "clients.conf"))
3088
3083
 
3159
3154
        # Close all input and output, do double fork, etc.
3160
3155
        daemon()
3161
3156
 
3162
 
    if gi.version_info < (3, 10, 2):
3163
 
        # multiprocessing will use threads, so before we use GLib we
3164
 
        # need to inform GLib that threads will be used.
3165
 
        GLib.threads_init()
 
3157
    # multiprocessing will use threads, so before we use GLib we need
 
3158
    # to inform GLib that threads will be used.
 
3159
    GLib.threads_init()
3166
3160
 
3167
3161
    global main_loop
3168
3162
    # From the Avahi example code
3248
3242
                        for k in ("name", "host"):
3249
3243
                            if isinstance(value[k], bytes):
3250
3244
                                value[k] = value[k].decode("utf-8")
3251
 
                        if "key_id" not in value:
 
3245
                        if not value.has_key("key_id"):
3252
3246
                            value["key_id"] = ""
3253
 
                        elif "fingerprint" not in value:
 
3247
                        elif not value.has_key("fingerprint"):
3254
3248
                            value["fingerprint"] = ""
3255
3249
                    #  old_client_settings
3256
3250
                    # .keys()
3615
3609
    # Must run before the D-Bus bus name gets deregistered
3616
3610
    cleanup()
3617
3611
 
3618
 
 
3619
 
def should_only_run_tests():
3620
 
    parser = argparse.ArgumentParser(add_help=False)
3621
 
    parser.add_argument("--check", action='store_true')
3622
 
    args, unknown_args = parser.parse_known_args()
3623
 
    run_tests = args.check
3624
 
    if run_tests:
3625
 
        # Remove --check argument from sys.argv
3626
 
        sys.argv[1:] = unknown_args
3627
 
    return run_tests
3628
 
 
3629
 
# Add all tests from doctest strings
3630
 
def load_tests(loader, tests, none):
3631
 
    import doctest
3632
 
    tests.addTests(doctest.DocTestSuite())
3633
 
    return tests
3634
3612
 
3635
3613
if __name__ == '__main__':
3636
 
    try:
3637
 
        if should_only_run_tests():
3638
 
            # Call using ./mandos --check [--verbose]
3639
 
            unittest.main()
3640
 
        else:
3641
 
            main()
3642
 
    finally:
3643
 
        logging.shutdown()
 
3614
    main()