/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" /* * glue routine for gss_acquire_cred */ #include #include #include #ifdef HAVE_STDLIB_H #include #endif #include #include #include /* local functions */ static gss_OID_set create_actual_mechs(const gss_OID, int); static gss_OID_set create_actual_mechs(mechs_array, count) const gss_OID mechs_array; int count; { gss_OID_set actual_mechs; int i; OM_uint32 minor; actual_mechs = (gss_OID_set) malloc(sizeof (gss_OID_set_desc)); if (!actual_mechs) return (NULL); actual_mechs->elements = (gss_OID) malloc(sizeof (gss_OID_desc) * count); if (!actual_mechs->elements) { free(actual_mechs); return (NULL); } actual_mechs->count = 0; for (i = 0; i < count; i++) { actual_mechs->elements[i].elements = (void *) malloc(mechs_array[i].length); if (actual_mechs->elements[i].elements == NULL) { (void) gss_release_oid_set(&minor, &actual_mechs); return (NULL); } g_OID_copy(&actual_mechs->elements[i], &mechs_array[i]); actual_mechs->count++; } return (actual_mechs); } OM_uint32 gss_acquire_cred_with_password(minor_status, desired_name, password, time_req, desired_mechs, cred_usage, output_cred_handle, actual_mechs, time_rec) OM_uint32 * minor_status; const gss_name_t desired_name; const gss_buffer_t password; OM_uint32 time_req; const gss_OID_set desired_mechs; int cred_usage; gss_cred_id_t *output_cred_handle; gss_OID_set * actual_mechs; OM_uint32 * time_rec; { OM_uint32 major = GSS_S_FAILURE; OM_uint32 initTimeOut, acceptTimeOut, outTime = GSS_C_INDEFINITE; gss_OID_set_desc default_OID_set; gss_OID_set mechs; gss_OID_desc default_OID; gss_mechanism mech; int i; gss_union_cred_t creds; /* start by checking parameters */ if (minor_status == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); *minor_status = 0; if (desired_name == GSS_C_NO_NAME) return (GSS_S_BAD_NAME); if (output_cred_handle == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); *output_cred_handle = GSS_C_NO_CREDENTIAL; /* Set output parameters to NULL for now */ if (actual_mechs != NULL) *actual_mechs = GSS_C_NULL_OID_SET; if (time_rec) *time_rec = 0; /* * if desired_mechs equals GSS_C_NULL_OID_SET, then pick an * appropriate default. We use the first mechanism in the * mechansim list as the default. This set is created with * statics thus needs not be freed */ if (desired_mechs == GSS_C_NULL_OID_SET) { mech = __gss_get_mechanism(GSS_C_NULL_OID); if (mech == NULL) return (GSS_S_BAD_MECH); mechs = &default_OID_set; default_OID_set.count = 1; default_OID_set.elements = &default_OID; default_OID.length = mech->mech_type.length; default_OID.elements = mech->mech_type.elements; } else mechs = desired_mechs; if (mechs->count == 0) return (GSS_S_BAD_MECH); /* allocate the output credential structure */ creds = (gss_union_cred_t)malloc(sizeof (gss_union_cred_desc)); if (creds == NULL) return (GSS_S_FAILURE); /* initialize to 0s */ (void) memset(creds, 0, sizeof (gss_union_cred_desc)); /* for each requested mech attempt to obtain a credential */ for (i = 0; i < mechs->count; i++) { major = gss_add_cred_with_password(minor_status, (gss_cred_id_t)creds, desired_name, &mechs->elements[i], password, cred_usage, time_req, time_req, NULL, NULL, &initTimeOut, &acceptTimeOut); if (major == GSS_S_COMPLETE) { /* update the credential's time */ if (cred_usage == GSS_C_ACCEPT) { if (outTime > acceptTimeOut) outTime = acceptTimeOut; } else if (cred_usage == GSS_C_INITIATE) { if (outTime > initTimeOut) outTime = initTimeOut; } else { /* * time_rec is the lesser of the * init/accept times */ if (initTimeOut > acceptTimeOut) outTime = (outTime > acceptTimeOut) ? acceptTimeOut : outTime; else outTime = (outTime > initTimeOut) ? initTimeOut : outTime; } } } /* for */ /* ensure that we have at least one credential element */ if (creds->count < 1) { free(creds); return (major); } /* * fill in output parameters * setup the actual mechs output parameter */ if (actual_mechs != NULL) { if ((*actual_mechs = create_actual_mechs(creds->mechs_array, creds->count)) == NULL) { (void) gss_release_cred(minor_status, (gss_cred_id_t *)&creds); *minor_status = 0; return (GSS_S_FAILURE); } } if (time_rec) *time_rec = outTime; *output_cred_handle = (gss_cred_id_t)creds; return (GSS_S_COMPLETE); } /* V2 INTERFACE */ OM_uint32 gss_add_cred_with_password(minor_status, input_cred_handle, desired_name, desired_mech, password, cred_usage, initiator_time_req, acceptor_time_req, output_cred_handle, actual_mechs, initiator_time_rec, acceptor_time_rec) OM_uint32 *minor_status; const gss_cred_id_t input_cred_handle; const gss_name_t desired_name; const gss_OID desired_mech; const gss_buffer_t password; gss_cred_usage_t cred_usage; OM_uint32 initiator_time_req; OM_uint32 acceptor_time_req; gss_cred_id_t *output_cred_handle; gss_OID_set *actual_mechs; OM_uint32 *initiator_time_rec; OM_uint32 *acceptor_time_rec; { OM_uint32 status, time_req, time_rec, temp_minor_status; gss_mechanism mech; gss_mechanism_ext mech_ext; gss_union_name_t union_name = NULL; gss_union_cred_t union_cred, new_union_cred; gss_name_t internal_name = GSS_C_NO_NAME; gss_name_t allocated_name = GSS_C_NO_NAME; gss_cred_id_t cred = NULL; gss_OID new_mechs_array = NULL; gss_cred_id_t *new_cred_array = NULL; /* check input parameters */ if (minor_status == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE); *minor_status = 0; if (input_cred_handle == GSS_C_NO_CREDENTIAL && output_cred_handle == NULL) return (GSS_S_CALL_INACCESSIBLE_WRITE | GSS_S_NO_CRED); if (desired_name == GSS_C_NO_NAME) return (GSS_S_BAD_NAME); union_name = (gss_union_name_t)desired_name; if (output_cred_handle != NULL) *output_cred_handle = GSS_C_NO_CREDENTIAL; if (actual_mechs != NULL) *actual_mechs = NULL; if (acceptor_time_rec != NULL) *acceptor_time_rec = 0; if (initiator_time_rec != NULL) *initiator_time_rec = 0; if ((mech = __gss_get_mechanism(desired_mech)) == NULL) return (GSS_S_BAD_MECH); if ((mech_ext = __gss_get_mechanism_ext(desired_mech)) == NULL || mech_ext->gss_acquire_cred_with_password == NULL) return (GSS_S_UNAVAILABLE); if (input_cred_handle == GSS_C_NO_CREDENTIAL) { union_cred = malloc(sizeof (gss_union_cred_desc)); if (union_cred == NULL) return (GSS_S_FAILURE); (void) memset(union_cred, 0, sizeof (gss_union_cred_desc)); } else { union_cred = (gss_union_cred_t)input_cred_handle; if (__gss_get_mechanism_cred(union_cred, desired_mech) != GSS_C_NO_CREDENTIAL) return (GSS_S_DUPLICATE_ELEMENT); } /* May need to create an MN */ if (union_name->mech_type && g_OID_equal(union_name->mech_type, &mech->mech_type)) internal_name = union_name->mech_name; else { if (__gss_import_internal_name(minor_status, &mech->mech_type, union_name, &allocated_name) != GSS_S_COMPLETE) return (GSS_S_BAD_NAME); internal_name = allocated_name; } if (cred_usage == GSS_C_ACCEPT) time_req = acceptor_time_req; else if (cred_usage == GSS_C_INITIATE) time_req = initiator_time_req; else if (cred_usage == GSS_C_BOTH) time_req = (acceptor_time_req > initiator_time_req) ? acceptor_time_req : initiator_time_req; status = mech_ext->gss_acquire_cred_with_password(mech->context, minor_status, internal_name, password, time_req, GSS_C_NULL_OID_SET, cred_usage, &cred, NULL, &time_rec); if (status != GSS_S_COMPLETE) goto errout; /* May need to set credential auxinfo strucutre */ if (union_cred->auxinfo.creation_time == 0) { union_cred->auxinfo.creation_time = time(NULL); union_cred->auxinfo.time_rec = time_rec; union_cred->auxinfo.cred_usage = cred_usage; if ((status = mech->gss_display_name(mech->context, &temp_minor_status, internal_name, &union_cred->auxinfo.name, &union_cred->auxinfo.name_type)) != GSS_S_COMPLETE) goto errout; } /* Now add the new credential elements */ new_mechs_array = (gss_OID) malloc(sizeof (gss_OID_desc) * (union_cred->count+1)); new_cred_array = (gss_cred_id_t *) malloc(sizeof (gss_cred_id_t) * (union_cred->count+1)); if (!new_mechs_array || !new_cred_array) { status = GSS_S_FAILURE; goto errout; } if (acceptor_time_rec) if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) *acceptor_time_rec = time_rec; if (initiator_time_rec) if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) *initiator_time_rec = time_rec; /* * OK, expand the mechanism array and the credential array */ (void) memcpy(new_mechs_array, union_cred->mechs_array, sizeof (gss_OID_desc) * union_cred->count); (void) memcpy(new_cred_array, union_cred->cred_array, sizeof (gss_cred_id_t) * union_cred->count); new_cred_array[union_cred->count] = cred; if ((new_mechs_array[union_cred->count].elements = malloc(mech->mech_type.length)) == NULL) goto errout; g_OID_copy(&new_mechs_array[union_cred->count], &mech->mech_type); if (actual_mechs) { *actual_mechs = create_actual_mechs(new_mechs_array, union_cred->count + 1); if (*actual_mechs == NULL) { free(new_mechs_array[union_cred->count].elements); goto errout; } } if (output_cred_handle == NULL) { free(union_cred->mechs_array); free(union_cred->cred_array); new_union_cred = union_cred; } else { new_union_cred = malloc(sizeof (gss_union_cred_desc)); if (new_union_cred == NULL) { free(new_mechs_array[union_cred->count].elements); goto errout; } *new_union_cred = *union_cred; *output_cred_handle = (gss_cred_id_t)new_union_cred; } new_union_cred->mechs_array = new_mechs_array; new_union_cred->cred_array = new_cred_array; new_union_cred->count++; /* We're done with the internal name. Free it if we allocated it. */ if (allocated_name) (void) __gss_release_internal_name(&temp_minor_status, &mech->mech_type, &allocated_name); return (GSS_S_COMPLETE); errout: if (new_mechs_array) free(new_mechs_array); if (new_cred_array) free(new_cred_array); if (cred != NULL && mech->gss_release_cred) mech->gss_release_cred(mech->context, &temp_minor_status, &cred); if (allocated_name) (void) __gss_release_internal_name(&temp_minor_status, &mech->mech_type, &allocated_name); if (input_cred_handle == GSS_C_NO_CREDENTIAL && union_cred) { if (union_cred->auxinfo.name.value) free(union_cred->auxinfo.name.value); free(union_cred); } return (status); }