1c19800e8SDoug Rabson /* 2c19800e8SDoug Rabson * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan 3c19800e8SDoug Rabson * (Royal Institute of Technology, Stockholm, Sweden). 4c19800e8SDoug Rabson * All rights reserved. 5c19800e8SDoug Rabson * 6c19800e8SDoug Rabson * Redistribution and use in source and binary forms, with or without 7c19800e8SDoug Rabson * modification, are permitted provided that the following conditions 8c19800e8SDoug Rabson * are met: 9c19800e8SDoug Rabson * 10c19800e8SDoug Rabson * 1. Redistributions of source code must retain the above copyright 11c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer. 12c19800e8SDoug Rabson * 13c19800e8SDoug Rabson * 2. Redistributions in binary form must reproduce the above copyright 14c19800e8SDoug Rabson * notice, this list of conditions and the following disclaimer in the 15c19800e8SDoug Rabson * documentation and/or other materials provided with the distribution. 16c19800e8SDoug Rabson * 17c19800e8SDoug Rabson * 3. Neither the name of the Institute nor the names of its contributors 18c19800e8SDoug Rabson * may be used to endorse or promote products derived from this software 19c19800e8SDoug Rabson * without specific prior written permission. 20c19800e8SDoug Rabson * 21c19800e8SDoug Rabson * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22c19800e8SDoug Rabson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23c19800e8SDoug Rabson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24c19800e8SDoug Rabson * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25c19800e8SDoug Rabson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26c19800e8SDoug Rabson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27c19800e8SDoug Rabson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28c19800e8SDoug Rabson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29c19800e8SDoug Rabson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30c19800e8SDoug Rabson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31c19800e8SDoug Rabson * SUCH DAMAGE. 32c19800e8SDoug Rabson */ 33c19800e8SDoug Rabson 34c19800e8SDoug Rabson #include "krb5/gsskrb5_locl.h" 35c19800e8SDoug Rabson 36c19800e8SDoug Rabson RCSID("$Id: acquire_cred.c 22124 2007-12-04 00:03:52Z lha $"); 37c19800e8SDoug Rabson 38c19800e8SDoug Rabson OM_uint32 39c19800e8SDoug Rabson __gsskrb5_ccache_lifetime(OM_uint32 *minor_status, 40c19800e8SDoug Rabson krb5_context context, 41c19800e8SDoug Rabson krb5_ccache id, 42c19800e8SDoug Rabson krb5_principal principal, 43c19800e8SDoug Rabson OM_uint32 *lifetime) 44c19800e8SDoug Rabson { 45c19800e8SDoug Rabson krb5_creds in_cred, *out_cred; 46c19800e8SDoug Rabson krb5_const_realm realm; 47c19800e8SDoug Rabson krb5_error_code kret; 48c19800e8SDoug Rabson 49c19800e8SDoug Rabson memset(&in_cred, 0, sizeof(in_cred)); 50c19800e8SDoug Rabson in_cred.client = principal; 51c19800e8SDoug Rabson 52c19800e8SDoug Rabson realm = krb5_principal_get_realm(context, principal); 53c19800e8SDoug Rabson if (realm == NULL) { 54c19800e8SDoug Rabson _gsskrb5_clear_status (); 55c19800e8SDoug Rabson *minor_status = KRB5_PRINC_NOMATCH; /* XXX */ 56c19800e8SDoug Rabson return GSS_S_FAILURE; 57c19800e8SDoug Rabson } 58c19800e8SDoug Rabson 59c19800e8SDoug Rabson kret = krb5_make_principal(context, &in_cred.server, 60c19800e8SDoug Rabson realm, KRB5_TGS_NAME, realm, NULL); 61c19800e8SDoug Rabson if (kret) { 62c19800e8SDoug Rabson *minor_status = kret; 63c19800e8SDoug Rabson return GSS_S_FAILURE; 64c19800e8SDoug Rabson } 65c19800e8SDoug Rabson 66c19800e8SDoug Rabson kret = krb5_get_credentials(context, 0, 67c19800e8SDoug Rabson id, &in_cred, &out_cred); 68c19800e8SDoug Rabson krb5_free_principal(context, in_cred.server); 69c19800e8SDoug Rabson if (kret) { 70c19800e8SDoug Rabson *minor_status = kret; 71c19800e8SDoug Rabson return GSS_S_FAILURE; 72c19800e8SDoug Rabson } 73c19800e8SDoug Rabson 74c19800e8SDoug Rabson *lifetime = out_cred->times.endtime; 75c19800e8SDoug Rabson krb5_free_creds(context, out_cred); 76c19800e8SDoug Rabson 77c19800e8SDoug Rabson return GSS_S_COMPLETE; 78c19800e8SDoug Rabson } 79c19800e8SDoug Rabson 80c19800e8SDoug Rabson 81c19800e8SDoug Rabson 82c19800e8SDoug Rabson 83c19800e8SDoug Rabson static krb5_error_code 84c19800e8SDoug Rabson get_keytab(krb5_context context, krb5_keytab *keytab) 85c19800e8SDoug Rabson { 86c19800e8SDoug Rabson char kt_name[256]; 87c19800e8SDoug Rabson krb5_error_code kret; 88c19800e8SDoug Rabson 89c19800e8SDoug Rabson HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex); 90c19800e8SDoug Rabson 91c19800e8SDoug Rabson if (_gsskrb5_keytab != NULL) { 92c19800e8SDoug Rabson kret = krb5_kt_get_name(context, 93c19800e8SDoug Rabson _gsskrb5_keytab, 94c19800e8SDoug Rabson kt_name, sizeof(kt_name)); 95c19800e8SDoug Rabson if (kret == 0) 96c19800e8SDoug Rabson kret = krb5_kt_resolve(context, kt_name, keytab); 97c19800e8SDoug Rabson } else 98c19800e8SDoug Rabson kret = krb5_kt_default(context, keytab); 99c19800e8SDoug Rabson 100c19800e8SDoug Rabson HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex); 101c19800e8SDoug Rabson 102c19800e8SDoug Rabson return (kret); 103c19800e8SDoug Rabson } 104c19800e8SDoug Rabson 105c19800e8SDoug Rabson static OM_uint32 acquire_initiator_cred 106c19800e8SDoug Rabson (OM_uint32 * minor_status, 107c19800e8SDoug Rabson krb5_context context, 108c19800e8SDoug Rabson const gss_name_t desired_name, 109c19800e8SDoug Rabson OM_uint32 time_req, 110c19800e8SDoug Rabson const gss_OID_set desired_mechs, 111c19800e8SDoug Rabson gss_cred_usage_t cred_usage, 112c19800e8SDoug Rabson gsskrb5_cred handle, 113c19800e8SDoug Rabson gss_OID_set * actual_mechs, 114c19800e8SDoug Rabson OM_uint32 * time_rec 115c19800e8SDoug Rabson ) 116c19800e8SDoug Rabson { 117c19800e8SDoug Rabson OM_uint32 ret; 118c19800e8SDoug Rabson krb5_creds cred; 119c19800e8SDoug Rabson krb5_principal def_princ; 120c19800e8SDoug Rabson krb5_get_init_creds_opt *opt; 121c19800e8SDoug Rabson krb5_ccache ccache; 122c19800e8SDoug Rabson krb5_keytab keytab; 123c19800e8SDoug Rabson krb5_error_code kret; 124c19800e8SDoug Rabson 125c19800e8SDoug Rabson keytab = NULL; 126c19800e8SDoug Rabson ccache = NULL; 127c19800e8SDoug Rabson def_princ = NULL; 128c19800e8SDoug Rabson ret = GSS_S_FAILURE; 129c19800e8SDoug Rabson memset(&cred, 0, sizeof(cred)); 130c19800e8SDoug Rabson 131c19800e8SDoug Rabson /* If we have a preferred principal, lets try to find it in all 132c19800e8SDoug Rabson * caches, otherwise, fall back to default cache. Ignore 133c19800e8SDoug Rabson * errors. */ 134c19800e8SDoug Rabson if (handle->principal) 135c19800e8SDoug Rabson kret = krb5_cc_cache_match (context, 136c19800e8SDoug Rabson handle->principal, 137c19800e8SDoug Rabson NULL, 138c19800e8SDoug Rabson &ccache); 139c19800e8SDoug Rabson 140c19800e8SDoug Rabson if (ccache == NULL) { 141c19800e8SDoug Rabson kret = krb5_cc_default(context, &ccache); 142c19800e8SDoug Rabson if (kret) 143c19800e8SDoug Rabson goto end; 144c19800e8SDoug Rabson } 145c19800e8SDoug Rabson kret = krb5_cc_get_principal(context, ccache, 146c19800e8SDoug Rabson &def_princ); 147c19800e8SDoug Rabson if (kret != 0) { 148c19800e8SDoug Rabson /* we'll try to use a keytab below */ 149c19800e8SDoug Rabson krb5_cc_destroy(context, ccache); 150c19800e8SDoug Rabson ccache = NULL; 151c19800e8SDoug Rabson kret = 0; 152c19800e8SDoug Rabson } else if (handle->principal == NULL) { 153c19800e8SDoug Rabson kret = krb5_copy_principal(context, def_princ, 154c19800e8SDoug Rabson &handle->principal); 155c19800e8SDoug Rabson if (kret) 156c19800e8SDoug Rabson goto end; 157c19800e8SDoug Rabson } else if (handle->principal != NULL && 158c19800e8SDoug Rabson krb5_principal_compare(context, handle->principal, 159c19800e8SDoug Rabson def_princ) == FALSE) { 160c19800e8SDoug Rabson /* Before failing, lets check the keytab */ 161c19800e8SDoug Rabson krb5_free_principal(context, def_princ); 162c19800e8SDoug Rabson def_princ = NULL; 163c19800e8SDoug Rabson } 164c19800e8SDoug Rabson if (def_princ == NULL) { 165c19800e8SDoug Rabson /* We have no existing credentials cache, 166c19800e8SDoug Rabson * so attempt to get a TGT using a keytab. 167c19800e8SDoug Rabson */ 168c19800e8SDoug Rabson if (handle->principal == NULL) { 169c19800e8SDoug Rabson kret = krb5_get_default_principal(context, 170c19800e8SDoug Rabson &handle->principal); 171c19800e8SDoug Rabson if (kret) 172c19800e8SDoug Rabson goto end; 173c19800e8SDoug Rabson } 174c19800e8SDoug Rabson kret = get_keytab(context, &keytab); 175c19800e8SDoug Rabson if (kret) 176c19800e8SDoug Rabson goto end; 177c19800e8SDoug Rabson kret = krb5_get_init_creds_opt_alloc(context, &opt); 178c19800e8SDoug Rabson if (kret) 179c19800e8SDoug Rabson goto end; 180c19800e8SDoug Rabson kret = krb5_get_init_creds_keytab(context, &cred, 181c19800e8SDoug Rabson handle->principal, keytab, 0, NULL, opt); 182c19800e8SDoug Rabson krb5_get_init_creds_opt_free(context, opt); 183c19800e8SDoug Rabson if (kret) 184c19800e8SDoug Rabson goto end; 185c19800e8SDoug Rabson kret = krb5_cc_gen_new(context, &krb5_mcc_ops, 186c19800e8SDoug Rabson &ccache); 187c19800e8SDoug Rabson if (kret) 188c19800e8SDoug Rabson goto end; 189c19800e8SDoug Rabson kret = krb5_cc_initialize(context, ccache, cred.client); 190c19800e8SDoug Rabson if (kret) 191c19800e8SDoug Rabson goto end; 192c19800e8SDoug Rabson kret = krb5_cc_store_cred(context, ccache, &cred); 193c19800e8SDoug Rabson if (kret) 194c19800e8SDoug Rabson goto end; 195c19800e8SDoug Rabson handle->lifetime = cred.times.endtime; 196c19800e8SDoug Rabson handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE; 197c19800e8SDoug Rabson } else { 198c19800e8SDoug Rabson 199c19800e8SDoug Rabson ret = __gsskrb5_ccache_lifetime(minor_status, 200c19800e8SDoug Rabson context, 201c19800e8SDoug Rabson ccache, 202c19800e8SDoug Rabson handle->principal, 203c19800e8SDoug Rabson &handle->lifetime); 204c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE) 205c19800e8SDoug Rabson goto end; 206c19800e8SDoug Rabson kret = 0; 207c19800e8SDoug Rabson } 208c19800e8SDoug Rabson 209c19800e8SDoug Rabson handle->ccache = ccache; 210c19800e8SDoug Rabson ret = GSS_S_COMPLETE; 211c19800e8SDoug Rabson 212c19800e8SDoug Rabson end: 213c19800e8SDoug Rabson if (cred.client != NULL) 214c19800e8SDoug Rabson krb5_free_cred_contents(context, &cred); 215c19800e8SDoug Rabson if (def_princ != NULL) 216c19800e8SDoug Rabson krb5_free_principal(context, def_princ); 217c19800e8SDoug Rabson if (keytab != NULL) 218c19800e8SDoug Rabson krb5_kt_close(context, keytab); 219c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE) { 220c19800e8SDoug Rabson if (ccache != NULL) 221c19800e8SDoug Rabson krb5_cc_close(context, ccache); 222c19800e8SDoug Rabson if (kret != 0) { 223c19800e8SDoug Rabson *minor_status = kret; 224c19800e8SDoug Rabson } 225c19800e8SDoug Rabson } 226c19800e8SDoug Rabson return (ret); 227c19800e8SDoug Rabson } 228c19800e8SDoug Rabson 229c19800e8SDoug Rabson static OM_uint32 acquire_acceptor_cred 230c19800e8SDoug Rabson (OM_uint32 * minor_status, 231c19800e8SDoug Rabson krb5_context context, 232c19800e8SDoug Rabson const gss_name_t desired_name, 233c19800e8SDoug Rabson OM_uint32 time_req, 234c19800e8SDoug Rabson const gss_OID_set desired_mechs, 235c19800e8SDoug Rabson gss_cred_usage_t cred_usage, 236c19800e8SDoug Rabson gsskrb5_cred handle, 237c19800e8SDoug Rabson gss_OID_set * actual_mechs, 238c19800e8SDoug Rabson OM_uint32 * time_rec 239c19800e8SDoug Rabson ) 240c19800e8SDoug Rabson { 241c19800e8SDoug Rabson OM_uint32 ret; 242c19800e8SDoug Rabson krb5_error_code kret; 243c19800e8SDoug Rabson 244c19800e8SDoug Rabson kret = 0; 245c19800e8SDoug Rabson ret = GSS_S_FAILURE; 246c19800e8SDoug Rabson kret = get_keytab(context, &handle->keytab); 247c19800e8SDoug Rabson if (kret) 248c19800e8SDoug Rabson goto end; 249c19800e8SDoug Rabson 250c19800e8SDoug Rabson /* check that the requested principal exists in the keytab */ 251c19800e8SDoug Rabson if (handle->principal) { 252c19800e8SDoug Rabson krb5_keytab_entry entry; 253c19800e8SDoug Rabson 254c19800e8SDoug Rabson kret = krb5_kt_get_entry(context, handle->keytab, 255c19800e8SDoug Rabson handle->principal, 0, 0, &entry); 256c19800e8SDoug Rabson if (kret) 257c19800e8SDoug Rabson goto end; 258c19800e8SDoug Rabson krb5_kt_free_entry(context, &entry); 259c19800e8SDoug Rabson ret = GSS_S_COMPLETE; 260c19800e8SDoug Rabson } else { 261c19800e8SDoug Rabson /* 262c19800e8SDoug Rabson * Check if there is at least one entry in the keytab before 263c19800e8SDoug Rabson * declaring it as an useful keytab. 264c19800e8SDoug Rabson */ 265c19800e8SDoug Rabson krb5_keytab_entry tmp; 266c19800e8SDoug Rabson krb5_kt_cursor c; 267c19800e8SDoug Rabson 268c19800e8SDoug Rabson kret = krb5_kt_start_seq_get (context, handle->keytab, &c); 269c19800e8SDoug Rabson if (kret) 270c19800e8SDoug Rabson goto end; 271c19800e8SDoug Rabson if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) { 272c19800e8SDoug Rabson krb5_kt_free_entry(context, &tmp); 273c19800e8SDoug Rabson ret = GSS_S_COMPLETE; /* ok found one entry */ 274c19800e8SDoug Rabson } 275c19800e8SDoug Rabson krb5_kt_end_seq_get (context, handle->keytab, &c); 276c19800e8SDoug Rabson } 277c19800e8SDoug Rabson end: 278c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE) { 279c19800e8SDoug Rabson if (handle->keytab != NULL) 280c19800e8SDoug Rabson krb5_kt_close(context, handle->keytab); 281c19800e8SDoug Rabson if (kret != 0) { 282c19800e8SDoug Rabson *minor_status = kret; 283c19800e8SDoug Rabson } 284c19800e8SDoug Rabson } 285c19800e8SDoug Rabson return (ret); 286c19800e8SDoug Rabson } 287c19800e8SDoug Rabson 288c19800e8SDoug Rabson OM_uint32 _gsskrb5_acquire_cred 289c19800e8SDoug Rabson (OM_uint32 * minor_status, 290c19800e8SDoug Rabson const gss_name_t desired_name, 291c19800e8SDoug Rabson OM_uint32 time_req, 292c19800e8SDoug Rabson const gss_OID_set desired_mechs, 293c19800e8SDoug Rabson gss_cred_usage_t cred_usage, 294c19800e8SDoug Rabson gss_cred_id_t * output_cred_handle, 295c19800e8SDoug Rabson gss_OID_set * actual_mechs, 296c19800e8SDoug Rabson OM_uint32 * time_rec 297c19800e8SDoug Rabson ) 298c19800e8SDoug Rabson { 299c19800e8SDoug Rabson krb5_context context; 300c19800e8SDoug Rabson gsskrb5_cred handle; 301c19800e8SDoug Rabson OM_uint32 ret; 302c19800e8SDoug Rabson 303c19800e8SDoug Rabson if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) { 304c19800e8SDoug Rabson *minor_status = GSS_KRB5_S_G_BAD_USAGE; 305c19800e8SDoug Rabson return GSS_S_FAILURE; 306c19800e8SDoug Rabson } 307c19800e8SDoug Rabson 308c19800e8SDoug Rabson GSSAPI_KRB5_INIT(&context); 309c19800e8SDoug Rabson 310c19800e8SDoug Rabson *output_cred_handle = NULL; 311c19800e8SDoug Rabson if (time_rec) 312c19800e8SDoug Rabson *time_rec = 0; 313c19800e8SDoug Rabson if (actual_mechs) 314c19800e8SDoug Rabson *actual_mechs = GSS_C_NO_OID_SET; 315c19800e8SDoug Rabson 316c19800e8SDoug Rabson if (desired_mechs) { 317c19800e8SDoug Rabson int present = 0; 318c19800e8SDoug Rabson 319c19800e8SDoug Rabson ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 320c19800e8SDoug Rabson desired_mechs, &present); 321c19800e8SDoug Rabson if (ret) 322c19800e8SDoug Rabson return ret; 323c19800e8SDoug Rabson if (!present) { 324c19800e8SDoug Rabson *minor_status = 0; 325c19800e8SDoug Rabson return GSS_S_BAD_MECH; 326c19800e8SDoug Rabson } 327c19800e8SDoug Rabson } 328c19800e8SDoug Rabson 329c19800e8SDoug Rabson handle = calloc(1, sizeof(*handle)); 330c19800e8SDoug Rabson if (handle == NULL) { 331c19800e8SDoug Rabson *minor_status = ENOMEM; 332c19800e8SDoug Rabson return (GSS_S_FAILURE); 333c19800e8SDoug Rabson } 334c19800e8SDoug Rabson 335c19800e8SDoug Rabson HEIMDAL_MUTEX_init(&handle->cred_id_mutex); 336c19800e8SDoug Rabson 337c19800e8SDoug Rabson if (desired_name != GSS_C_NO_NAME) { 338c19800e8SDoug Rabson krb5_principal name = (krb5_principal)desired_name; 339c19800e8SDoug Rabson ret = krb5_copy_principal(context, name, &handle->principal); 340c19800e8SDoug Rabson if (ret) { 341c19800e8SDoug Rabson HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); 342c19800e8SDoug Rabson *minor_status = ret; 343c19800e8SDoug Rabson free(handle); 344c19800e8SDoug Rabson return GSS_S_FAILURE; 345c19800e8SDoug Rabson } 346c19800e8SDoug Rabson } 347c19800e8SDoug Rabson if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { 348c19800e8SDoug Rabson ret = acquire_initiator_cred(minor_status, context, 349c19800e8SDoug Rabson desired_name, time_req, 350c19800e8SDoug Rabson desired_mechs, cred_usage, handle, 351c19800e8SDoug Rabson actual_mechs, time_rec); 352c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE) { 353c19800e8SDoug Rabson HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); 354c19800e8SDoug Rabson krb5_free_principal(context, handle->principal); 355c19800e8SDoug Rabson free(handle); 356c19800e8SDoug Rabson return (ret); 357c19800e8SDoug Rabson } 358c19800e8SDoug Rabson } 359c19800e8SDoug Rabson if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { 360c19800e8SDoug Rabson ret = acquire_acceptor_cred(minor_status, context, 361c19800e8SDoug Rabson desired_name, time_req, 362c19800e8SDoug Rabson desired_mechs, cred_usage, handle, actual_mechs, time_rec); 363c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE) { 364c19800e8SDoug Rabson HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); 365c19800e8SDoug Rabson krb5_free_principal(context, handle->principal); 366c19800e8SDoug Rabson free(handle); 367c19800e8SDoug Rabson return (ret); 368c19800e8SDoug Rabson } 369c19800e8SDoug Rabson } 370c19800e8SDoug Rabson ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); 371c19800e8SDoug Rabson if (ret == GSS_S_COMPLETE) 372c19800e8SDoug Rabson ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, 373c19800e8SDoug Rabson &handle->mechanisms); 374c19800e8SDoug Rabson if (ret == GSS_S_COMPLETE) 375c19800e8SDoug Rabson ret = _gsskrb5_inquire_cred(minor_status, (gss_cred_id_t)handle, 376c19800e8SDoug Rabson NULL, time_rec, NULL, actual_mechs); 377c19800e8SDoug Rabson if (ret != GSS_S_COMPLETE) { 378c19800e8SDoug Rabson if (handle->mechanisms != NULL) 379c19800e8SDoug Rabson gss_release_oid_set(NULL, &handle->mechanisms); 380c19800e8SDoug Rabson HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex); 381c19800e8SDoug Rabson krb5_free_principal(context, handle->principal); 382c19800e8SDoug Rabson free(handle); 383c19800e8SDoug Rabson return (ret); 384c19800e8SDoug Rabson } 385c19800e8SDoug Rabson *minor_status = 0; 386c19800e8SDoug Rabson if (time_rec) { 387c19800e8SDoug Rabson ret = _gsskrb5_lifetime_left(minor_status, 388c19800e8SDoug Rabson context, 389c19800e8SDoug Rabson handle->lifetime, 390c19800e8SDoug Rabson time_rec); 391c19800e8SDoug Rabson 392c19800e8SDoug Rabson if (ret) 393c19800e8SDoug Rabson return ret; 394c19800e8SDoug Rabson } 395c19800e8SDoug Rabson handle->usage = cred_usage; 396c19800e8SDoug Rabson *output_cred_handle = (gss_cred_id_t)handle; 397c19800e8SDoug Rabson return (GSS_S_COMPLETE); 398c19800e8SDoug Rabson } 399