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