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