1 /* #pragma ident "@(#)g_dsp_status.c 1.17 04/02/23 SMI" */
2
3 /*
4 * Copyright 1996 by Sun Microsystems, 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 Sun Microsystems not be used
11 * in advertising or publicity pertaining to distribution of the software
12 * without specific, written prior permission. Sun Microsystems 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 * SUN MICROSYSTEMS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
17 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
18 * EVENT SHALL SUN MICROSYSTEMS 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 /*
26 * glue routine gss_display_status
27 *
28 */
29
30 #include "mglueP.h"
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34
35 /* local function */
36 static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
37
38 OM_uint32 KRB5_CALLCONV
gss_display_status(minor_status,status_value,status_type,req_mech_type,message_context,status_string)39 gss_display_status (minor_status,
40 status_value,
41 status_type,
42 req_mech_type,
43 message_context,
44 status_string)
45
46 OM_uint32 * minor_status;
47 OM_uint32 status_value;
48 int status_type;
49 gss_OID req_mech_type;
50 OM_uint32 * message_context;
51 gss_buffer_t status_string;
52
53 {
54 gss_OID mech_type = (gss_OID) req_mech_type;
55 gss_mechanism mech;
56 gss_OID_desc m_oid = { 0, 0 };
57
58 if (minor_status != NULL)
59 *minor_status = 0;
60
61 if (status_string != GSS_C_NO_BUFFER) {
62 status_string->length = 0;
63 status_string->value = NULL;
64 }
65
66 if (minor_status == NULL ||
67 message_context == NULL ||
68 status_string == GSS_C_NO_BUFFER)
69
70 return (GSS_S_CALL_INACCESSIBLE_WRITE);
71
72 /* we handle major status codes, and the mechs do the minor */
73 if (status_type == GSS_C_GSS_CODE)
74 return (displayMajor(status_value, message_context,
75 status_string));
76
77 /*
78 * must be the minor status - let mechs do the work
79 * select the appropriate underlying mechanism routine and
80 * call it.
81 */
82
83 /* In this version, we only handle status codes that have been
84 mapped to a flat numbering space. Look up the value we got
85 passed. If it's not found, complain. */
86 if (status_value == 0) {
87 status_string->value = gssalloc_strdup("Unknown error");
88 if (status_string->value == NULL) {
89 *minor_status = ENOMEM;
90 map_errcode(minor_status);
91 return GSS_S_FAILURE;
92 }
93 status_string->length = strlen(status_string->value);
94 *message_context = 0;
95 *minor_status = 0;
96 return GSS_S_COMPLETE;
97 }
98 {
99 int err;
100 OM_uint32 m_status = 0, status;
101
102 err = gssint_mecherrmap_get(status_value, &m_oid, &m_status);
103 if (err) {
104 *minor_status = err;
105 map_errcode(minor_status);
106 return GSS_S_BAD_STATUS;
107 }
108 if (m_oid.length == 0) {
109 /* Magic flag for com_err values. */
110 status = g_display_com_err_status(minor_status, m_status, status_string);
111 if (status != GSS_S_COMPLETE)
112 map_errcode(minor_status);
113 return status;
114 }
115 mech_type = &m_oid;
116 status_value = m_status;
117 }
118
119 mech = gssint_get_mechanism (mech_type);
120
121 if (mech && mech->gss_display_status) {
122 OM_uint32 r;
123
124 r = mech->gss_display_status(minor_status,
125 status_value, status_type, mech_type,
126 message_context, status_string);
127 /* How's this for weird? If we get an error returning the
128 mechanism-specific error code, we save away the
129 mechanism-specific error code describing the error. */
130 if (r != GSS_S_COMPLETE)
131 map_error(minor_status, mech);
132 return r;
133 }
134
135 if (!mech)
136 return (GSS_S_BAD_MECH);
137
138 return (GSS_S_UNAVAILABLE);
139 }
140
141 /*
142 * function to map the major error codes
143 * it uses case statements so that the strings could be wrapped by gettext
144 * msgCtxt is interpreted as:
145 * 0 - first call
146 * 1 - routine error
147 * >= 2 - the supplementary error code bit shifted by 1
148 */
149 static OM_uint32
displayMajor(status,msgCtxt,outStr)150 displayMajor(status, msgCtxt, outStr)
151 OM_uint32 status;
152 OM_uint32 *msgCtxt;
153 gss_buffer_t outStr;
154 {
155 OM_uint32 oneVal, mask = 0x1, currErr;
156 char *errStr = NULL;
157 int i, haveErr = 0;
158
159 /* take care of the success value first */
160 if (status == GSS_S_COMPLETE)
161 errStr = _("The routine completed successfully");
162 else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
163 switch (oneVal) {
164 case GSS_S_CALL_INACCESSIBLE_READ:
165 errStr = _("A required input parameter could not be "
166 "read");
167 break;
168
169 case GSS_S_CALL_INACCESSIBLE_WRITE:
170 errStr = _("A required output parameter could not be "
171 "written");
172 break;
173
174 case GSS_S_CALL_BAD_STRUCTURE:
175 errStr = _("A parameter was malformed");
176 break;
177
178 default:
179 errStr = _("An invalid status code was supplied");
180 break;
181 }
182
183 /* we now need to determine new value of msgCtxt */
184 if (GSS_ROUTINE_ERROR(status))
185 *msgCtxt = 1;
186 else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
187 *msgCtxt = (OM_uint32)(oneVal << 1);
188 else
189 *msgCtxt = 0;
190
191 } else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
192 (oneVal = GSS_ROUTINE_ERROR(status))) {
193 switch (oneVal) {
194 case GSS_S_BAD_MECH:
195 errStr = _("An unsupported mechanism was requested");
196 break;
197
198 case GSS_S_BAD_NAME:
199 errStr = _("An invalid name was supplied");
200 break;
201
202 case GSS_S_BAD_NAMETYPE:
203 errStr = _("A supplied name was of an unsupported "
204 "type");
205 break;
206
207 case GSS_S_BAD_BINDINGS:
208 errStr = _("Incorrect channel bindings were supplied");
209 break;
210
211 case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
212 errStr = _("A token had an invalid Message Integrity "
213 "Check (MIC)");
214 break;
215
216 case GSS_S_NO_CRED:
217 errStr = _("No credentials were supplied, or the "
218 "credentials were unavailable or "
219 "inaccessible");
220 break;
221
222 case GSS_S_NO_CONTEXT:
223 errStr = _("No context has been established");
224 break;
225
226 case GSS_S_DEFECTIVE_TOKEN:
227 errStr = _("Invalid token was supplied");
228 break;
229
230 case GSS_S_DEFECTIVE_CREDENTIAL:
231 errStr = _("Invalid credential was supplied");
232 break;
233
234 case GSS_S_CREDENTIALS_EXPIRED:
235 errStr = _("The referenced credential has expired");
236 break;
237
238 case GSS_S_CONTEXT_EXPIRED:
239 errStr = _("The referenced context has expired");
240 break;
241
242 case GSS_S_FAILURE:
243 errStr = _("Unspecified GSS failure. Minor code "
244 "may provide more information");
245 break;
246
247 case GSS_S_BAD_QOP:
248 errStr = _("The quality-of-protection (QOP) "
249 "requested could not be provided");
250 break;
251
252 case GSS_S_UNAUTHORIZED:
253 errStr = _("The operation is forbidden by local "
254 "security policy");
255 break;
256
257 case GSS_S_UNAVAILABLE:
258 errStr = _("The operation or option is not "
259 "available or unsupported");
260 break;
261
262 case GSS_S_DUPLICATE_ELEMENT:
263 errStr = _("The requested credential element "
264 "already exists");
265 break;
266
267 case GSS_S_NAME_NOT_MN:
268 errStr = _("The provided name was not mechanism "
269 "specific (MN)");
270 break;
271
272 case GSS_S_BAD_STATUS:
273 default:
274 errStr = _("An invalid status code was supplied");
275 }
276
277 /* we must determine if the caller should call us again */
278 if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
279 *msgCtxt = (OM_uint32)(oneVal << 1);
280 else
281 *msgCtxt = 0;
282
283 } else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
284 (oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
285 /*
286 * if msgCtxt is not 0, then it should encode
287 * the supplementary error code we should be printing
288 */
289 if (*msgCtxt >= 2)
290 oneVal = (OM_uint32) (*msgCtxt) >> 1;
291 else
292 oneVal = GSS_SUPPLEMENTARY_INFO(status);
293
294 /* we display the errors LSB first */
295 for (i = 0; i < 16; i++) {
296 if (oneVal & mask) {
297 haveErr = 1;
298 break;
299 }
300 mask <<= 1;
301 }
302
303 /* isolate the bit or if not found set to illegal value */
304 if (haveErr)
305 currErr = oneVal & mask;
306 else
307 currErr = 1 << 17; /* illegal value */
308
309 switch (currErr) {
310 case GSS_S_CONTINUE_NEEDED:
311 errStr = _("The routine must be called again to "
312 "complete its function");
313 break;
314
315 case GSS_S_DUPLICATE_TOKEN:
316 errStr = _("The token was a duplicate of an earlier "
317 "token");
318 break;
319
320 case GSS_S_OLD_TOKEN:
321 errStr = _("The token's validity period has expired");
322 break;
323
324 case GSS_S_UNSEQ_TOKEN:
325 errStr = _("A later token has already been processed");
326 break;
327
328 case GSS_S_GAP_TOKEN:
329 errStr = _("An expected per-message token was not "
330 "received");
331 break;
332
333 default:
334 errStr = _("An invalid status code was supplied");
335 }
336
337 /*
338 * we must check if there is any other supplementary errors
339 * if found, then turn off current bit, and store next value
340 * in msgCtxt shifted by 1 bit
341 */
342 if (!haveErr)
343 *msgCtxt = 0;
344 else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
345 *msgCtxt = (OM_uint32)
346 ((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
347 else
348 *msgCtxt = 0;
349 }
350
351 if (errStr == NULL)
352 errStr = "An invalid status code was supplied";
353
354 /* now copy the status code and return to caller */
355 outStr->length = strlen(errStr);
356 outStr->value = gssalloc_strdup(errStr);
357 if (outStr->value == NULL) {
358 outStr->length = 0;
359 return (GSS_S_FAILURE);
360 }
361
362 return (GSS_S_COMPLETE);
363 } /* displayMajor */
364