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