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
display_unknown(kind,value,buffer)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
display_calling(minor_status,code,status_string)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
display_routine(minor_status,code,status_string)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
display_bit(minor_status,code,status_string)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
g_display_major_status(minor_status,status_value,message_context,status_string)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