xref: /freebsd/crypto/krb5/src/lib/gssapi/mechglue/g_dsp_status.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
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