Home | History | Annotate | Download | only in libgss
      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