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