/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-11-03 19:17:57 UTC
  • Revision ID: teddy@recompile.se-20191103191757-1hdpp0u5fxa8iumo
INSTALL: Add "-" argument to "su" invocations.

Show diffs side-by-side

added added

removed removed

Lines of Context:
11
11
# "AvahiService" class, and some lines in "main".
12
12
#
13
13
# Everything else is
14
 
# Copyright © 2008-2020 Teddy Hogeborn
15
 
# Copyright © 2008-2020 Björn Påhlsson
 
14
# Copyright © 2008-2019 Teddy Hogeborn
 
15
# Copyright © 2008-2019 Björn Påhlsson
16
16
#
17
17
# This file is part of Mandos.
18
18
#
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.14"
 
131
version = "1.8.9"
147
132
stored_state_file = "clients.pickle"
148
133
 
149
134
logger = logging.getLogger()
524
509
class AvahiServiceToSyslog(AvahiService):
525
510
    def rename(self, *args, **kwargs):
526
511
        """Add the new name to the syslog messages"""
527
 
        ret = super(AvahiServiceToSyslog, self).rename(*args,
528
 
                                                       **kwargs)
 
512
        ret = super(AvahiServiceToSyslog, self).rename(*args, **kwargs)
529
513
        syslogger.setFormatter(logging.Formatter(
530
514
            'Mandos ({}) [%(process)d]: %(levelname)s: %(message)s'
531
515
            .format(self.name)))
563
547
    OPENPGP_FMT_RAW = 0         # gnutls/openpgp.h
564
548
 
565
549
    # Types
566
 
    class _session_int(ctypes.Structure):
 
550
    class session_int(ctypes.Structure):
567
551
        _fields_ = []
568
 
    session_t = ctypes.POINTER(_session_int)
 
552
    session_t = ctypes.POINTER(session_int)
569
553
 
570
554
    class certificate_credentials_st(ctypes.Structure):
571
555
        _fields_ = []
577
561
        _fields_ = [('data', ctypes.POINTER(ctypes.c_ubyte)),
578
562
                    ('size', ctypes.c_uint)]
579
563
 
580
 
    class _openpgp_crt_int(ctypes.Structure):
 
564
    class openpgp_crt_int(ctypes.Structure):
581
565
        _fields_ = []
582
 
    openpgp_crt_t = ctypes.POINTER(_openpgp_crt_int)
 
566
    openpgp_crt_t = ctypes.POINTER(openpgp_crt_int)
583
567
    openpgp_crt_fmt_t = ctypes.c_int  # gnutls/openpgp.h
584
568
    log_func = ctypes.CFUNCTYPE(None, ctypes.c_int, ctypes.c_char_p)
585
569
    credentials_type_t = ctypes.c_int
594
578
            # gnutls.strerror()
595
579
            self.code = code
596
580
            if message is None and code is not None:
597
 
                message = gnutls.strerror(code).decode(
598
 
                    "utf-8", errors="replace")
 
581
                message = gnutls.strerror(code)
599
582
            return super(gnutls.Error, self).__init__(
600
583
                message, *args)
601
584
 
602
585
    class CertificateSecurityError(Error):
603
586
        pass
604
587
 
605
 
    class PointerTo:
606
 
        def __init__(self, cls):
607
 
            self.cls = cls
608
 
 
609
 
        def from_param(self, obj):
610
 
            if not isinstance(obj, self.cls):
611
 
                raise TypeError("Not of type {}: {!r}"
612
 
                                .format(self.cls.__name__, obj))
613
 
            return ctypes.byref(obj.from_param(obj))
614
 
 
615
 
    class CastToVoidPointer:
616
 
        def __init__(self, cls):
617
 
            self.cls = cls
618
 
 
619
 
        def from_param(self, obj):
620
 
            if not isinstance(obj, self.cls):
621
 
                raise TypeError("Not of type {}: {!r}"
622
 
                                .format(self.cls.__name__, obj))
623
 
            return ctypes.cast(obj.from_param(obj), ctypes.c_void_p)
624
 
 
625
 
    class With_from_param:
626
 
        @classmethod
627
 
        def from_param(cls, obj):
628
 
            return obj._as_parameter_
629
 
 
630
588
    # Classes
631
 
    class Credentials(With_from_param):
 
589
    class Credentials:
632
590
        def __init__(self):
633
 
            self._as_parameter_ = gnutls.certificate_credentials_t()
634
 
            gnutls.certificate_allocate_credentials(self)
 
591
            self._c_object = gnutls.certificate_credentials_t()
 
592
            gnutls.certificate_allocate_credentials(
 
593
                ctypes.byref(self._c_object))
635
594
            self.type = gnutls.CRD_CERTIFICATE
636
595
 
637
596
        def __del__(self):
638
 
            gnutls.certificate_free_credentials(self)
 
597
            gnutls.certificate_free_credentials(self._c_object)
639
598
 
640
 
    class ClientSession(With_from_param):
 
599
    class ClientSession:
641
600
        def __init__(self, socket, credentials=None):
642
 
            self._as_parameter_ = gnutls.session_t()
 
601
            self._c_object = gnutls.session_t()
643
602
            gnutls_flags = gnutls.CLIENT
644
603
            if gnutls.check_version(b"3.5.6"):
645
604
                gnutls_flags |= gnutls.NO_TICKETS
646
605
            if gnutls.has_rawpk:
647
606
                gnutls_flags |= gnutls.ENABLE_RAWPK
648
 
            gnutls.init(self, gnutls_flags)
 
607
            gnutls.init(ctypes.byref(self._c_object), gnutls_flags)
649
608
            del gnutls_flags
650
 
            gnutls.set_default_priority(self)
651
 
            gnutls.transport_set_ptr(self, socket.fileno())
652
 
            gnutls.handshake_set_private_extensions(self, True)
 
609
            gnutls.set_default_priority(self._c_object)
 
610
            gnutls.transport_set_ptr(self._c_object, socket.fileno())
 
611
            gnutls.handshake_set_private_extensions(self._c_object,
 
612
                                                    True)
653
613
            self.socket = socket
654
614
            if credentials is None:
655
615
                credentials = gnutls.Credentials()
656
 
            gnutls.credentials_set(self, credentials.type,
657
 
                                   credentials)
 
616
            gnutls.credentials_set(self._c_object, credentials.type,
 
617
                                   ctypes.cast(credentials._c_object,
 
618
                                               ctypes.c_void_p))
658
619
            self.credentials = credentials
659
620
 
660
621
        def __del__(self):
661
 
            gnutls.deinit(self)
 
622
            gnutls.deinit(self._c_object)
662
623
 
663
624
        def handshake(self):
664
 
            return gnutls.handshake(self)
 
625
            return gnutls.handshake(self._c_object)
665
626
 
666
627
        def send(self, data):
667
628
            data = bytes(data)
668
629
            data_len = len(data)
669
630
            while data_len > 0:
670
 
                data_len -= gnutls.record_send(self, data[-data_len:],
 
631
                data_len -= gnutls.record_send(self._c_object,
 
632
                                               data[-data_len:],
671
633
                                               data_len)
672
634
 
673
635
        def bye(self):
674
 
            return gnutls.bye(self, gnutls.SHUT_RDWR)
 
636
            return gnutls.bye(self._c_object, gnutls.SHUT_RDWR)
675
637
 
676
638
    # Error handling functions
677
639
    def _error_code(result):
678
640
        """A function to raise exceptions on errors, suitable
679
641
        for the 'restype' attribute on ctypes functions"""
680
 
        if result >= gnutls.E_SUCCESS:
 
642
        if result >= 0:
681
643
            return result
682
644
        if result == gnutls.E_NO_CERTIFICATE_FOUND:
683
645
            raise gnutls.CertificateSecurityError(code=result)
684
646
        raise gnutls.Error(code=result)
685
647
 
686
 
    def _retry_on_error(result, func, arguments,
687
 
                        _error_code=_error_code):
 
648
    def _retry_on_error(result, func, arguments):
688
649
        """A function to retry on some errors, suitable
689
650
        for the 'errcheck' attribute on ctypes functions"""
690
 
        while result < gnutls.E_SUCCESS:
 
651
        while result < 0:
691
652
            if result not in (gnutls.E_INTERRUPTED, gnutls.E_AGAIN):
692
653
                return _error_code(result)
693
654
            result = func(*arguments)
698
659
 
699
660
    # Functions
700
661
    priority_set_direct = _library.gnutls_priority_set_direct
701
 
    priority_set_direct.argtypes = [ClientSession, ctypes.c_char_p,
 
662
    priority_set_direct.argtypes = [session_t, ctypes.c_char_p,
702
663
                                    ctypes.POINTER(ctypes.c_char_p)]
703
664
    priority_set_direct.restype = _error_code
704
665
 
705
666
    init = _library.gnutls_init
706
 
    init.argtypes = [PointerTo(ClientSession), ctypes.c_int]
 
667
    init.argtypes = [ctypes.POINTER(session_t), ctypes.c_int]
707
668
    init.restype = _error_code
708
669
 
709
670
    set_default_priority = _library.gnutls_set_default_priority
710
 
    set_default_priority.argtypes = [ClientSession]
 
671
    set_default_priority.argtypes = [session_t]
711
672
    set_default_priority.restype = _error_code
712
673
 
713
674
    record_send = _library.gnutls_record_send
714
 
    record_send.argtypes = [ClientSession, ctypes.c_void_p,
 
675
    record_send.argtypes = [session_t, ctypes.c_void_p,
715
676
                            ctypes.c_size_t]
716
677
    record_send.restype = ctypes.c_ssize_t
717
678
    record_send.errcheck = _retry_on_error
719
680
    certificate_allocate_credentials = (
720
681
        _library.gnutls_certificate_allocate_credentials)
721
682
    certificate_allocate_credentials.argtypes = [
722
 
        PointerTo(Credentials)]
 
683
        ctypes.POINTER(certificate_credentials_t)]
723
684
    certificate_allocate_credentials.restype = _error_code
724
685
 
725
686
    certificate_free_credentials = (
726
687
        _library.gnutls_certificate_free_credentials)
727
 
    certificate_free_credentials.argtypes = [Credentials]
 
688
    certificate_free_credentials.argtypes = [
 
689
        certificate_credentials_t]
728
690
    certificate_free_credentials.restype = None
729
691
 
730
692
    handshake_set_private_extensions = (
731
693
        _library.gnutls_handshake_set_private_extensions)
732
 
    handshake_set_private_extensions.argtypes = [ClientSession,
 
694
    handshake_set_private_extensions.argtypes = [session_t,
733
695
                                                 ctypes.c_int]
734
696
    handshake_set_private_extensions.restype = None
735
697
 
736
698
    credentials_set = _library.gnutls_credentials_set
737
 
    credentials_set.argtypes = [ClientSession, credentials_type_t,
738
 
                                CastToVoidPointer(Credentials)]
 
699
    credentials_set.argtypes = [session_t, credentials_type_t,
 
700
                                ctypes.c_void_p]
739
701
    credentials_set.restype = _error_code
740
702
 
741
703
    strerror = _library.gnutls_strerror
743
705
    strerror.restype = ctypes.c_char_p
744
706
 
745
707
    certificate_type_get = _library.gnutls_certificate_type_get
746
 
    certificate_type_get.argtypes = [ClientSession]
 
708
    certificate_type_get.argtypes = [session_t]
747
709
    certificate_type_get.restype = _error_code
748
710
 
749
711
    certificate_get_peers = _library.gnutls_certificate_get_peers
750
 
    certificate_get_peers.argtypes = [ClientSession,
 
712
    certificate_get_peers.argtypes = [session_t,
751
713
                                      ctypes.POINTER(ctypes.c_uint)]
752
714
    certificate_get_peers.restype = ctypes.POINTER(datum_t)
753
715
 
760
722
    global_set_log_function.restype = None
761
723
 
762
724
    deinit = _library.gnutls_deinit
763
 
    deinit.argtypes = [ClientSession]
 
725
    deinit.argtypes = [session_t]
764
726
    deinit.restype = None
765
727
 
766
728
    handshake = _library.gnutls_handshake
767
 
    handshake.argtypes = [ClientSession]
768
 
    handshake.restype = ctypes.c_int
 
729
    handshake.argtypes = [session_t]
 
730
    handshake.restype = _error_code
769
731
    handshake.errcheck = _retry_on_error
770
732
 
771
733
    transport_set_ptr = _library.gnutls_transport_set_ptr
772
 
    transport_set_ptr.argtypes = [ClientSession, transport_ptr_t]
 
734
    transport_set_ptr.argtypes = [session_t, transport_ptr_t]
773
735
    transport_set_ptr.restype = None
774
736
 
775
737
    bye = _library.gnutls_bye
776
 
    bye.argtypes = [ClientSession, close_request_t]
777
 
    bye.restype = ctypes.c_int
 
738
    bye.argtypes = [session_t, close_request_t]
 
739
    bye.restype = _error_code
778
740
    bye.errcheck = _retry_on_error
779
741
 
780
742
    check_version = _library.gnutls_check_version
797
759
 
798
760
        x509_crt_fmt_t = ctypes.c_int
799
761
 
800
 
        # All the function declarations below are from
801
 
        # gnutls/abstract.h
 
762
        # All the function declarations below are from gnutls/abstract.h
802
763
        pubkey_init = _library.gnutls_pubkey_init
803
764
        pubkey_init.argtypes = [ctypes.POINTER(pubkey_t)]
804
765
        pubkey_init.restype = _error_code
818
779
        pubkey_deinit.argtypes = [pubkey_t]
819
780
        pubkey_deinit.restype = None
820
781
    else:
821
 
        # All the function declarations below are from
822
 
        # gnutls/openpgp.h
 
782
        # All the function declarations below are from gnutls/openpgp.h
823
783
 
824
784
        openpgp_crt_init = _library.gnutls_openpgp_crt_init
825
785
        openpgp_crt_init.argtypes = [ctypes.POINTER(openpgp_crt_t)]
831
791
                                       openpgp_crt_fmt_t]
832
792
        openpgp_crt_import.restype = _error_code
833
793
 
834
 
        openpgp_crt_verify_self = \
835
 
            _library.gnutls_openpgp_crt_verify_self
836
 
        openpgp_crt_verify_self.argtypes = [
837
 
            openpgp_crt_t,
838
 
            ctypes.c_uint,
839
 
            ctypes.POINTER(ctypes.c_uint),
840
 
        ]
 
794
        openpgp_crt_verify_self = _library.gnutls_openpgp_crt_verify_self
 
795
        openpgp_crt_verify_self.argtypes = [openpgp_crt_t, ctypes.c_uint,
 
796
                                            ctypes.POINTER(ctypes.c_uint)]
841
797
        openpgp_crt_verify_self.restype = _error_code
842
798
 
843
799
        openpgp_crt_deinit = _library.gnutls_openpgp_crt_deinit
854
810
 
855
811
    if check_version(b"3.6.4"):
856
812
        certificate_type_get2 = _library.gnutls_certificate_type_get2
857
 
        certificate_type_get2.argtypes = [ClientSession, ctypes.c_int]
 
813
        certificate_type_get2.argtypes = [session_t, ctypes.c_int]
858
814
        certificate_type_get2.restype = _error_code
859
815
 
860
816
    # Remove non-public functions
1081
1037
        if self.checker_initiator_tag is not None:
1082
1038
            GLib.source_remove(self.checker_initiator_tag)
1083
1039
        self.checker_initiator_tag = GLib.timeout_add(
1084
 
            random.randrange(int(self.interval.total_seconds() * 1000
1085
 
                                 + 1)),
 
1040
            int(self.interval.total_seconds() * 1000),
1086
1041
            self.start_checker)
1087
1042
        # Schedule a disable() when 'timeout' has passed
1088
1043
        if self.disable_initiator_tag is not None:
1163
1118
        if self.checker is None:
1164
1119
            # Escape attributes for the shell
1165
1120
            escaped_attrs = {
1166
 
                attr: shlex.quote(str(getattr(self, attr)))
 
1121
                attr: re.escape(str(getattr(self, attr)))
1167
1122
                for attr in self.runtime_expansions}
1168
1123
            try:
1169
1124
                command = self.checker_command % escaped_attrs
1458
1413
                raise ValueError("Byte arrays not supported for non-"
1459
1414
                                 "'ay' signature {!r}"
1460
1415
                                 .format(prop._dbus_signature))
1461
 
            value = dbus.ByteArray(bytes(value))
 
1416
            value = dbus.ByteArray(b''.join(chr(byte)
 
1417
                                            for byte in value))
1462
1418
        prop(value)
1463
1419
 
1464
1420
    @dbus.service.method(dbus.PROPERTIES_IFACE,
2320
2276
            priority = self.server.gnutls_priority
2321
2277
            if priority is None:
2322
2278
                priority = "NORMAL"
2323
 
            gnutls.priority_set_direct(session,
2324
 
                                       priority.encode("utf-8"), None)
 
2279
            gnutls.priority_set_direct(session._c_object,
 
2280
                                       priority.encode("utf-8"),
 
2281
                                       None)
2325
2282
 
2326
2283
            # Start communication using the Mandos protocol
2327
2284
            # Get protocol number
2354
2311
                    except (TypeError, gnutls.Error) as error:
2355
2312
                        logger.warning("Bad certificate: %s", error)
2356
2313
                        return
2357
 
                    logger.debug("Key ID: %s",
2358
 
                                 key_id.decode("utf-8",
2359
 
                                               errors="replace"))
 
2314
                    logger.debug("Key ID: %s", key_id)
2360
2315
 
2361
2316
                else:
2362
2317
                    key_id = b""
2454
2409
    def peer_certificate(session):
2455
2410
        "Return the peer's certificate as a bytestring"
2456
2411
        try:
2457
 
            cert_type = gnutls.certificate_type_get2(
2458
 
                session, gnutls.CTYPE_PEERS)
 
2412
            cert_type = gnutls.certificate_type_get2(session._c_object,
 
2413
                                                     gnutls.CTYPE_PEERS)
2459
2414
        except AttributeError:
2460
 
            cert_type = gnutls.certificate_type_get(session)
 
2415
            cert_type = gnutls.certificate_type_get(session._c_object)
2461
2416
        if gnutls.has_rawpk:
2462
2417
            valid_cert_types = frozenset((gnutls.CRT_RAWPK,))
2463
2418
        else:
2470
2425
            return b""
2471
2426
        list_size = ctypes.c_uint(1)
2472
2427
        cert_list = (gnutls.certificate_get_peers
2473
 
                     (session, ctypes.byref(list_size)))
 
2428
                     (session._c_object, ctypes.byref(list_size)))
2474
2429
        if not bool(cert_list) and list_size.value != 0:
2475
2430
            raise gnutls.Error("error getting peer certificate")
2476
2431
        if list_size.value == 0:
2498
2453
        buf = ctypes.create_string_buffer(32)
2499
2454
        buf_len = ctypes.c_size_t(len(buf))
2500
2455
        # Get the key ID from the raw public key into the buffer
2501
 
        gnutls.pubkey_get_key_id(
2502
 
            pubkey,
2503
 
            gnutls.KEYID_USE_SHA256,
2504
 
            ctypes.cast(ctypes.byref(buf),
2505
 
                        ctypes.POINTER(ctypes.c_ubyte)),
2506
 
            ctypes.byref(buf_len))
 
2456
        gnutls.pubkey_get_key_id(pubkey,
 
2457
                                 gnutls.KEYID_USE_SHA256,
 
2458
                                 ctypes.cast(ctypes.byref(buf),
 
2459
                                             ctypes.POINTER(ctypes.c_ubyte)),
 
2460
                                 ctypes.byref(buf_len))
2507
2461
        # Deinit the certificate
2508
2462
        gnutls.pubkey_deinit(pubkey)
2509
2463
 
2754
2708
            address = request[3]
2755
2709
 
2756
2710
            for c in self.clients.values():
2757
 
                if key_id == ("E3B0C44298FC1C149AFBF4C8996FB924"
2758
 
                              "27AE41E4649B934CA495991B7852B855"):
 
2711
                if key_id == "E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855":
2759
2712
                    continue
2760
2713
                if key_id and c.key_id == key_id:
2761
2714
                    client = c
2796
2749
        if command == 'getattr':
2797
2750
            attrname = request[1]
2798
2751
            if isinstance(client_object.__getattribute__(attrname),
2799
 
                          collections.abc.Callable):
 
2752
                          collections.Callable):
2800
2753
                parent_pipe.send(('function', ))
2801
2754
            else:
2802
2755
                parent_pipe.send((
2813
2766
def rfc3339_duration_to_delta(duration):
2814
2767
    """Parse an RFC 3339 "duration" and return a datetime.timedelta
2815
2768
 
2816
 
    >>> timedelta = datetime.timedelta
2817
 
    >>> rfc3339_duration_to_delta("P7D") == timedelta(7)
2818
 
    True
2819
 
    >>> rfc3339_duration_to_delta("PT60S") == timedelta(0, 60)
2820
 
    True
2821
 
    >>> rfc3339_duration_to_delta("PT60M") == timedelta(0, 3600)
2822
 
    True
2823
 
    >>> rfc3339_duration_to_delta("PT24H") == timedelta(1)
2824
 
    True
2825
 
    >>> rfc3339_duration_to_delta("P1W") == timedelta(7)
2826
 
    True
2827
 
    >>> rfc3339_duration_to_delta("PT5M30S") == timedelta(0, 330)
2828
 
    True
2829
 
    >>> rfc3339_duration_to_delta("P1DT3M20S") == timedelta(1, 200)
2830
 
    True
2831
 
    >>> del timedelta
 
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
2832
2783
    """
2833
2784
 
2834
2785
    # Parsing an RFC 3339 duration with regular expressions is not
3201
3152
 
3202
3153
        @gnutls.log_func
3203
3154
        def debug_gnutls(level, string):
3204
 
            logger.debug("GnuTLS: %s",
3205
 
                         string[:-1].decode("utf-8",
3206
 
                                            errors="replace"))
 
3155
            logger.debug("GnuTLS: %s", string[:-1])
3207
3156
 
3208
3157
        gnutls.global_set_log_function(debug_gnutls)
3209
3158