From ef319a3619754daaa2f8fe473d87ab452a4c2e00 Mon Sep 17 00:00:00 2001 From: Alexander Scheel Date: Mon, 24 Jul 2017 09:19:12 -0400 Subject: [PATCH] Implement support for GSSAPI extension RFC 5801 RFC 5801 provides SASL-specific mechanism inquiry calls for GSSAPI. The inquire_mech_for_saslname call allows resolving mechs by their respective SASL names, and inquire_saslname_for_mech allows the reverse operation, also providing a mechanism name and description. These calls are implemented as part of the raw interface. Signed-off-by: Alexander Scheel --- gssapi/raw/__init__.py | 6 +++ gssapi/raw/ext_rfc5801.pyx | 86 ++++++++++++++++++++++++++++++++++++++ gssapi/raw/named_tuples.py | 4 ++ gssapi/tests/test_raw.py | 26 ++++++++++++ setup.py | 1 + 5 files changed, 123 insertions(+) create mode 100644 gssapi/raw/ext_rfc5801.pyx diff --git a/gssapi/raw/__init__.py b/gssapi/raw/__init__.py index ef2677f8..2ad87452 100644 --- a/gssapi/raw/__init__.py +++ b/gssapi/raw/__init__.py @@ -81,6 +81,12 @@ except ImportError: pass +# optional RFC 5801 support +try: + from gssapi.raw.ext_rfc5801 import * # noqa +except ImportError: + pass + try: from gssapi.raw.ext_cred_imp_exp import * # noqa except ImportError: diff --git a/gssapi/raw/ext_rfc5801.pyx b/gssapi/raw/ext_rfc5801.pyx new file mode 100644 index 00000000..09a8f40c --- /dev/null +++ b/gssapi/raw/ext_rfc5801.pyx @@ -0,0 +1,86 @@ +from gssapi.raw.cython_types cimport * +from gssapi.raw.oids cimport OID +GSSAPI="BASE" # This ensures that a full module is generated by Cython + +from gssapi.raw.cython_converters cimport c_make_oid + +from gssapi.raw.named_tuples import InquireSASLNameResult +from gssapi.raw.misc import GSSError + +cdef extern from "python_gssapi_ext.h": + OM_uint32 gss_inquire_saslname_for_mech( + OM_uint32 *min_stat, + const gss_OID desired_mech, + gss_buffer_t sasl_mech_name, + gss_buffer_t mech_name, + gss_buffer_t mech_description) nogil + + OM_uint32 gss_inquire_mech_for_saslname( + OM_uint32 *min_stat, + const gss_buffer_t sasl_mech_name, + gss_OID *mech_type) nogil + + +def inquire_saslname_for_mech(OID mech): + """ + inquire_saslname_for_mech(mech) + Gets information about a specified mech, including the SASL name, + the mech name, and the mech description. + + Args: + mech (OID): Mechanism to inquire about + + Returns: + InquireSASLNameResult: the results of inquiry; a mech's SASL name, + name, and description. + """ + cdef OM_uint32 maj_stat, min_stat + cdef gss_buffer_desc sasl_mech_name + cdef gss_buffer_desc mech_name + cdef gss_buffer_desc mech_desc + cdef gss_OID m = GSS_C_NO_OID + + if mech is not None: + m = &mech.raw_oid + + maj_stat = gss_inquire_saslname_for_mech(&min_stat, m, &sasl_mech_name, + &mech_name, &mech_desc) + + if maj_stat == GSS_S_COMPLETE: + out_smn = sasl_mech_name.value[:sasl_mech_name.length] + out_mn = mech_name.value[:mech_name.length] + out_md = mech_desc.value[:mech_desc.length] + + gss_release_buffer(&min_stat, &sasl_mech_name) + gss_release_buffer(&min_stat, &mech_name) + gss_release_buffer(&min_stat, &mech_desc) + + return InquireSASLNameResult(out_smn, out_mn, out_md) + else: + raise GSSError(maj_stat, min_stat) + + +def inquire_mech_for_saslname(bytes sasl_name): + """ + inquire_mech_for_saslname(sasl_name) + Gets the OID for the mech specified by SASL name. + + Args: + sasl_name (bytes): SASL name of the mechanism + + Returns: + OID: the mechanism with corresponding SASL name. + """ + cdef OM_uint32 maj_stat, min_stat + cdef gss_buffer_desc sn + cdef gss_OID m + + sn.length = len(sasl_name) + sn.value = sasl_name + + maj_stat = gss_inquire_mech_for_saslname(&min_stat, &sn, &m) + + if maj_stat == GSS_S_COMPLETE: + return c_make_oid(m) + else: + raise GSSError(maj_stat, min_stat) diff --git a/gssapi/raw/named_tuples.py b/gssapi/raw/named_tuples.py index 137f19fd..3ce494ea 100644 --- a/gssapi/raw/named_tuples.py +++ b/gssapi/raw/named_tuples.py @@ -70,3 +70,7 @@ DisplayAttrResult = namedtuple('DisplayAttrResult', ['name', 'short_desc', 'long_desc']) + +InquireSASLNameResult = namedtuple('InquireSASLNameResult', + ['sasl_mech_name', 'mech_name', + 'mech_description']) diff --git a/gssapi/tests/test_raw.py b/gssapi/tests/test_raw.py index fbe54f1c..595e0a68 100644 --- a/gssapi/tests/test_raw.py +++ b/gssapi/tests/test_raw.py @@ -734,6 +734,32 @@ def test_display_mech_attr(self): display_out.short_desc.should_be(attr[2]) display_out.long_desc.should_be(attr[3]) + @ktu.gssapi_extension_test('rfc5801', 'SASL Names') + def test_sasl_names(self): + mechs = gb.indicate_mechs() + + for mech in mechs: + out = gb.inquire_saslname_for_mech(mech) + + out_smn = out.sasl_mech_name + out_smn.shouldnt_be_none() + out_smn.should_be_a(bytes) + out_smn.shouldnt_be_empty() + + out_mn = out.mech_name + out_mn.shouldnt_be_none() + out_mn.should_be_a(bytes) + out_mn.shouldnt_be_empty() + + out_md = out.mech_description + out_md.shouldnt_be_none() + out_md.should_be_a(bytes) + out_md.shouldnt_be_empty() + + cmp_mech = gb.inquire_mech_for_saslname(out_smn) + cmp_mech.shouldnt_be_none() + cmp_mech.should_be(mech) + class TestIntEnumFlagSet(unittest.TestCase): def test_create_from_int(self): diff --git a/setup.py b/setup.py index 2f29f0ca..67bc4ef9 100755 --- a/setup.py +++ b/setup.py @@ -260,6 +260,7 @@ def gssapi_modules(lst): extension_file('cred_store', 'gss_store_cred_into'), extension_file('rfc5587', 'gss_indicate_mechs_by_attrs'), extension_file('rfc5588', 'gss_store_cred'), + extension_file('rfc5801', 'gss_inquire_saslname_for_mech'), extension_file('cred_imp_exp', 'gss_import_cred'), extension_file('dce', 'gss_wrap_iov'), extension_file('iov_mic', 'gss_get_mic_iov'),