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