-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit introduces optional support for RFC 6680 to the low-level API. Note that gss_display_name_ext is not tested, since it is not implemented by MIT krb5. Additionally, in order to test the get/set/delete attribute methods, you will have to install the demo greet plugin that comes with krb5. Otherwise, the tests will be skipped. Part of #4
- Loading branch information
1 parent
ee437ca
commit 61eede9
Showing
7 changed files
with
448 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
from gssapi.raw.cython_types cimport * | ||
|
||
cdef extern from "python_gssapi.h": | ||
ctypedef struct gss_buffer_set_desc: | ||
size_t count | ||
gss_buffer_desc *elements | ||
ctypedef gss_buffer_set_desc* gss_buffer_set_t | ||
|
||
gss_buffer_set_t GSS_C_NO_BUFFER_SET | ||
|
||
OM_uint32 gss_release_buffer_set(OM_uint32 *min_stat, | ||
gss_buffer_set_t *buffer_set) nogil |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,282 @@ | ||
GSSAPI="BASE" # This ensures that a full module is generated by Cython | ||
|
||
from gssapi.raw.cython_types cimport * | ||
from gssapi.raw.ext_buffer_sets cimport * | ||
from gssapi.raw.names cimport Name | ||
from gssapi.raw.oids cimport OID | ||
from gssapi.raw.cython_converters cimport c_make_oid | ||
|
||
from gssapi.raw.misc import GSSError | ||
from gssapi.raw.named_tuples import InquireNameResult, GetNameAttributeResult | ||
from gssapi.raw import types as gsstypes | ||
|
||
cdef extern from "gssapi/gssapi_ext.h": | ||
OM_uint32 gss_display_name_ext(OM_uint32 *min_stat, gss_name_t name, | ||
gss_OID name_type, | ||
gss_buffer_t output_name) nogil | ||
|
||
OM_uint32 gss_inquire_name(OM_uint32 *min_stat, gss_name_t name, | ||
int *name_is_mn, gss_OID *mech_type, | ||
gss_buffer_set_t *attrs) nogil | ||
|
||
OM_uint32 gss_get_name_attribute(OM_uint32 *min_stat, gss_name_t name, | ||
gss_buffer_t attr, int *authenticated, | ||
int *complete, gss_buffer_t value, | ||
gss_buffer_t display_value, | ||
int *more) nogil | ||
|
||
OM_uint32 gss_set_name_attribute(OM_uint32 *min_stat, gss_name_t name, | ||
int complete, gss_buffer_t attr, | ||
gss_buffer_t value) nogil | ||
|
||
OM_uint32 gss_delete_name_attribute(OM_uint32 *min_stat, gss_name_t name, | ||
gss_buffer_t attr) nogil | ||
|
||
OM_uint32 gss_export_name_composite(OM_uint32 *min_stat, gss_name_t name, | ||
gss_buffer_t exported_name) nogil | ||
|
||
gss_OID GSS_C_NT_COMPOSITE_EXPORT | ||
|
||
|
||
gsstypes.NameType.composite_export = c_make_oid(GSS_C_NT_COMPOSITE_EXPORT) | ||
|
||
|
||
def display_name_ext(Name name not None, OID name_type not None): | ||
""" | ||
Display the given Name using the given name type OID | ||
This method attempts to display the given Name using the syntax of | ||
the given name type. If this is not possible, an appropriate error | ||
will be raised. | ||
Args: | ||
name (Name): the name to display | ||
name_type (OID): the name type (see NameType) to use to | ||
display the given name | ||
Returns: | ||
bytes: the displayed name | ||
Raises: | ||
OperationUnavailableError: the given name could not be displayed | ||
using the given name type | ||
""" | ||
|
||
# GSS_C_EMPTY_BUFFER | ||
cdef gss_buffer_desc output_name = gss_buffer_desc(0, NULL) | ||
|
||
cdef OM_uint32 maj_stat, min_stat | ||
|
||
maj_stat = gss_display_name_ext(&min_stat, name.raw_name, | ||
&name_type.raw_oid, &output_name) | ||
|
||
if maj_stat == GSS_S_COMPLETE: | ||
name_text = output_name.value[:output_name.length] | ||
gss_release_buffer(&min_stat, &output_name) | ||
return name_text | ||
else: | ||
raise GSSError(maj_stat, min_stat) | ||
|
||
|
||
def inquire_name(Name name not None): | ||
""" | ||
Get information about a Name | ||
This method retrives information about the given name, including | ||
the set of attribute names for the given name, as well as whether or | ||
not the name is a Mechanism Name. Additionally, if the given name is | ||
a Mechanism Name, the associated mechansim is returned as well. | ||
Args: | ||
name (Name): the name about which to inquire | ||
Returns: | ||
InquireNameResult: the set of attribute names for the given name, | ||
whether or not the name is a Mechanism Name, and potentially | ||
the associated mechanism if it is a Mechanism Name | ||
Raises: | ||
GSSError | ||
""" | ||
|
||
cdef int name_is_mn = 0 | ||
cdef gss_OID mn_mech | ||
cdef gss_buffer_set_t attr_names = GSS_C_NO_BUFFER_SET | ||
|
||
cdef OM_uint32 maj_stat, min_stat | ||
|
||
maj_stat = gss_inquire_name(&min_stat, name.raw_name, &name_is_mn, | ||
&mn_mech, &attr_names) | ||
|
||
cdef int i | ||
cdef OID py_mech = None | ||
if maj_stat == GSS_S_COMPLETE: | ||
py_attr_names = [] | ||
|
||
if attr_names != GSS_C_NO_BUFFER_SET: | ||
for i in range(attr_names.count): | ||
attr_name = attr_names.elements[i] | ||
py_attr_names.append(attr_name.value[:attr_name.length]) | ||
|
||
gss_release_buffer_set(&min_stat, &attr_names) | ||
|
||
if name_is_mn: | ||
py_mech = OID() | ||
py_mech.raw_oid = mn_mech[0] | ||
|
||
return InquireNameResult(py_attr_names, <bint>name_is_mn, py_mech) | ||
else: | ||
raise GSSError(maj_stat, min_stat) | ||
|
||
|
||
def set_name_attribute(Name name not None, attr not None, value not None, | ||
bint complete=False): | ||
""" | ||
Add a value to a Name attribute | ||
This method adds a value to the given attribute on the given name. | ||
Args: | ||
name (Name): the Name on which to set the attribute | ||
attr (bytes): the name of the attribute | ||
value (bytes): the value to add | ||
complete (bool): whether or not to mark this attribute's value | ||
set as being "complete" | ||
Raises: | ||
OperationUnavailableError: the given attribute name is unknown | ||
or could not be set | ||
""" | ||
|
||
cdef gss_buffer_desc attr_buff = gss_buffer_desc(len(attr), attr) | ||
cdef gss_buffer_desc val_buff = gss_buffer_desc(len(value), value) | ||
|
||
cdef OM_uint32 maj_stat, min_stat | ||
|
||
maj_stat = gss_set_name_attribute(&min_stat, name.raw_name, complete, | ||
&attr_buff, &val_buff) | ||
|
||
if maj_stat != GSS_S_COMPLETE: | ||
raise GSSError(maj_stat, min_stat) | ||
|
||
|
||
def get_name_attribute(Name name not None, attr not None, more=None): | ||
""" | ||
Get the value(s) of a Name attribute | ||
This method retrieves the value(s) of the given attribute | ||
for the given Name. | ||
Note that this functionality matches pseudo-API presented | ||
in RFC 6680, not the C API (which uses a state variable and | ||
multiple calls to retrieve multiple values). | ||
Args: | ||
name (Name): the Name from which to get the attribute | ||
attr (bytes): the name of the attribute | ||
Returns: | ||
GetNameAttributeResult: the raw version of the value(s), | ||
the human-readable version of the value(s), whether | ||
or not the attribute was authenticated, and whether or | ||
not the attribute's value set was marked as complete | ||
Raises: | ||
OperationUnavailableError: the given attribute is unknown | ||
or unset | ||
""" | ||
cdef gss_buffer_desc attr_buff = gss_buffer_desc(len(attr), attr) | ||
|
||
cdef gss_buffer_desc val_buff = gss_buffer_desc(0, NULL) | ||
cdef gss_buffer_desc displ_val_buff = gss_buffer_desc(0, NULL) | ||
cdef int complete | ||
cdef int authenticated | ||
|
||
cdef int more_val = -1 | ||
py_vals = [] | ||
py_displ_vals = [] | ||
|
||
cdef OM_uint32 maj_stat, min_stat | ||
|
||
while more_val != 0: | ||
maj_stat = gss_get_name_attribute(&min_stat, name.raw_name, | ||
&attr_buff, | ||
&authenticated, &complete, | ||
&val_buff, &displ_val_buff, | ||
&more_val) | ||
|
||
if maj_stat == GSS_S_COMPLETE: | ||
py_vals.append(val_buff.value[:val_buff.length]) | ||
py_displ_vals.append( | ||
displ_val_buff.value[:displ_val_buff.length]) | ||
|
||
gss_release_buffer(&min_stat, &val_buff) | ||
gss_release_buffer(&min_stat, &displ_val_buff) | ||
else: | ||
raise GSSError(maj_stat, min_stat) | ||
|
||
return GetNameAttributeResult(py_vals, py_displ_vals, <bint>authenticated, | ||
<bint>complete) | ||
|
||
|
||
def delete_name_attribute(Name name not None, attr not None): | ||
""" | ||
Remove an attribute from a Name | ||
This method removes an attribute from a Name. This method may be | ||
used before :func:`set_name_attribute` clear the values of an attribute | ||
before setting a new value (making the latter method work like a 'set' | ||
operation instead of an 'add' operation). | ||
Note that the removal of certain attributes may not be allowed. | ||
Args: | ||
name (Name): the name to remove the attribute from | ||
attr (bytes): the name of the attribute | ||
Raises: | ||
OperationUnavailableError | ||
UnauthorizedError | ||
""" | ||
|
||
cdef gss_buffer_desc attr_buff = gss_buffer_desc(len(attr), attr) | ||
|
||
cdef OM_uint32 maj_stat, min_stat | ||
|
||
maj_stat = gss_delete_name_attribute(&min_stat, name.raw_name, | ||
&attr_buff) | ||
|
||
if maj_stat != GSS_S_COMPLETE: | ||
raise GSSError(maj_stat, min_stat) | ||
|
||
|
||
def export_name_composite(Name name not None): | ||
""" | ||
Export a name, preserving attribute information | ||
This method functions similarly to :func:`export_name`, except that | ||
it preserves attribute information. The resulting bytes may be imported | ||
using :func:`import_name` with the `NameType.composite_export` name type. | ||
Args: | ||
name (Name): the name to export | ||
Returns: | ||
bytes: the exported composite name | ||
Raises: | ||
GSSError | ||
""" | ||
|
||
cdef gss_buffer_desc res = gss_buffer_desc(0, NULL) | ||
|
||
cdef OM_uint32 maj_stat, min_stat | ||
|
||
maj_stat = gss_export_name_composite(&min_stat, name.raw_name, &res) | ||
|
||
if maj_stat == GSS_S_COMPLETE: | ||
py_res = res.value[:res.length] | ||
gss_release_buffer(&min_stat, &res) | ||
return py_res | ||
else: | ||
raise GSSError(maj_stat, min_stat) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.