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