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 "krb5/gsskrb5_locl.h" 35 36 RCSID("$Id: add_cred.c 20688 2007-05-17 18:44:31Z lha $"); 37 38 OM_uint32 _gsskrb5_add_cred ( 39 OM_uint32 *minor_status, 40 const gss_cred_id_t input_cred_handle, 41 const gss_name_t desired_name, 42 const gss_OID desired_mech, 43 gss_cred_usage_t cred_usage, 44 OM_uint32 initiator_time_req, 45 OM_uint32 acceptor_time_req, 46 gss_cred_id_t *output_cred_handle, 47 gss_OID_set *actual_mechs, 48 OM_uint32 *initiator_time_rec, 49 OM_uint32 *acceptor_time_rec) 50 { 51 krb5_context context; 52 OM_uint32 ret, lifetime; 53 gsskrb5_cred cred, handle; 54 krb5_const_principal dname; 55 56 handle = NULL; 57 cred = (gsskrb5_cred)input_cred_handle; 58 dname = (krb5_const_principal)desired_name; 59 60 GSSAPI_KRB5_INIT (&context); 61 62 if (gss_oid_equal(desired_mech, GSS_KRB5_MECHANISM) == 0) { 63 *minor_status = 0; 64 return GSS_S_BAD_MECH; 65 } 66 67 if (cred == NULL && output_cred_handle == NULL) { 68 *minor_status = 0; 69 return GSS_S_NO_CRED; 70 } 71 72 if (cred == NULL) { /* XXX standard conformance failure */ 73 *minor_status = 0; 74 return GSS_S_NO_CRED; 75 } 76 77 /* check if requested output usage is compatible with output usage */ 78 if (output_cred_handle != NULL) { 79 HEIMDAL_MUTEX_lock(&cred->cred_id_mutex); 80 if (cred->usage != cred_usage && cred->usage != GSS_C_BOTH) { 81 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 82 *minor_status = GSS_KRB5_S_G_BAD_USAGE; 83 return(GSS_S_FAILURE); 84 } 85 } 86 87 /* check that we have the same name */ 88 if (dname != NULL && 89 krb5_principal_compare(context, dname, 90 cred->principal) != FALSE) { 91 if (output_cred_handle) 92 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 93 *minor_status = 0; 94 return GSS_S_BAD_NAME; 95 } 96 97 /* make a copy */ 98 if (output_cred_handle) { 99 krb5_error_code kret; 100 101 handle = calloc(1, sizeof(*handle)); 102 if (handle == NULL) { 103 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 104 *minor_status = ENOMEM; 105 return (GSS_S_FAILURE); 106 } 107 108 handle->usage = cred_usage; 109 handle->lifetime = cred->lifetime; 110 handle->principal = NULL; 111 handle->keytab = NULL; 112 handle->ccache = NULL; 113 handle->mechanisms = NULL; 114 HEIMDAL_MUTEX_init(&handle->cred_id_mutex); 115 116 ret = GSS_S_FAILURE; 117 118 kret = krb5_copy_principal(context, cred->principal, 119 &handle->principal); 120 if (kret) { 121 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 122 free(handle); 123 *minor_status = kret; 124 return GSS_S_FAILURE; 125 } 126 127 if (cred->keytab) { 128 char name[KRB5_KT_PREFIX_MAX_LEN + MAXPATHLEN]; 129 int len; 130 131 ret = GSS_S_FAILURE; 132 133 kret = krb5_kt_get_type(context, cred->keytab, 134 name, KRB5_KT_PREFIX_MAX_LEN); 135 if (kret) { 136 *minor_status = kret; 137 goto failure; 138 } 139 len = strlen(name); 140 name[len++] = ':'; 141 142 kret = krb5_kt_get_name(context, cred->keytab, 143 name + len, 144 sizeof(name) - len); 145 if (kret) { 146 *minor_status = kret; 147 goto failure; 148 } 149 150 kret = krb5_kt_resolve(context, name, 151 &handle->keytab); 152 if (kret){ 153 *minor_status = kret; 154 goto failure; 155 } 156 } 157 158 if (cred->ccache) { 159 const char *type, *name; 160 char *type_name; 161 162 ret = GSS_S_FAILURE; 163 164 type = krb5_cc_get_type(context, cred->ccache); 165 if (type == NULL){ 166 *minor_status = ENOMEM; 167 goto failure; 168 } 169 170 if (strcmp(type, "MEMORY") == 0) { 171 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, 172 &handle->ccache); 173 if (ret) { 174 *minor_status = ret; 175 goto failure; 176 } 177 178 ret = krb5_cc_copy_cache(context, cred->ccache, 179 handle->ccache); 180 if (ret) { 181 *minor_status = ret; 182 goto failure; 183 } 184 185 } else { 186 name = krb5_cc_get_name(context, cred->ccache); 187 if (name == NULL) { 188 *minor_status = ENOMEM; 189 goto failure; 190 } 191 192 asprintf(&type_name, "%s:%s", type, name); 193 if (type_name == NULL) { 194 *minor_status = ENOMEM; 195 goto failure; 196 } 197 198 kret = krb5_cc_resolve(context, type_name, 199 &handle->ccache); 200 free(type_name); 201 if (kret) { 202 *minor_status = kret; 203 goto failure; 204 } 205 } 206 } 207 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); 208 if (ret) 209 goto failure; 210 211 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 212 &handle->mechanisms); 213 if (ret) 214 goto failure; 215 } 216 217 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 218 219 ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, 220 NULL, &lifetime, NULL, actual_mechs); 221 if (ret) 222 goto failure; 223 224 if (initiator_time_rec) 225 *initiator_time_rec = lifetime; 226 if (acceptor_time_rec) 227 *acceptor_time_rec = lifetime; 228 229 if (output_cred_handle) { 230 *output_cred_handle = (gss_cred_id_t)handle; 231 } 232 233 *minor_status = 0; 234 return ret; 235 236 failure: 237 238 if (handle) { 239 if (handle->principal) 240 krb5_free_principal(context, handle->principal); 241 if (handle->keytab) 242 krb5_kt_close(context, handle->keytab); 243 if (handle->ccache) 244 krb5_cc_destroy(context, handle->ccache); 245 if (handle->mechanisms) 246 gss_release_oid_set(NULL, &handle->mechanisms); 247 free(handle); 248 } 249 if (output_cred_handle) 250 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 251 return ret; 252 } 253