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 for gss_acquire_cred
     28  */
     29 #include <mechglueP.h>
     30 #include <stdio.h>
     31 #ifdef HAVE_STDLIB_H
     32 #include <stdlib.h>
     33 #endif
     34 #include <string.h>
     35 #include <errno.h>
     36 #include <time.h>
     37 
     38 /* local functions */
     39 static gss_OID_set create_actual_mechs(const gss_OID, int);
     40 
     41 static gss_OID_set
     42 create_actual_mechs(mechs_array, count)
     43 	const gss_OID	mechs_array;
     44 	int count;
     45 {
     46 	gss_OID_set 	actual_mechs;
     47 	int		i;
     48 	OM_uint32	minor;
     49 
     50 	actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc));
     51 	if (!actual_mechs)
     52 		return (NULL);
     53 
     54 	actual_mechs->elements = (gss_OID)
     55 		malloc(sizeof (gss_OID_desc) * count);
     56 	if (!actual_mechs->elements) {
     57 		free(actual_mechs);
     58 		return (NULL);
     59 	}
     60 
     61 	actual_mechs->count = 0;
     62 
     63 	for (i = 0; i < count; i++) {
     64 		actual_mechs->elements[i].elements = (void *)
     65 			malloc(mechs_array[i].length);
     66 		if (actual_mechs->elements[i].elements == NULL) {
     67 			(void) gss_release_oid_set(&minor, &actual_mechs);
     68 			return (NULL);
     69 		}
     70 		g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]);
     71 		actual_mechs->count++;
     72 	}
     73 
     74 	return (actual_mechs);
     75 }
     76 
     77 static OM_uint32
     78 val_acq_cred_args(
     79 	OM_uint32 *minor_status,
     80 	gss_cred_id_t *output_cred_handle,
     81 	gss_OID_set *actual_mechs,
     82 	OM_uint32 *time_rec)
     83 {
     84 
     85 	/* Initialize outputs. */
     86 
     87 	if (minor_status != NULL)
     88 		*minor_status = 0;
     89 
     90 	if (output_cred_handle != NULL)
     91 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
     92 
     93 	if (actual_mechs != NULL)
     94 		*actual_mechs = GSS_C_NULL_OID_SET;
     95 
     96 	if (time_rec != NULL)
     97 		*time_rec = 0;
     98 
     99 	/* Validate arguments. */
    100 
    101 	if (minor_status == NULL)
    102 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    103 
    104 	if (output_cred_handle == NULL)
    105 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    106 
    107 	return (GSS_S_COMPLETE);
    108 }
    109 
    110 OM_uint32
    111 gss_acquire_cred(minor_status,
    112 			desired_name,
    113 			time_req,
    114 			desired_mechs,
    115 			cred_usage,
    116 			output_cred_handle,
    117 			actual_mechs,
    118 			time_rec)
    119 
    120 OM_uint32 *		minor_status;
    121 const gss_name_t	desired_name;
    122 OM_uint32		time_req;
    123 const gss_OID_set	desired_mechs;
    124 int			cred_usage;
    125 gss_cred_id_t 		*output_cred_handle;
    126 gss_OID_set *		actual_mechs;
    127 OM_uint32 *		time_rec;
    128 
    129 {
    130 	OM_uint32 major = GSS_S_FAILURE;
    131 	OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE;
    132 	gss_OID_set_desc default_OID_set;
    133 	gss_OID_set mechs;
    134 	gss_OID_desc default_OID;
    135 	gss_mechanism mech;
    136 	int i;
    137 	gss_union_cred_t creds;
    138 
    139 	major = val_acq_cred_args(minor_status,
    140 				output_cred_handle,
    141 				actual_mechs,
    142 				time_rec);
    143 	if (major != GSS_S_COMPLETE)
    144 		return (major);
    145 
    146 	/* Initial value needed below. */
    147 	major = GSS_S_FAILURE;
    148 
    149 	/*
    150 	 * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an
    151 	 * appropriate default.  We use the first mechanism in the
    152 	 * mechansim list as the default. This set is created with
    153 	 * statics thus needs not be freed
    154 	 */
    155 	if (desired_mechs == GSS_C_NULL_OID_SET) {
    156 		mech = __gss_get_mechanism(NULL);
    157 		if (mech == NULL)
    158 			return (GSS_S_BAD_MECH);
    159 
    160 		mechs = &default_OID_set;
    161 		default_OID_set.count = 1;
    162 		default_OID_set.elements = &default_OID;
    163 		default_OID.length = mech->mech_type.length;
    164 		default_OID.elements = mech->mech_type.elements;
    165 	} else
    166 		mechs = desired_mechs;
    167 
    168 	if (mechs->count == NULL)
    169 		return (GSS_S_BAD_MECH);
    170 
    171 	/* allocate the output credential structure */
    172 	creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc));
    173 	if (creds == NULL)
    174 		return (GSS_S_FAILURE);
    175 
    176 	/* initialize to 0s */
    177 	(void) memset(creds, 0, sizeof (gss_union_cred_desc));
    178 
    179 	/* for each requested mech attempt to obtain a credential */
    180 	for (i = 0; i < mechs->count; i++) {
    181 		major = gss_add_cred(minor_status, (gss_cred_id_t)creds,
    182 				desired_name,
    183 				&mechs->elements[i],
    184 				cred_usage, time_req, time_req, NULL,
    185 				NULL, &initTimeOut, &acceptTimeOut);
    186 		if (major == GSS_S_COMPLETE) {
    187 			/* update the credential's time */
    188 			if (cred_usage == GSS_C_ACCEPT) {
    189 				if (outTime > acceptTimeOut)
    190 					outTime = acceptTimeOut;
    191 			} else if (cred_usage == GSS_C_INITIATE) {
    192 				if (outTime > initTimeOut)
    193 					outTime = initTimeOut;
    194 			} else {
    195 				/*
    196 				 * time_rec is the lesser of the
    197 				 * init/accept times
    198 				 */
    199 				if (initTimeOut > acceptTimeOut)
    200 					outTime = (outTime > acceptTimeOut) ?
    201 						acceptTimeOut : outTime;
    202 				else
    203 					outTime = (outTime > initTimeOut) ?
    204 						initTimeOut : outTime;
    205 			}
    206 		}
    207 	} /* for */
    208 
    209 	/* ensure that we have at least one credential element */
    210 	if (creds->count < 1) {
    211 		free(creds);
    212 		return (major);
    213 	}
    214 
    215 	/*
    216 	 * fill in output parameters
    217 	 * setup the actual mechs output parameter
    218 	 */
    219 	if (actual_mechs != NULL) {
    220 		if ((*actual_mechs = create_actual_mechs(creds->mechs_array,
    221 					creds->count)) == NULL) {
    222 			(void) gss_release_cred(minor_status,
    223 				(gss_cred_id_t *)&creds);
    224 			*minor_status = 0;
    225 			return (GSS_S_FAILURE);
    226 		}
    227 	}
    228 
    229 	if (time_rec)
    230 		*time_rec = outTime;
    231 
    232 
    233 	*output_cred_handle = (gss_cred_id_t)creds;
    234 	return (GSS_S_COMPLETE);
    235 }
    236 
    237 static OM_uint32
    238 val_add_cred_args(
    239 	OM_uint32 *minor_status,
    240 	gss_cred_id_t input_cred_handle,
    241 	gss_cred_id_t *output_cred_handle,
    242 	gss_OID_set *actual_mechs,
    243 	OM_uint32 *initiator_time_rec,
    244 	OM_uint32 *acceptor_time_rec)
    245 {
    246 
    247 	/* Initialize outputs. */
    248 
    249 	if (minor_status != NULL)
    250 		*minor_status = 0;
    251 
    252 	if (output_cred_handle != NULL)
    253 		*output_cred_handle = GSS_C_NO_CREDENTIAL;
    254 
    255 	if (actual_mechs != NULL)
    256 		*actual_mechs = GSS_C_NO_OID_SET;
    257 
    258 	if (acceptor_time_rec != NULL)
    259 		*acceptor_time_rec = 0;
    260 
    261 	if (initiator_time_rec != NULL)
    262 		*initiator_time_rec = 0;
    263 
    264 	/* Validate arguments. */
    265 
    266 	if (minor_status == NULL)
    267 		return (GSS_S_CALL_INACCESSIBLE_WRITE);
    268 
    269 	if (input_cred_handle == GSS_C_NO_CREDENTIAL &&
    270 		output_cred_handle == NULL)
    271 
    272 		return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED);
    273 
    274 	return (GSS_S_COMPLETE);
    275 }
    276 
    277 /* V2 INTERFACE */
    278 OM_uint32
    279 gss_add_cred(minor_status, input_cred_handle,
    280 			desired_name, desired_mech, cred_usage,
    281 			initiator_time_req, acceptor_time_req,
    282 			output_cred_handle, actual_mechs,
    283 			initiator_time_rec, acceptor_time_rec)
    284 	OM_uint32		*minor_status;
    285 	const gss_cred_id_t	input_cred_handle;
    286 	const gss_name_t	desired_name;
    287 	const gss_OID		desired_mech;
    288 	gss_cred_usage_t	cred_usage;
    289 	OM_uint32		initiator_time_req;
    290 	OM_uint32		acceptor_time_req;
    291 	gss_cred_id_t		*output_cred_handle;
    292 	gss_OID_set		*actual_mechs;
    293 	OM_uint32		*initiator_time_rec;
    294 	OM_uint32		*acceptor_time_rec;
    295 {
    296 	OM_uint32		status, time_req, time_rec, temp_minor_status;
    297 	gss_mechanism 		mech;
    298 	gss_union_name_t	union_name = NULL;
    299 	gss_union_cred_t	union_cred, new_union_cred;
    300 	gss_name_t		internal_name = GSS_C_NO_NAME;
    301 	gss_name_t		allocated_name = GSS_C_NO_NAME;
    302 	gss_cred_id_t		cred = NULL;
    303 	gss_OID			new_mechs_array = NULL;
    304 	gss_cred_id_t		*new_cred_array = NULL;
    305 
    306 	status = val_add_cred_args(minor_status,
    307 				input_cred_handle,
    308 				output_cred_handle,
    309 				actual_mechs,
    310 				initiator_time_rec,
    311 				acceptor_time_rec);
    312 	if (status != GSS_S_COMPLETE)
    313 		return (status);
    314 
    315 	mech = __gss_get_mechanism(desired_mech);
    316 	if (!mech)
    317 		return (GSS_S_BAD_MECH);
    318 	else if (!mech->gss_acquire_cred)
    319 		return (GSS_S_UNAVAILABLE);
    320 
    321 	if (input_cred_handle == GSS_C_NO_CREDENTIAL) {
    322 		union_cred = malloc(sizeof (gss_union_cred_desc));
    323 		if (union_cred == NULL)
    324 			return (GSS_S_FAILURE);
    325 
    326 		(void) memset(union_cred, 0, sizeof (gss_union_cred_desc));
    327 	} else {
    328 		/* Input Cred is non-NULL */
    329 		union_cred = (gss_union_cred_t)input_cred_handle;
    330 
    331 		if (__gss_get_mechanism_cred(union_cred, desired_mech) !=
    332 			GSS_C_NO_CREDENTIAL) {
    333 			status = GSS_S_DUPLICATE_ELEMENT;
    334 			goto errout;
    335 		}
    336 
    337 		/*
    338 		 * If no name was given, determine the name from the
    339 		 * existing credential.
    340 		 */
    341 		if (desired_name == GSS_C_NO_NAME) {
    342 			if (gss_import_name(minor_status,
    343 				&union_cred->auxinfo.name,
    344 				union_cred->auxinfo.name_type,
    345 				&allocated_name) == GSS_S_COMPLETE &&
    346 			    (gss_canonicalize_name(minor_status,
    347 					allocated_name,
    348 					&mech->mech_type,
    349 					NULL) == GSS_S_COMPLETE)) {
    350 				internal_name = allocated_name;
    351 			}
    352 		} /* else, get the name from the desired_name below */
    353 	}
    354 	if (desired_name != GSS_C_NO_NAME) {
    355 		/* may need to create a mechanism specific name */
    356 		union_name = (gss_union_name_t)desired_name;
    357 
    358 		if (union_name->mech_type &&
    359 			g_OID_equal(union_name->mech_type,
    360 					&mech->mech_type))
    361 			internal_name = union_name->mech_name;
    362 		else {
    363 			if (__gss_import_internal_name(minor_status,
    364 				&mech->mech_type, union_name,
    365 				&allocated_name) != GSS_S_COMPLETE) {
    366 				status = GSS_S_BAD_NAME;
    367 				goto errout;
    368 			}
    369 			internal_name = allocated_name;
    370 		}
    371 	}
    372 
    373 	if (cred_usage == GSS_C_ACCEPT)
    374 		time_req = acceptor_time_req;
    375 	else if (cred_usage == GSS_C_INITIATE)
    376 		time_req = initiator_time_req;
    377 	else if (cred_usage == GSS_C_BOTH)
    378 		time_req = (acceptor_time_req > initiator_time_req) ?
    379 			acceptor_time_req : initiator_time_req;
    380 
    381 	status = mech->gss_acquire_cred(mech->context, minor_status,
    382 				internal_name, time_req,
    383 				GSS_C_NULL_OID_SET, cred_usage,
    384 				&cred, NULL, &time_rec);
    385 
    386 	if (status != GSS_S_COMPLETE)
    387 		goto errout;
    388 
    389 	/* may need to set credential auxinfo structure */
    390 	if (union_cred->auxinfo.creation_time == 0) {
    391 		union_cred->auxinfo.creation_time = time(NULL);
    392 		union_cred->auxinfo.time_rec = time_rec;
    393 		union_cred->auxinfo.cred_usage = cred_usage;
    394 
    395 	/*
    396 	 * If internal_name is GSS_C_NO_NAME a cred with no associated
    397 	 * name was requested: don't set auxinfo.name or auxinfo.name_type.
    398 	 */
    399 		if (internal_name != GSS_C_NO_NAME) {
    400 			if ((status = mech->gss_display_name(mech->context,
    401 					&temp_minor_status, internal_name,
    402 					&union_cred->auxinfo.name,
    403 					&union_cred->auxinfo.name_type)) !=
    404 				GSS_S_COMPLETE)
    405 				goto errout;
    406 		}
    407 	}
    408 
    409 	/* now add the new credential elements */
    410 	new_mechs_array = (gss_OID)
    411 		malloc(sizeof (gss_OID_desc) * (union_cred->count+1));
    412 
    413 	new_cred_array = (gss_cred_id_t *)
    414 		malloc(sizeof (gss_cred_id_t) * (union_cred->count+1));
    415 
    416 	if (!new_mechs_array || !new_cred_array) {
    417 		status = GSS_S_FAILURE;
    418 		goto errout;
    419 	}
    420 
    421 	if (acceptor_time_rec)
    422 		if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH)
    423 			*acceptor_time_rec = time_rec;
    424 	if (initiator_time_rec)
    425 		if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH)
    426 			*initiator_time_rec = time_rec;
    427 
    428 	/*
    429 	 * OK, expand the mechanism array and the credential array
    430 	 */
    431 	(void) memcpy(new_mechs_array, union_cred->mechs_array,
    432 		sizeof (gss_OID_desc) * union_cred->count);
    433 	(void) memcpy(new_cred_array, union_cred->cred_array,
    434 		sizeof (gss_cred_id_t) * union_cred->count);
    435 
    436 	new_cred_array[union_cred->count] = cred;
    437 	if ((new_mechs_array[union_cred->count].elements =
    438 			malloc(mech->mech_type.length)) == NULL)
    439 		goto errout;
    440 
    441 	g_OID_copy(&new_mechs_array[union_cred->count],
    442 			&mech->mech_type);
    443 
    444 	if (actual_mechs) {
    445 		*actual_mechs = create_actual_mechs(new_mechs_array,
    446 					union_cred->count + 1);
    447 		if (*actual_mechs == NULL) {
    448 			free(new_mechs_array[union_cred->count].elements);
    449 			goto errout;
    450 		}
    451 	}
    452 
    453 	if (output_cred_handle == NULL) {
    454 		free(union_cred->mechs_array);
    455 		free(union_cred->cred_array);
    456 		new_union_cred = union_cred;
    457 	} else {
    458 		new_union_cred = malloc(sizeof (gss_union_cred_desc));
    459 		if (new_union_cred == NULL) {
    460 			free(new_mechs_array[union_cred->count].elements);
    461 			goto errout;
    462 		}
    463 		*new_union_cred = *union_cred;
    464 		*output_cred_handle = (gss_cred_id_t)new_union_cred;
    465 	}
    466 
    467 	new_union_cred->mechs_array = new_mechs_array;
    468 	new_union_cred->cred_array = new_cred_array;
    469 	new_union_cred->count++;
    470 
    471 	/* We're done with the internal name. Free it if we allocated it. */
    472 
    473 	if (allocated_name)
    474 		(void) __gss_release_internal_name(&temp_minor_status,
    475 					&mech->mech_type,
    476 					&allocated_name);
    477 
    478 	return (GSS_S_COMPLETE);
    479 
    480 errout:
    481 	if (new_mechs_array)
    482 		free(new_mechs_array);
    483 	if (new_cred_array)
    484 		free(new_cred_array);
    485 
    486 	if (cred != NULL && mech->gss_release_cred)
    487 		mech->gss_release_cred(mech->context,
    488 				&temp_minor_status, &cred);
    489 
    490 	if (allocated_name)
    491 		(void) __gss_release_internal_name(&temp_minor_status,
    492 					&mech->mech_type,
    493 					&allocated_name);
    494 
    495 	if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) {
    496 		if (union_cred->auxinfo.name.value)
    497 			free(union_cred->auxinfo.name.value);
    498 		free(union_cred);
    499 	}
    500 
    501 	return (status);
    502 }
    503