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 (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