1/* 2 * Copyright (c) 2003 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Portions Copyright (c) 2009 Apple Inc. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * 3. Neither the name of the Institute nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 */ 35 36#include "gsskrb5_locl.h" 37 38OM_uint32 GSSAPI_CALLCONV _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->endtime = cred->endtime; 110 handle->principal = NULL; 111 handle->keytab = NULL; 112 handle->ccache = NULL; 113 HEIMDAL_MUTEX_init(&handle->cred_id_mutex); 114 115 kret = krb5_copy_principal(context, cred->principal, 116 &handle->principal); 117 if (kret) { 118 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 119 free(handle); 120 *minor_status = kret; 121 return GSS_S_FAILURE; 122 } 123 124 if (cred->keytab) { 125 char *name = NULL; 126 127 ret = GSS_S_FAILURE; 128 129 kret = krb5_kt_get_full_name(context, cred->keytab, &name); 130 if (kret) { 131 *minor_status = kret; 132 goto failure; 133 } 134 135 kret = krb5_kt_resolve(context, name, 136 &handle->keytab); 137 krb5_xfree(name); 138 if (kret){ 139 *minor_status = kret; 140 goto failure; 141 } 142 } 143 144 if (cred->ccache) { 145 const char *type, *name; 146 char *type_name = NULL; 147 148 ret = GSS_S_FAILURE; 149 150 type = krb5_cc_get_type(context, cred->ccache); 151 if (type == NULL){ 152 *minor_status = ENOMEM; 153 goto failure; 154 } 155 156 if (strcmp(type, "MEMORY") == 0) { 157 ret = krb5_cc_new_unique(context, type, 158 NULL, &handle->ccache); 159 if (ret) { 160 *minor_status = ret; 161 goto failure; 162 } 163 164 ret = krb5_cc_copy_cache(context, cred->ccache, 165 handle->ccache); 166 if (ret) { 167 *minor_status = ret; 168 goto failure; 169 } 170 171 } else { 172 name = krb5_cc_get_name(context, cred->ccache); 173 if (name == NULL) { 174 *minor_status = ENOMEM; 175 goto failure; 176 } 177 178 kret = asprintf(&type_name, "%s:%s", type, name); 179 if (kret < 0 || type_name == NULL) { 180 *minor_status = ENOMEM; 181 goto failure; 182 } 183 184 kret = krb5_cc_resolve(context, type_name, 185 &handle->ccache); 186 free(type_name); 187 if (kret) { 188 *minor_status = kret; 189 goto failure; 190 } 191 } 192 } 193 } 194 195 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 196 197 ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, 198 NULL, &lifetime, NULL, actual_mechs); 199 if (ret) 200 goto failure; 201 202 if (initiator_time_rec) 203 *initiator_time_rec = lifetime; 204 if (acceptor_time_rec) 205 *acceptor_time_rec = lifetime; 206 207 if (output_cred_handle) { 208 *output_cred_handle = (gss_cred_id_t)handle; 209 } 210 211 *minor_status = 0; 212 return ret; 213 214 failure: 215 216 if (handle) { 217 if (handle->principal) 218 krb5_free_principal(context, handle->principal); 219 if (handle->keytab) 220 krb5_kt_close(context, handle->keytab); 221 if (handle->ccache) 222 krb5_cc_destroy(context, handle->ccache); 223 free(handle); 224 } 225 if (output_cred_handle) 226 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 227 return ret; 228} 229