1178825Sdfr/* 2233294Sstas * Copyright (c) 2003 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 5178825Sdfr * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 9178825Sdfr * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 12178825Sdfr * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 16178825Sdfr * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 20178825Sdfr * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 32178825Sdfr */ 33178825Sdfr 34233294Sstas#include "gsskrb5_locl.h" 35178825Sdfr 36233294SstasOM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( 37178825Sdfr OM_uint32 *minor_status, 38178825Sdfr const gss_cred_id_t input_cred_handle, 39178825Sdfr const gss_name_t desired_name, 40178825Sdfr const gss_OID desired_mech, 41178825Sdfr gss_cred_usage_t cred_usage, 42178825Sdfr OM_uint32 initiator_time_req, 43178825Sdfr OM_uint32 acceptor_time_req, 44178825Sdfr gss_cred_id_t *output_cred_handle, 45178825Sdfr gss_OID_set *actual_mechs, 46178825Sdfr OM_uint32 *initiator_time_rec, 47178825Sdfr OM_uint32 *acceptor_time_rec) 48178825Sdfr{ 49178825Sdfr krb5_context context; 50178825Sdfr OM_uint32 ret, lifetime; 51178825Sdfr gsskrb5_cred cred, handle; 52178825Sdfr krb5_const_principal dname; 53178825Sdfr 54178825Sdfr handle = NULL; 55178825Sdfr cred = (gsskrb5_cred)input_cred_handle; 56178825Sdfr dname = (krb5_const_principal)desired_name; 57178825Sdfr 58178825Sdfr GSSAPI_KRB5_INIT (&context); 59178825Sdfr 60178825Sdfr if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { 61178825Sdfr *minor_status = 0; 62178825Sdfr return GSS_S_BAD_MECH; 63178825Sdfr } 64178825Sdfr 65178825Sdfr if (cred == NULL && output_cred_handle == NULL) { 66178825Sdfr *minor_status = 0; 67178825Sdfr return GSS_S_NO_CRED; 68178825Sdfr } 69178825Sdfr 70178825Sdfr if (cred == NULL) { /* XXX standard conformance failure */ 71178825Sdfr *minor_status = 0; 72178825Sdfr return GSS_S_NO_CRED; 73178825Sdfr } 74178825Sdfr 75233294Sstas /* check if requested output usage is compatible with output usage */ 76178825Sdfr if (output_cred_handle != NULL) { 77178825Sdfr HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); 78178825Sdfr if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { 79178825Sdfr HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 80178825Sdfr *minor_status = GSS_KRB5_S_G_BAD_USAGE; 81178825Sdfr return(GSS_S_FAILURE); 82178825Sdfr } 83178825Sdfr } 84233294Sstas 85178825Sdfr /* check that we have the same name */ 86178825Sdfr if (dname != NULL && 87233294Sstas krb5_principal_compare(context, dname, 88178825Sdfr cred->principal) != FALSE) { 89178825Sdfr if (output_cred_handle) 90178825Sdfr HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 91178825Sdfr *minor_status = 0; 92178825Sdfr return GSS_S_BAD_NAME; 93178825Sdfr } 94178825Sdfr 95178825Sdfr /* make a copy */ 96178825Sdfr if (output_cred_handle) { 97178825Sdfr krb5_error_code kret; 98178825Sdfr 99178825Sdfr handle = calloc(1, sizeof(*handle)); 100178825Sdfr if (handle == NULL) { 101178825Sdfr HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 102178825Sdfr *minor_status = ENOMEM; 103178825Sdfr return (GSS_S_FAILURE); 104178825Sdfr } 105178825Sdfr 106178825Sdfr handle->usage = cred_usage; 107178825Sdfr handle->lifetime = cred->lifetime; 108178825Sdfr handle->principal = NULL; 109178825Sdfr handle->keytab = NULL; 110178825Sdfr handle->ccache = NULL; 111178825Sdfr handle->mechanisms = NULL; 112178825Sdfr HEIMDAL_MUTEX_init(&handle->cred_id_mutex); 113233294Sstas 114178825Sdfr ret = GSS_S_FAILURE; 115178825Sdfr 116178825Sdfr kret = krb5_copy_principal(context, cred->principal, 117178825Sdfr &handle->principal); 118178825Sdfr if (kret) { 119178825Sdfr HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 120178825Sdfr free(handle); 121178825Sdfr *minor_status = kret; 122178825Sdfr return GSS_S_FAILURE; 123178825Sdfr } 124178825Sdfr 125178825Sdfr if (cred->keytab) { 126233294Sstas char *name = NULL; 127233294Sstas 128178825Sdfr ret = GSS_S_FAILURE; 129178825Sdfr 130233294Sstas kret = krb5_kt_get_full_name(context, cred->keytab, &name); 131178825Sdfr if (kret) { 132178825Sdfr *minor_status = kret; 133178825Sdfr goto failure; 134178825Sdfr } 135178825Sdfr 136178825Sdfr kret = krb5_kt_resolve(context, name, 137178825Sdfr &handle->keytab); 138233294Sstas krb5_xfree(name); 139178825Sdfr if (kret){ 140178825Sdfr *minor_status = kret; 141178825Sdfr goto failure; 142178825Sdfr } 143178825Sdfr } 144178825Sdfr 145178825Sdfr if (cred->ccache) { 146178825Sdfr const char *type, *name; 147233294Sstas char *type_name = NULL; 148178825Sdfr 149178825Sdfr ret = GSS_S_FAILURE; 150178825Sdfr 151178825Sdfr type = krb5_cc_get_type(context, cred->ccache); 152178825Sdfr if (type == NULL){ 153178825Sdfr *minor_status = ENOMEM; 154178825Sdfr goto failure; 155178825Sdfr } 156178825Sdfr 157178825Sdfr if (strcmp(type, "MEMORY") == 0) { 158233294Sstas ret = krb5_cc_new_unique(context, type, 159233294Sstas NULL, &handle->ccache); 160178825Sdfr if (ret) { 161178825Sdfr *minor_status = ret; 162178825Sdfr goto failure; 163178825Sdfr } 164178825Sdfr 165178825Sdfr ret = krb5_cc_copy_cache(context, cred->ccache, 166178825Sdfr handle->ccache); 167178825Sdfr if (ret) { 168178825Sdfr *minor_status = ret; 169178825Sdfr goto failure; 170178825Sdfr } 171178825Sdfr 172178825Sdfr } else { 173178825Sdfr name = krb5_cc_get_name(context, cred->ccache); 174178825Sdfr if (name == NULL) { 175178825Sdfr *minor_status = ENOMEM; 176178825Sdfr goto failure; 177178825Sdfr } 178233294Sstas 179233294Sstas kret = asprintf(&type_name, "%s:%s", type, name); 180233294Sstas if (kret < 0 || type_name == NULL) { 181178825Sdfr *minor_status = ENOMEM; 182178825Sdfr goto failure; 183178825Sdfr } 184233294Sstas 185178825Sdfr kret = krb5_cc_resolve(context, type_name, 186178825Sdfr &handle->ccache); 187178825Sdfr free(type_name); 188178825Sdfr if (kret) { 189178825Sdfr *minor_status = kret; 190178825Sdfr goto failure; 191233294Sstas } 192178825Sdfr } 193178825Sdfr } 194178825Sdfr ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); 195178825Sdfr if (ret) 196178825Sdfr goto failure; 197178825Sdfr 198178825Sdfr ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 199178825Sdfr &handle->mechanisms); 200178825Sdfr if (ret) 201178825Sdfr goto failure; 202178825Sdfr } 203178825Sdfr 204178825Sdfr HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 205178825Sdfr 206233294Sstas ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, 207178825Sdfr NULL, &lifetime, NULL, actual_mechs); 208178825Sdfr if (ret) 209178825Sdfr goto failure; 210178825Sdfr 211178825Sdfr if (initiator_time_rec) 212178825Sdfr *initiator_time_rec = lifetime; 213178825Sdfr if (acceptor_time_rec) 214178825Sdfr *acceptor_time_rec = lifetime; 215178825Sdfr 216178825Sdfr if (output_cred_handle) { 217178825Sdfr *output_cred_handle = (gss_cred_id_t)handle; 218178825Sdfr } 219178825Sdfr 220178825Sdfr *minor_status = 0; 221178825Sdfr return ret; 222178825Sdfr 223178825Sdfr failure: 224178825Sdfr 225178825Sdfr if (handle) { 226178825Sdfr if (handle->principal) 227178825Sdfr krb5_free_principal(context, handle->principal); 228178825Sdfr if (handle->keytab) 229178825Sdfr krb5_kt_close(context, handle->keytab); 230178825Sdfr if (handle->ccache) 231178825Sdfr krb5_cc_destroy(context, handle->ccache); 232178825Sdfr if (handle->mechanisms) 233178825Sdfr gss_release_oid_set(NULL, &handle->mechanisms); 234178825Sdfr free(handle); 235178825Sdfr } 236178825Sdfr if (output_cred_handle) 237178825Sdfr HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 238178825Sdfr return ret; 239178825Sdfr} 240