1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220
|
GSSAPI="BASE" # This ensures that a full module is generated by Cython
import locale # for decoding error messages
from gssapi.raw.cython_types cimport *
from gssapi.raw.cython_converters cimport c_create_oid_set
from gssapi.raw.names cimport Name
from gssapi.raw.oids cimport OID
from gssapi.raw.types import MechType
cdef extern from "python_gssapi.h":
OM_uint32 gss_display_status(OM_uint32 *minor_status,
OM_uint32 status_value,
int status_type,
const gss_OID mech_type,
OM_uint32 *message_context,
gss_buffer_t status_string)
OM_uint32 gss_indicate_mechs(OM_uint32 *minor_status,
gss_OID_set *mech_set)
OM_uint32 gss_inquire_names_for_mech(OM_uint32 *minor_status,
const gss_OID mech_type,
gss_OID_set *name_types)
OM_uint32 gss_inquire_mechs_for_name(OM_uint32 *minor_status,
const gss_name_t input_name,
gss_OID_set *mech_types)
def indicate_mechs():
cdef gss_OID_set mech_set
cdef OM_uint32 maj_stat, min_stat
maj_stat = gss_indicate_mechs(&min_stat, &mech_set)
if maj_stat == GSS_S_COMPLETE:
return c_create_oid_set(mech_set)
else:
raise GSSError(maj_stat, min_stat)
def inquire_names_for_mech(OID mech not None):
cdef gss_OID_set name_types
cdef OM_uint32 maj_stat, min_stat
maj_stat = gss_inquire_names_for_mech(&min_stat, &mech.raw_oid,
&name_types)
if maj_stat == GSS_S_COMPLETE:
return c_create_oid_set(name_types)
else:
raise GSSError(maj_stat, min_stat)
def inquire_mechs_for_name(Name name not None):
cdef gss_OID_set mech_types
cdef OM_uint32 maj_stat, min_stat
maj_stat = gss_inquire_mechs_for_name(&min_stat, name.raw_name,
&mech_types)
if maj_stat == GSS_S_COMPLETE:
return c_create_oid_set(mech_types)
else:
raise GSSError(maj_stat, min_stat)
def _display_status(unsigned int error_code, bint is_major_code,
OID mech=None, unsigned int message_context=0):
cdef int status_type
cdef gss_OID c_mech_type
if is_major_code:
status_type = GSS_C_GSS_CODE
else:
status_type = GSS_C_MECH_CODE
if mech is None:
c_mech_type = GSS_C_NO_OID
else:
c_mech_type = &mech.raw_oid
cdef OM_uint32 maj_stat
cdef OM_uint32 min_stat
cdef OM_uint32 msg_ctx_out = message_context
cdef gss_buffer_desc msg_buff
maj_stat = gss_display_status(&min_stat, error_code, status_type,
c_mech_type, &msg_ctx_out, &msg_buff)
if maj_stat == GSS_S_COMPLETE:
call_again = bool(msg_ctx_out)
msg_out = (<char*>msg_buff.value)[:msg_buff.length]
gss_release_buffer(&min_stat, &msg_buff)
return (msg_out, msg_ctx_out, call_again)
else:
# This hides whatever error gss_display_status is complaining about,
# but obviates infinite recursion into stack exhaustion. The
# exception raised here is handled by get_all_statuses(), which prints
# the code.
raise ValueError("gss_display_status call returned failure "
"(major {0}, minor {1}).".format(maj_stat, min_stat))
class GSSErrorRegistry(type):
__registry = {}
def __init__(cls, name, bases, attributes):
calling_code = getattr(cls, 'CALLING_CODE', None)
routine_code = getattr(cls, 'ROUTINE_CODE', None)
supplementary_code = getattr(cls, 'SUPPLEMENTARY_CODE', None)
# NB(directxman12): we ignore minor code since it's mech-specific
if any([calling_code, routine_code, supplementary_code]):
if calling_code not in cls.__registry:
cls.__registry[calling_code] = {}
call_reg = cls.__registry[calling_code]
if routine_code not in call_reg:
call_reg[routine_code] = {}
routine_reg = call_reg[routine_code]
routine_reg[supplementary_code] = cls
@staticmethod
def __get_registry(code, parent_reg):
return parent_reg.get(code, parent_reg.get(None, {}))
def __find_error(cls, maj_code):
codes = cls._parse_major_code(maj_code)
calling_code, routine_code, suppl_code = codes
call_reg = cls.__get_registry(calling_code, cls.__registry)
routine_reg = cls.__get_registry(routine_code, call_reg)
return routine_reg.get(suppl_code, routine_reg.get(None, None))
def __call__(cls, maj_code, min_code, *args, **kwargs):
new_cls = cls.__find_error(maj_code) or cls
return super(GSSErrorRegistry, new_cls).__call__(maj_code, min_code,
*args, **kwargs)
# NB(directxman12): this needs to be here (and not in another file)
# so that display_status can use it
class GSSError(Exception, metaclass=GSSErrorRegistry):
MESSAGE = u"Major ({maj_stat}): {maj_str}, Minor ({min_stat}): {min_str}"
@classmethod
def _parse_major_code(cls, maj_code):
# major status codes consist of
# calling error | routine error | supplementary info
# in non-overlapping bits
calling_code = GSS_CALLING_ERROR(maj_code) or None
routine_code = GSS_ROUTINE_ERROR(maj_code) or None
supplementary_code = GSS_SUPPLEMENTARY_INFO(maj_code) or None
return (calling_code, routine_code, supplementary_code)
def __init__(self, maj_code, min_code, token=None):
self.maj_code = maj_code
self.min_code = min_code
self.token = token
split_codes = self._parse_major_code(maj_code)
self.calling_code = split_codes[0]
self.routine_code = split_codes[1]
self.supplementary_code = split_codes[2]
super(GSSError, self).__init__(self.gen_message())
def get_all_statuses(self, code, is_maj):
try:
msg_encoding = locale.getlocale(locale.LC_MESSAGES)[1] or 'UTF-8'
except AttributeError: # Windows doesn't have LC_MESSAGES
msg_encoding = 'UTF-8'
res = []
try:
msg, ctx, cont = _display_status(code, is_maj)
res.append(msg.decode(msg_encoding))
except ValueError as e:
res.append(u'{0} Decoding code: {1}'.format(e, code))
cont = False
while cont:
try:
msg, ctx, cont = _display_status(code, is_maj,
message_context=ctx)
res.append(msg.decode(msg_encoding))
except ValueError as e:
res.append(u'{0} Decoding code: {1}'.format(e, code))
cont = False
return res
def gen_message(self):
maj_statuses = self.get_all_statuses(self.maj_code, True)
min_statuses = self.get_all_statuses(self.min_code, False)
maj_str = u' -- '.join(maj_statuses)
min_str = u' -- '.join(min_statuses)
return self.MESSAGE.format(maj_stat=self.maj_code,
maj_str=maj_str,
min_stat=self.min_code,
min_str=min_str)
|