1 /* 2 * Copyright (c) 2003 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "gsskrb5_locl.h" 35 36 OM_uint32 GSSAPI_CALLCONV _gsskrb5_add_cred ( 37 OM_uint32 *minor_status, 38 const gss_cred_id_t input_cred_handle, 39 const gss_name_t desired_name, 40 const gss_OID desired_mech, 41 gss_cred_usage_t cred_usage, 42 OM_uint32 initiator_time_req, 43 OM_uint32 acceptor_time_req, 44 gss_cred_id_t *output_cred_handle, 45 gss_OID_set *actual_mechs, 46 OM_uint32 *initiator_time_rec, 47 OM_uint32 *acceptor_time_rec) 48 { 49 krb5_context context; 50 OM_uint32 ret, lifetime; 51 gsskrb5_cred cred, handle; 52 krb5_const_principal dname; 53 54 handle = NULL; 55 cred = (gsskrb5_cred)input_cred_handle; 56 dname = (krb5_const_principal)desired_name; 57 58 GSSAPI_KRB5_INIT (&context); 59 60 if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { 61 *minor_status = 0; 62 return GSS_S_BAD_MECH; 63 } 64 65 if (cred == NULL && output_cred_handle == NULL) { 66 *minor_status = 0; 67 return GSS_S_NO_CRED; 68 } 69 70 if (cred == NULL) { /* XXX standard conformance failure */ 71 *minor_status = 0; 72 return GSS_S_NO_CRED; 73 } 74 75 /* check if requested output usage is compatible with output usage */ 76 if (output_cred_handle != NULL) { 77 HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); 78 if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { 79 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 80 *minor_status = GSS_KRB5_S_G_BAD_USAGE; 81 return(GSS_S_FAILURE); 82 } 83 } 84 85 /* check that we have the same name */ 86 if (dname != NULL && 87 krb5_principal_compare(context, dname, 88 cred->principal) != FALSE) { 89 if (output_cred_handle) 90 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 91 *minor_status = 0; 92 return GSS_S_BAD_NAME; 93 } 94 95 /* make a copy */ 96 if (output_cred_handle) { 97 krb5_error_code kret; 98 99 handle = calloc(1, sizeof(*handle)); 100 if (handle == NULL) { 101 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 102 *minor_status = ENOMEM; 103 return (GSS_S_FAILURE); 104 } 105 106 handle->usage = cred_usage; 107 handle->lifetime = cred->lifetime; 108 handle->principal = NULL; 109 handle->keytab = NULL; 110 handle->ccache = NULL; 111 handle->mechanisms = NULL; 112 HEIMDAL_MUTEX_init(&handle->cred_id_mutex); 113 114 ret = GSS_S_FAILURE; 115 116 kret = krb5_copy_principal(context, cred->principal, 117 &handle->principal); 118 if (kret) { 119 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 120 free(handle); 121 *minor_status = kret; 122 return GSS_S_FAILURE; 123 } 124 125 if (cred->keytab) { 126 char *name = NULL; 127 128 ret = GSS_S_FAILURE; 129 130 kret = krb5_kt_get_full_name(context, cred->keytab, &name); 131 if (kret) { 132 *minor_status = kret; 133 goto failure; 134 } 135 136 kret = krb5_kt_resolve(context, name, 137 &handle->keytab); 138 krb5_xfree(name); 139 if (kret){ 140 *minor_status = kret; 141 goto failure; 142 } 143 } 144 145 if (cred->ccache) { 146 const char *type, *name; 147 char *type_name = NULL; 148 149 ret = GSS_S_FAILURE; 150 151 type = krb5_cc_get_type(context, cred->ccache); 152 if (type == NULL){ 153 *minor_status = ENOMEM; 154 goto failure; 155 } 156 157 if (strcmp(type, "MEMORY") == 0) { 158 ret = krb5_cc_new_unique(context, type, 159 NULL, &handle->ccache); 160 if (ret) { 161 *minor_status = ret; 162 goto failure; 163 } 164 165 ret = krb5_cc_copy_cache(context, cred->ccache, 166 handle->ccache); 167 if (ret) { 168 *minor_status = ret; 169 goto failure; 170 } 171 172 } else { 173 name = krb5_cc_get_name(context, cred->ccache); 174 if (name == NULL) { 175 *minor_status = ENOMEM; 176 goto failure; 177 } 178 179 kret = asprintf(&type_name, "%s:%s", type, name); 180 if (kret < 0 || type_name == NULL) { 181 *minor_status = ENOMEM; 182 goto failure; 183 } 184 185 kret = krb5_cc_resolve(context, type_name, 186 &handle->ccache); 187 free(type_name); 188 if (kret) { 189 *minor_status = kret; 190 goto failure; 191 } 192 } 193 } 194 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); 195 if (ret) 196 goto failure; 197 198 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 199 &handle->mechanisms); 200 if (ret) 201 goto failure; 202 } 203 204 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 205 206 ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, 207 NULL, &lifetime, NULL, actual_mechs); 208 if (ret) 209 goto failure; 210 211 if (initiator_time_rec) 212 *initiator_time_rec = lifetime; 213 if (acceptor_time_rec) 214 *acceptor_time_rec = lifetime; 215 216 if (output_cred_handle) { 217 *output_cred_handle = (gss_cred_id_t)handle; 218 } 219 220 *minor_status = 0; 221 return ret; 222 223 failure: 224 225 if (handle) { 226 if (handle->principal) 227 krb5_free_principal(context, handle->principal); 228 if (handle->keytab) 229 krb5_kt_close(context, handle->keytab); 230 if (handle->ccache) 231 krb5_cc_destroy(context, handle->ccache); 232 if (handle->mechanisms) 233 gss_release_oid_set(NULL, &handle->mechanisms); 234 free(handle); 235 } 236 if (output_cred_handle) 237 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 238 return ret; 239 } 240