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