xref: /illumos-gate/usr/src/lib/libgss/g_dsp_status.c (revision 8eea8e29)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *  glue routine gss_display_status
31  *
32  */
33 
34 #include <mechglueP.h>
35 #include <stdio.h>
36 #ifdef HAVE_STDLIB_H
37 #include <stdlib.h>
38 #endif
39 #include <string.h>
40 #include <libintl.h>
41 #include <errno.h>
42 
43 #ifndef TEXT_DOMAIN
44 #error TEXT_DOMAIN not defined
45 #endif
46 
47 /* local function */
48 static OM_uint32 displayMajor(OM_uint32, OM_uint32 *, gss_buffer_t);
49 
50 
51 OM_uint32
52 gss_display_status(minor_status,
53 			status_value,
54 			status_type,
55 			req_mech_type,
56 			message_context,
57 			status_string)
58 
59 OM_uint32 *minor_status;
60 OM_uint32 status_value;
61 int status_type;
62 const gss_OID req_mech_type;
63 OM_uint32 *message_context;
64 gss_buffer_t status_string;
65 {
66 	gss_OID mech_type = (gss_OID) req_mech_type;
67 	gss_mechanism mech;
68 
69 	/* check the input parameters */
70 	if (!minor_status)
71 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
72 
73 	*minor_status = 0;
74 
75 	if (!message_context || status_string == NULL)
76 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
77 
78 	status_string->length = 0;
79 	status_string->value = NULL;
80 
81 	/* we handle major status codes, and the mechs do the minor */
82 	if (status_type == GSS_C_GSS_CODE)
83 		return (displayMajor(status_value, message_context,
84 				status_string));
85 
86 	/*
87 	 * must be the minor status - let mechs do the work
88 	 * select the appropriate underlying mechanism routine and
89 	 * call it.
90 	 */
91 	mech = __gss_get_mechanism(mech_type);
92 
93 	if (mech && mech->gss_display_status) {
94 		if (mech_type == GSS_C_NULL_OID)
95 			mech_type = &mech->mech_type;
96 
97 		return (mech->gss_display_status(mech->context, minor_status,
98 				status_value, status_type, mech_type,
99 				message_context, status_string));
100 	}
101 
102 	if (!mech)
103 		return (GSS_S_BAD_MECH);
104 
105 	return (GSS_S_UNAVAILABLE);
106 } /* gss_display_status */
107 
108 
109 /*
110  * function to map the major error codes
111  * it uses case statements so that the strings could be wrapped by gettext
112  * msgCtxt is interpreted as:
113  *	0 - first call
114  *	1 - routine error
115  *	>= 2 - the supplementary error code bit shifted by 1
116  */
117 static OM_uint32
118 displayMajor(status, msgCtxt, outStr)
119 OM_uint32 status;
120 OM_uint32 *msgCtxt;
121 gss_buffer_t outStr;
122 {
123 	OM_uint32 oneVal, mask = 0x1, currErr;
124 	char *errStr = NULL;
125 	int i, haveErr = 0;
126 
127 	/* take care of the success value first */
128 	if (status == GSS_S_COMPLETE)
129 		errStr = dgettext(TEXT_DOMAIN,
130 				"The routine completed successfully");
131 	else if (*msgCtxt == 0 && (oneVal = GSS_CALLING_ERROR(status))) {
132 		switch (oneVal) {
133 		case GSS_S_CALL_INACCESSIBLE_READ:
134 			errStr = dgettext(TEXT_DOMAIN,
135 					"A required input parameter"
136 					" could not be read");
137 			break;
138 
139 		case GSS_S_CALL_INACCESSIBLE_WRITE:
140 			errStr = dgettext(TEXT_DOMAIN,
141 					"A required output parameter"
142 					" could not be written");
143 			break;
144 
145 		case GSS_S_CALL_BAD_STRUCTURE:
146 			errStr = dgettext(TEXT_DOMAIN,
147 					"A parameter was malformed");
148 			break;
149 
150 		default:
151 			errStr = dgettext(TEXT_DOMAIN,
152 					"An invalid status code was supplied");
153 			break;
154 		}
155 
156 		/* we now need to determine new value of msgCtxt */
157 		if (GSS_ROUTINE_ERROR(status))
158 			*msgCtxt = 1;
159 		else if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
160 			*msgCtxt = (OM_uint32)(oneVal << 1);
161 		else
162 			*msgCtxt = 0;
163 
164 	} else if ((*msgCtxt == 0 || *msgCtxt == 1) &&
165 		(oneVal = GSS_ROUTINE_ERROR(status))) {
166 		switch (oneVal) {
167 		case GSS_S_BAD_MECH:
168 			errStr = dgettext(TEXT_DOMAIN,
169 					"An unsupported mechanism"
170 					" was requested");
171 			break;
172 
173 		case GSS_S_BAD_NAME:
174 			errStr = dgettext(TEXT_DOMAIN,
175 					"An invalid name was supplied");
176 			break;
177 
178 		case GSS_S_BAD_NAMETYPE:
179 			errStr = dgettext(TEXT_DOMAIN,
180 					"A supplied name was of an"
181 					" unsupported type");
182 			break;
183 
184 		case GSS_S_BAD_BINDINGS:
185 			errStr = dgettext(TEXT_DOMAIN,
186 					"Incorrect channel bindings"
187 					" were supplied");
188 			break;
189 
190 		case GSS_S_BAD_SIG: /* same as GSS_S_BAD_MIC: */
191 			errStr = dgettext(TEXT_DOMAIN,
192 					"A token had an invalid Message"
193 					" Integrity Check (MIC)");
194 			break;
195 
196 		case GSS_S_NO_CRED:
197 			errStr = dgettext(TEXT_DOMAIN,
198 					"No credentials were supplied, or the"
199 					" credentials were unavailable or"
200 					" inaccessible");
201 			break;
202 
203 		case GSS_S_NO_CONTEXT:
204 			errStr = dgettext(TEXT_DOMAIN,
205 					"No context has been established");
206 			break;
207 
208 		case GSS_S_DEFECTIVE_TOKEN:
209 			errStr = dgettext(TEXT_DOMAIN,
210 					"Invalid token was supplied");
211 			break;
212 
213 		case GSS_S_DEFECTIVE_CREDENTIAL:
214 			errStr = dgettext(TEXT_DOMAIN,
215 					"Invalid credential was supplied");
216 			break;
217 
218 		case GSS_S_CREDENTIALS_EXPIRED:
219 			errStr = dgettext(TEXT_DOMAIN,
220 					"The referenced credential has"
221 					" expired");
222 			break;
223 
224 		case GSS_S_CONTEXT_EXPIRED:
225 			errStr = dgettext(TEXT_DOMAIN,
226 					"The referenced context has expired");
227 			break;
228 
229 		case GSS_S_FAILURE:
230 			errStr = dgettext(TEXT_DOMAIN,
231 					"Unspecified GSS failure.  Minor code"
232 					" may provide more information");
233 			break;
234 
235 		case GSS_S_BAD_QOP:
236 			errStr = dgettext(TEXT_DOMAIN,
237 					"The quality-of-protection (QOP) "
238 					"requested could not be provided");
239 			break;
240 
241 		case GSS_S_UNAUTHORIZED:
242 			errStr = dgettext(TEXT_DOMAIN,
243 					"The operation is forbidden by local"
244 					" security policy");
245 			break;
246 
247 		case GSS_S_UNAVAILABLE:
248 			errStr = dgettext(TEXT_DOMAIN,
249 					"The operation or option is not"
250 					" available or unsupported");
251 			break;
252 
253 		case GSS_S_DUPLICATE_ELEMENT:
254 			errStr = dgettext(TEXT_DOMAIN,
255 					"The requested credential element"
256 					" already exists");
257 			break;
258 
259 		case GSS_S_NAME_NOT_MN:
260 			errStr = dgettext(TEXT_DOMAIN,
261 					"The provided name was not mechanism"
262 					" specific (MN)");
263 			break;
264 
265 		case GSS_S_BAD_STATUS:
266 		default:
267 			errStr = dgettext(TEXT_DOMAIN,
268 					"An invalid status code was supplied");
269 		}
270 
271 		/* we must determine if the caller should call us again */
272 		if ((oneVal = GSS_SUPPLEMENTARY_INFO(status)) != 0)
273 			*msgCtxt = (OM_uint32)(oneVal << 1);
274 		else
275 			*msgCtxt = 0;
276 
277 	} else if ((*msgCtxt == 0 || *msgCtxt >= 2) &&
278 		(oneVal = GSS_SUPPLEMENTARY_INFO(status))) {
279 		/*
280 		 * if msgCtxt is not 0, then it should encode
281 		 * the supplementary error code we should be printing
282 		 */
283 		if (*msgCtxt >= 2)
284 			oneVal = (OM_uint32) (*msgCtxt) >> 1;
285 		else
286 			oneVal = GSS_SUPPLEMENTARY_INFO(status);
287 
288 		/* we display the errors LSB first */
289 		for (i = 0; i < 16; i++) {
290 			if (oneVal & mask) {
291 				haveErr = 1;
292 				break;
293 			}
294 			mask <<= 1;
295 		}
296 
297 		/* isolate the bit or if not found set to illegal value */
298 		if (haveErr)
299 			currErr = oneVal & mask;
300 		else
301 			currErr = 1 << 17; /* illegal value */
302 
303 		switch (currErr) {
304 		case GSS_S_CONTINUE_NEEDED:
305 			errStr = dgettext(TEXT_DOMAIN,
306 					"The routine must be called again to"
307 					" complete its function");
308 			break;
309 
310 		case GSS_S_DUPLICATE_TOKEN:
311 			errStr = dgettext(TEXT_DOMAIN,
312 					"The token was a duplicate of an"
313 					" earlier token");
314 			break;
315 
316 		case GSS_S_OLD_TOKEN:
317 			errStr = dgettext(TEXT_DOMAIN,
318 					"The token's validity period"
319 					" has expired");
320 			break;
321 
322 		case GSS_S_UNSEQ_TOKEN:
323 			errStr = dgettext(TEXT_DOMAIN,
324 					"A later token has already been"
325 					" processed");
326 			break;
327 
328 		case GSS_S_GAP_TOKEN:
329 			errStr = dgettext(TEXT_DOMAIN,
330 					"An expected per-message token was"
331 					" not received");
332 			break;
333 
334 		default:
335 			errStr = dgettext(TEXT_DOMAIN,
336 					"An invalid status code was supplied");
337 		}
338 
339 		/*
340 		 * we must check if there is any other supplementary errors
341 		 * if found, then turn off current bit, and store next value
342 		 * in msgCtxt shifted by 1 bit
343 		 */
344 		if (!haveErr)
345 			*msgCtxt = 0;
346 		else if (GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask)
347 			*msgCtxt = (OM_uint32)
348 				((GSS_SUPPLEMENTARY_INFO(oneVal) ^ mask) << 1);
349 		else
350 			*msgCtxt = 0;
351 	}
352 
353 	if (errStr == NULL)
354 		errStr = dgettext(TEXT_DOMAIN,
355 				"An invalid status code was supplied");
356 
357 	/* now copy the status code and return to caller */
358 	outStr->length = strlen(errStr);
359 	outStr->value = malloc((size_t)outStr->length+1);
360 	if (outStr->value == NULL) {
361 		outStr->length = 0;
362 		return (GSS_S_FAILURE);
363 	}
364 
365 	(void) strcpy((char *)outStr->value, errStr);
366 	return (GSS_S_COMPLETE);
367 } /* displayMajor */
368