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