xref: /illumos-gate/usr/src/lib/gss_mechs/mech_krb5/mech/disp_major_status.c (revision c65ebfc7045424bd04a6c7719a27b0ad3399ad54)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 
3 /*
4  * Copyright 1993 by OpenVision Technologies, Inc.
5  *
6  * Permission to use, copy, modify, distribute, and sell this software
7  * and its documentation for any purpose is hereby granted without fee,
8  * provided that the above copyright notice appears in all copies and
9  * that both that copyright notice and this permission notice appear in
10  * supporting documentation, and that the name of OpenVision not be used
11  * in advertising or publicity pertaining to distribution of the software
12  * without specific, written prior permission. OpenVision makes no
13  * representations about the suitability of this software for any
14  * purpose.  It is provided "as is" without express or implied warranty.
15  *
16  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
19  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
20  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
21  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
22  * PERFORMANCE OF THIS SOFTWARE.
23  */
24 
25 #include "gssapiP_generic.h"
26 #include <string.h>
27 #include <stdio.h>
28 
29 /*
30  * $Id: disp_major_status.c 13236 2001-05-08 17:10:18Z epeisach $
31  */
32 
33 /* XXXX these are not part of the GSSAPI C bindings!  (but should be) */
34 /* SUNW15resync - MIT 1.5 has these in gssapi.h */
35 
36 #define GSS_CALLING_ERROR_FIELD(x) \
37    (((x) >> GSS_C_CALLING_ERROR_OFFSET) & GSS_C_CALLING_ERROR_MASK)
38 #define GSS_ROUTINE_ERROR_FIELD(x) \
39    (((x) >> GSS_C_ROUTINE_ERROR_OFFSET) & GSS_C_ROUTINE_ERROR_MASK)
40 #define GSS_SUPPLEMENTARY_INFO_FIELD(x) \
41    (((x) >> GSS_C_SUPPLEMENTARY_OFFSET) & GSS_C_SUPPLEMENTARY_MASK)
42 
43 
44 /* This code has knowledge of the min and max errors of each type
45    within the gssapi major status */
46 
47 #define GSS_ERROR_STR(value, array, select, min, max, num) \
48    (((select(value) < (min)) || (select(value) > (max))) ? NULL : \
49     (array)[num(value)])
50 
51 /**/
52 
53 static const char * const calling_error_string[] = {
54    NULL,
55    "A required input parameter could not be read",
56    "A required input parameter could not be written",
57    "A parameter was malformed",
58 };
59 
60 static const char * const calling_error = "calling error";
61 
62 #define GSS_CALLING_ERROR_STR(x) \
63    GSS_ERROR_STR((x), calling_error_string, GSS_CALLING_ERROR, \
64 		 GSS_S_CALL_INACCESSIBLE_READ, GSS_S_CALL_BAD_STRUCTURE, \
65 		 GSS_CALLING_ERROR_FIELD)
66 
67 /**/
68 
69 static const char * const routine_error_string[] = {
70    NULL,
71    "An unsupported mechanism was requested",
72    "An invalid name was supplied",
73    "A supplied name was of an unsupported type",
74    "Incorrect channel bindings were supplied",
75    "An invalid status code was supplied",
76    "A token had an invalid signature",
77    "No credentials were supplied",
78    "No context has been established",
79    "A token was invalid",
80    "A credential was invalid",
81    "The referenced credentials have expired",
82    "The context has expired",
83    "Miscellaneous failure",
84    "The quality-of-protection requested could not be provided",
85    "The operation is forbidden by the local security policy",
86    "The operation or option is not available",
87 };
88 
89 static const char * const routine_error = "routine error";
90 
91 #define GSS_ROUTINE_ERROR_STR(x) \
92    GSS_ERROR_STR((x), routine_error_string, GSS_ROUTINE_ERROR, \
93 		 GSS_S_BAD_MECH, GSS_S_FAILURE, \
94 		 GSS_ROUTINE_ERROR_FIELD)
95 
96 /**/
97 
98 /* this becomes overly gross after about 4 strings */
99 
100 static const char * const sinfo_string[] = {
101    "The routine must be called again to complete its function",
102    "The token was a duplicate of an earlier token",
103    "The token's validity period has expired",
104    "A later token has already been processed",
105 };
106 
107 static const char * const sinfo_code = "supplementary info code";
108 
109 #define LSBGET(x) ((((x)^((x)-1))+1)>>1)
110 #define LSBMASK(n) ((1<<(n))^((1<<(n))-1))
111 
112 #define GSS_SINFO_STR(x) \
113    ((((1<<(x)) < GSS_S_CONTINUE_NEEDED) || ((1<<(x)) > GSS_S_UNSEQ_TOKEN)) ? \
114     /**/NULL:sinfo_string[(x)])
115 
116 /**/
117 
118 static const char * const no_error = "No error";
119 static const char * const unknown_error = "Unknown %s (field = %d)";
120 
121 /**/
122 
123 static int
124 display_unknown(kind, value, buffer)
125      const char *kind;
126      OM_uint32 value;
127      gss_buffer_t buffer;
128 {
129    char *str;
130 
131    if ((str =
132 	(char *) xmalloc(strlen(unknown_error)+strlen(kind)+7)) == NULL)
133       return(0);
134 
135    sprintf(str, unknown_error, kind, value);
136 
137    buffer->length = strlen(str);
138    buffer->value = str;
139 
140    return(1);
141 }
142 
143 /* code should be set to the calling error field */
144 
145 static OM_uint32 display_calling(minor_status, code, status_string)
146      OM_uint32 *minor_status;
147      OM_uint32 code;
148      gss_buffer_t status_string;
149 {
150    const char *str;
151 
152    if ((str = GSS_CALLING_ERROR_STR(code))) {
153       if (! g_make_string_buffer(str, status_string)) {
154 	 *minor_status = ENOMEM;
155 	 return(GSS_S_FAILURE);
156       }
157    } else {
158       if (! display_unknown(calling_error, GSS_CALLING_ERROR_FIELD(code),
159 			    status_string)) {
160 	 *minor_status = ENOMEM;
161 	 return(GSS_S_FAILURE);
162       }
163    }
164    *minor_status = 0;
165    return(GSS_S_COMPLETE);
166 }
167 
168 /* code should be set to the routine error field */
169 
170 static OM_uint32 display_routine(minor_status, code, status_string)
171      OM_uint32 *minor_status;
172      OM_uint32 code;
173      gss_buffer_t status_string;
174 {
175    const char *str;
176 
177    if ((str = GSS_ROUTINE_ERROR_STR(code))) {
178       if (! g_make_string_buffer(str, status_string)) {
179 	 *minor_status = ENOMEM;
180 	 return(GSS_S_FAILURE);
181       }
182    } else {
183       if (! display_unknown(routine_error, GSS_ROUTINE_ERROR_FIELD(code),
184 			    status_string)) {
185 	 *minor_status = ENOMEM;
186 	 return(GSS_S_FAILURE);
187       }
188    }
189    *minor_status = 0;
190    return(GSS_S_COMPLETE);
191 }
192 
193 /* code should be set to the bit offset (log_2) of a supplementary info bit */
194 
195 static OM_uint32 display_bit(minor_status, code, status_string)
196      OM_uint32 *minor_status;
197      OM_uint32 code;
198      gss_buffer_t status_string;
199 {
200    const char *str;
201 
202    if ((str = GSS_SINFO_STR(code))) {
203       if (! g_make_string_buffer(str, status_string)) {
204 	 *minor_status = ENOMEM;
205 	 return(GSS_S_FAILURE);
206       }
207    } else {
208       if (! display_unknown(sinfo_code, 1<<code, status_string)) {
209 	 *minor_status = ENOMEM;
210 	 return(GSS_S_FAILURE);
211       }
212    }
213    *minor_status = 0;
214    return(GSS_S_COMPLETE);
215 }
216 
217 /**/
218 
219 /* return error messages, for routine errors, call error, and status,
220    in that order.
221      message_context == 0 : print the routine error
222      message_context == 1 : print the calling error
223      message_context > 2  : print supplementary info bit (message_context-2)
224      */
225 
226 OM_uint32 g_display_major_status(minor_status, status_value,
227 				 message_context, status_string)
228      OM_uint32 *minor_status;
229      OM_uint32 status_value;
230      OM_uint32 *message_context;
231      gss_buffer_t status_string;
232 {
233    OM_uint32 ret, tmp;
234    int bit;
235 
236    /*** deal with no error at all specially */
237 
238    if (status_value == 0) {
239       if (! g_make_string_buffer(no_error, status_string)) {
240 	 *minor_status = ENOMEM;
241 	 return(GSS_S_FAILURE);
242       }
243       *message_context = 0;
244       *minor_status = 0;
245       return(GSS_S_COMPLETE);
246    }
247 
248    /*** do routine error */
249 
250    if (*message_context == 0) {
251       if ((tmp = GSS_ROUTINE_ERROR(status_value))) {
252 	 status_value -= tmp;
253 	 if ((ret = display_routine(minor_status, tmp, status_string)))
254 	    return(ret);
255 	 *minor_status = 0;
256 	 if (status_value) {
257 	    (*message_context)++;
258 	    return(GSS_S_COMPLETE);
259 	 } else {
260 	    *message_context = 0;
261 	    return(GSS_S_COMPLETE);
262 	 }
263       } else {
264 	 (*message_context)++;
265       }
266    } else {
267       status_value -= GSS_ROUTINE_ERROR(status_value);
268    }
269 
270    /*** do calling error */
271 
272    if (*message_context == 1) {
273       if ((tmp = GSS_CALLING_ERROR(status_value))) {
274 	 status_value -= tmp;
275 	 if ((ret = display_calling(minor_status, tmp, status_string)))
276 	    return(ret);
277 	 *minor_status = 0;
278 	 if (status_value) {
279 	    (*message_context)++;
280 	    return(GSS_S_COMPLETE);
281 	 } else {
282 	    *message_context = 0;
283 	    return(GSS_S_COMPLETE);
284 	 }
285       } else {
286 	 (*message_context)++;
287       }
288    } else {
289       status_value -= GSS_CALLING_ERROR(status_value);
290    }
291 
292    /*** do sinfo bits (*message_context == 2 + number of bits done) */
293 
294    tmp = GSS_SUPPLEMENTARY_INFO_FIELD(status_value);
295    /* mask off the bits which have been done */
296    if (*message_context > 2) {
297       tmp &= ~LSBMASK(*message_context-3);
298       status_value &= ~LSBMASK(*message_context-3);
299    }
300 
301    if (!tmp) {
302       /* bogon input - there should be something left */
303       *minor_status = (OM_uint32) G_BAD_MSG_CTX;
304       return(GSS_S_FAILURE);
305    }
306 
307    /* compute the bit offset */
308    /*SUPPRESS 570*/
309    for (bit=0; (((OM_uint32) 1)<<bit) != LSBGET(tmp); bit++) ;
310 
311    /* print it */
312    if ((ret = display_bit(minor_status, bit, status_string)))
313       return(ret);
314 
315    /* compute the new status_value/message_context */
316    status_value -= ((OM_uint32) 1)<<bit;
317 
318    if (status_value) {
319       *message_context = bit+3;
320       return(GSS_S_COMPLETE);
321    } else {
322       *message_context = 0;
323       return(GSS_S_COMPLETE);
324    }
325 }
326