1/* $NetBSD$ */ 2 3/* 4 * Copyright (c) 2003 Kungliga Tekniska H��gskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * 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->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 = NULL; 129 130 ret = GSS_S_FAILURE; 131 132 kret = krb5_kt_get_full_name(context, cred->keytab, &name); 133 if (kret) { 134 *minor_status = kret; 135 goto failure; 136 } 137 138 kret = krb5_kt_resolve(context, name, 139 &handle->keytab); 140 krb5_xfree(name); 141 if (kret){ 142 *minor_status = kret; 143 goto failure; 144 } 145 } 146 147 if (cred->ccache) { 148 const char *type, *name; 149 char *type_name = NULL; 150 151 ret = GSS_S_FAILURE; 152 153 type = krb5_cc_get_type(context, cred->ccache); 154 if (type == NULL){ 155 *minor_status = ENOMEM; 156 goto failure; 157 } 158 159 if (strcmp(type, "MEMORY") == 0) { 160 ret = krb5_cc_new_unique(context, type, 161 NULL, &handle->ccache); 162 if (ret) { 163 *minor_status = ret; 164 goto failure; 165 } 166 167 ret = krb5_cc_copy_cache(context, cred->ccache, 168 handle->ccache); 169 if (ret) { 170 *minor_status = ret; 171 goto failure; 172 } 173 174 } else { 175 name = krb5_cc_get_name(context, cred->ccache); 176 if (name == NULL) { 177 *minor_status = ENOMEM; 178 goto failure; 179 } 180 181 kret = asprintf(&type_name, "%s:%s", type, name); 182 if (kret < 0 || type_name == NULL) { 183 *minor_status = ENOMEM; 184 goto failure; 185 } 186 187 kret = krb5_cc_resolve(context, type_name, 188 &handle->ccache); 189 free(type_name); 190 if (kret) { 191 *minor_status = kret; 192 goto failure; 193 } 194 } 195 } 196 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); 197 if (ret) 198 goto failure; 199 200 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 201 &handle->mechanisms); 202 if (ret) 203 goto failure; 204 } 205 206 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 207 208 ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)cred, 209 NULL, &lifetime, NULL, actual_mechs); 210 if (ret) 211 goto failure; 212 213 if (initiator_time_rec) 214 *initiator_time_rec = lifetime; 215 if (acceptor_time_rec) 216 *acceptor_time_rec = lifetime; 217 218 if (output_cred_handle) { 219 *output_cred_handle = (gss_cred_id_t)handle; 220 } 221 222 *minor_status = 0; 223 return ret; 224 225 failure: 226 227 if (handle) { 228 if (handle->principal) 229 krb5_free_principal(context, handle->principal); 230 if (handle->keytab) 231 krb5_kt_close(context, handle->keytab); 232 if (handle->ccache) 233 krb5_cc_destroy(context, handle->ccache); 234 if (handle->mechanisms) 235 gss_release_oid_set(NULL, &handle->mechanisms); 236 free(handle); 237 } 238 if (output_cred_handle) 239 HEIMDAL_MUTEX_unlock(&cred->cred_id_mutex); 240 return ret; 241} 242