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