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 36OM_uint32 _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[KRB5_KT_PREFIX_MAX_LEN + MAXPATHLEN]; 127 int len; 128 129 ret = GSS_S_FAILURE; 130 131 kret = krb5_kt_get_type(context, cred->keytab, 132 name, KRB5_KT_PREFIX_MAX_LEN); 133 if (kret) { 134 *minor_status = kret; 135 goto failure; 136 } 137 len = strlen(name); 138 name[len++] = ':'; 139 140 kret = krb5_kt_get_name(context, cred->keytab, 141 name + len, 142 sizeof(name) - len); 143 if (kret) { 144 *minor_status = kret; 145 goto failure; 146 } 147 148 kret = krb5_kt_resolve(context, name, 149 &handle->keytab); 150 if (kret){ 151 *minor_status = kret; 152 goto failure; 153 } 154 } 155 156 if (cred->ccache) { 157 const char *type, *name; 158 char *type_name; 159 160 ret = GSS_S_FAILURE; 161 162 type = krb5_cc_get_type(context, cred->ccache); 163 if (type == NULL){ 164 *minor_status = ENOMEM; 165 goto failure; 166 } 167 168 if (strcmp(type, "MEMORY") == 0) { 169 ret = krb5_cc_new_unique(context, type, 170 NULL, &handle->ccache); 171 if (ret) { 172 *minor_status = ret; 173 goto failure; 174 } 175 176 ret = krb5_cc_copy_cache(context, cred->ccache, 177 handle->ccache); 178 if (ret) { 179 *minor_status = ret; 180 goto failure; 181 } 182 183 } else { 184 name = krb5_cc_get_name(context, cred->ccache); 185 if (name == NULL) { 186 *minor_status = ENOMEM; 187 goto failure; 188 } 189 190 asprintf(&type_name, "%s:%s", type, name); 191 if (type_name == NULL) { 192 *minor_status = ENOMEM; 193 goto failure; 194 } 195 196 kret = krb5_cc_resolve(context, type_name, 197 &handle->ccache); 198 free(type_name); 199 if (kret) { 200 *minor_status = kret; 201 goto failure; 202 } 203 } 204 } 205 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); 206 if (ret) 207 goto failure; 208 209 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 210 &handle->mechanisms); 211 if (ret) 212 goto failure; 213 } 214 215 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 216 217 ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, 218 NULL, &lifetime, NULL, actual_mechs); 219 if (ret) 220 goto failure; 221 222 if (initiator_time_rec) 223 *initiator_time_rec = lifetime; 224 if (acceptor_time_rec) 225 *acceptor_time_rec = lifetime; 226 227 if (output_cred_handle) { 228 *output_cred_handle = (gss_cred_id_t)handle; 229 } 230 231 *minor_status = 0; 232 return ret; 233 234 failure: 235 236 if (handle) { 237 if (handle->principal) 238 krb5_free_principal(context, handle->principal); 239 if (handle->keytab) 240 krb5_kt_close(context, handle->keytab); 241 if (handle->ccache) 242 krb5_cc_destroy(context, handle->ccache); 243 if (handle->mechanisms) 244 gss_release_oid_set(NULL, &handle->mechanisms); 245 free(handle); 246 } 247 if (output_cred_handle) 248 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 249 return ret; 250} 251