File: misc.pyx

package info (click to toggle)
python-gssapi 1.10.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 876 kB
  • sloc: python: 3,707; sh: 198; makefile: 154; ansic: 60
file content (220 lines) | stat: -rw-r--r-- 7,558 bytes parent folder | download | duplicates (3)
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)