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