From 9efd74fabe5a3ab5f89e8355d6e6ea5a011f5211 Mon Sep 17 00:00:00 2001 From: "Jacques A. Vidrine" Date: Thu, 9 May 2002 15:22:34 +0000 Subject: [PATCH] Attempt to handle GSS_C_INITIATE/GSS_C_ACCEPT/GSS_C_BOTH. If GSS_C_INITIATE is specified, then get credentials from the default cache. If we don't have any, then try using the keytab. If GSS_C_ACCEPT is specified, just note our principal name and open the keytab. If GSS_C_BOTH is specified, do both of the above. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@10978 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/gssapi/acquire_cred.c | 305 ++++++++++++++++++++------------- lib/gssapi/krb5/acquire_cred.c | 305 ++++++++++++++++++++------------- 2 files changed, 372 insertions(+), 238 deletions(-) diff --git a/lib/gssapi/acquire_cred.c b/lib/gssapi/acquire_cred.c index f4d97b71f..a9cdaadaa 100644 --- a/lib/gssapi/acquire_cred.c +++ b/lib/gssapi/acquire_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -35,6 +35,158 @@ RCSID("$Id$"); +static krb5_error_code +get_keytab(krb5_keytab *keytab) +{ + char kt_name[256]; + krb5_error_code kret; + + if (gssapi_krb5_keytab != NULL) { + kret = krb5_kt_get_name(gssapi_krb5_context, + gssapi_krb5_keytab, + kt_name, sizeof(kt_name)); + if (kret == 0) + kret = krb5_kt_resolve(gssapi_krb5_context, kt_name, keytab); + } else + kret = krb5_kt_default(gssapi_krb5_context, keytab); + return (kret); +} + +static OM_uint32 acquire_initiator_cred + (OM_uint32 * minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_creds cred; + krb5_principal def_princ; + krb5_get_init_creds_opt opt; + krb5_ccache ccache; + krb5_keytab keytab; + krb5_error_code kret; + + keytab = NULL; + ccache = NULL; + def_princ = NULL; + ret = GSS_S_FAILURE; + memset(&cred, 0, sizeof(cred)); + + kret = krb5_cc_default(gssapi_krb5_context, &ccache); + if (kret) + goto end; + kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, + &def_princ); + if (kret != 0) { + /* we'll try to use a keytab below */ + krb5_cc_destroy(gssapi_krb5_context, ccache); + ccache = NULL; + kret = 0; + } else if (handle->principal == NULL) { + kret = krb5_copy_principal(gssapi_krb5_context, def_princ, + &handle->principal); + if (kret) + goto end; + } else if (handle->principal != NULL && + krb5_principal_compare(gssapi_krb5_context, handle->principal, + def_princ) == FALSE) { + kret = KRB5_PRINC_NOMATCH; + goto end; + } + if (def_princ == NULL) { + /* We have no existing credentials cache, + * so attempt to get a TGT using a keytab. + */ + if (handle->principal == NULL) { + kret = krb5_get_default_principal(gssapi_krb5_context, + &handle->principal); + if (kret) + goto end; + } + kret = get_keytab(&keytab); + if (kret) + goto end; + krb5_get_init_creds_opt_init(&opt); + kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred, + handle->principal, keytab, 0, NULL, &opt); + if (kret) + goto end; + kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops, + &ccache); + if (kret) + goto end; + kret = krb5_cc_initialize(gssapi_krb5_context, ccache, cred.client); + if (kret) + goto end; + kret = krb5_cc_store_cred(gssapi_krb5_context, ccache, &cred); + if (kret) + goto end; + } + handle->ccache = ccache; + ret = GSS_S_COMPLETE; + +end: + if (cred.client != NULL) + krb5_free_creds_contents(gssapi_krb5_context, &cred); + if (def_princ != NULL) + krb5_free_principal(gssapi_krb5_context, def_princ); + if (keytab != NULL) + krb5_kt_close(gssapi_krb5_context, keytab); + if (ret != GSS_S_COMPLETE) { + if (ccache != NULL) + krb5_cc_close(gssapi_krb5_context, ccache); + if (kret != 0) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + } + } + return (ret); +} + +static OM_uint32 acquire_acceptor_cred + (OM_uint32 * minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_error_code kret; + + kret = 0; + ret = GSS_S_FAILURE; + if (handle->principal == NULL) { + kret = krb5_sname_to_principal(gssapi_krb5_context, NULL, NULL, + KRB5_NT_SRV_HST, &handle->principal); + if (kret) + goto end; + } + kret = get_keytab(&handle->keytab); + if (kret) + goto end; + ret = GSS_S_COMPLETE; + +end: + if (ret != GSS_S_COMPLETE) { + if (handle->keytab != NULL) + krb5_kt_close(gssapi_krb5_context, handle->keytab); + if (kret != 0) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + } + } + return (ret); +} + OM_uint32 gss_acquire_cred (OM_uint32 * minor_status, const gss_name_t desired_name, @@ -48,141 +200,56 @@ OM_uint32 gss_acquire_cred { gss_cred_id_t handle; OM_uint32 ret; - krb5_error_code kret = 0; - krb5_ccache ccache; gssapi_krb5_init (); + *minor_status = 0; handle = (gss_cred_id_t)malloc(sizeof(*handle)); if (handle == GSS_C_NO_CREDENTIAL) - return GSS_S_FAILURE; + return (GSS_S_FAILURE); memset(handle, 0, sizeof (*handle)); if (desired_name != NULL) { - ret = gss_duplicate_name(minor_status, desired_name, &handle->principal); - if (ret) { + ret = gss_duplicate_name(minor_status, desired_name, + &handle->principal); + if (ret != GSS_S_COMPLETE) { free(handle); - return ret; + return (ret); } } - - if (krb5_cc_default(gssapi_krb5_context, &ccache) == 0) { - krb5_principal def_princ; - - if (krb5_cc_get_principal(gssapi_krb5_context, ccache, - &def_princ) != 0) { - krb5_cc_close(gssapi_krb5_context, ccache); - goto try_keytab; + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { + ret = acquire_initiator_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, handle, actual_mechs, time_rec); + if (ret != GSS_S_COMPLETE) { + free(handle); + return (ret); } - if (handle->principal == NULL) { - ret = gss_duplicate_name(minor_status, def_princ, &handle->principal); - if (ret) { - free(handle); - krb5_free_principal(gssapi_krb5_context, def_princ); - krb5_cc_close(gssapi_krb5_context, ccache); - return ret; - } - } else if (krb5_principal_compare(gssapi_krb5_context, handle->principal, - def_princ) == FALSE) { - krb5_free_principal(gssapi_krb5_context, def_princ); - krb5_cc_close(gssapi_krb5_context, ccache); - goto try_keytab; - } - handle->ccache = ccache; - handle->keytab = NULL; - krb5_free_principal(gssapi_krb5_context, def_princ); - } else { - krb5_creds cred; - krb5_get_init_creds_opt opt; - - try_keytab: - if (gssapi_krb5_keytab != NULL) { - char kt_name[256]; - - kret = krb5_kt_get_name(gssapi_krb5_context, - gssapi_krb5_keytab, - kt_name, sizeof(kt_name)); - if (kret) - goto krb5_bad; - kret = krb5_kt_resolve(gssapi_krb5_context, kt_name, - &handle->keytab); - if (kret) - goto krb5_bad; - } else { - kret = krb5_kt_default(gssapi_krb5_context, &handle->keytab); - if (kret != 0) - goto krb5_bad; - } - - krb5_get_init_creds_opt_init(&opt); - memset(&cred, 0, sizeof(cred)); - - kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred, - handle->principal, handle->keytab, - 0, NULL, &opt); - if (kret != 0) - goto krb5_bad; - - kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops, - &handle->ccache); - if (kret != 0) { - krb5_free_creds_contents(gssapi_krb5_context, &cred); - goto krb5_bad; - } - - kret = krb5_cc_initialize(gssapi_krb5_context, handle->ccache, - cred.client); - if (kret != 0) { - krb5_free_creds_contents(gssapi_krb5_context, &cred); - goto krb5_bad; - } - - kret = krb5_cc_store_cred(gssapi_krb5_context, handle->ccache, &cred); - if (kret != 0) { - krb5_free_creds_contents(gssapi_krb5_context, &cred); - goto krb5_bad; - } - - krb5_free_creds_contents(gssapi_krb5_context, &cred); } - + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { + ret = acquire_acceptor_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, handle, actual_mechs, time_rec); + if (ret != GSS_S_COMPLETE) { + free(handle); + return (ret); + } + } + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, + actual_mechs); + if (ret != GSS_S_COMPLETE) { + if (handle->mechanisms != NULL) + gss_release_oid_set(NULL, &handle->mechanisms); + free(handle); + return (ret); + } /* XXX */ handle->lifetime = time_req; handle->usage = cred_usage; - - ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); - if (ret) - goto gssapi_bad; - - ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, - &handle->mechanisms); - if (ret) - goto gssapi_bad; - - ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, - actual_mechs); - if (ret) - goto gssapi_bad; - *output_cred_handle = handle; return (GSS_S_COMPLETE); - - krb5_bad: - ret = GSS_S_FAILURE; - *minor_status = kret; - gssapi_krb5_set_error_string (); - - gssapi_bad: - krb5_free_principal(gssapi_krb5_context, handle->principal); - if (handle->ccache != NULL) - krb5_cc_close(gssapi_krb5_context, handle->ccache); - if (handle->keytab != NULL) - krb5_kt_close(gssapi_krb5_context, handle->keytab); - if (handle->mechanisms != NULL) - gss_release_oid_set(NULL, &handle->mechanisms); - - free(handle); - - return (ret); } diff --git a/lib/gssapi/krb5/acquire_cred.c b/lib/gssapi/krb5/acquire_cred.c index f4d97b71f..a9cdaadaa 100644 --- a/lib/gssapi/krb5/acquire_cred.c +++ b/lib/gssapi/krb5/acquire_cred.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -35,6 +35,158 @@ RCSID("$Id$"); +static krb5_error_code +get_keytab(krb5_keytab *keytab) +{ + char kt_name[256]; + krb5_error_code kret; + + if (gssapi_krb5_keytab != NULL) { + kret = krb5_kt_get_name(gssapi_krb5_context, + gssapi_krb5_keytab, + kt_name, sizeof(kt_name)); + if (kret == 0) + kret = krb5_kt_resolve(gssapi_krb5_context, kt_name, keytab); + } else + kret = krb5_kt_default(gssapi_krb5_context, keytab); + return (kret); +} + +static OM_uint32 acquire_initiator_cred + (OM_uint32 * minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_creds cred; + krb5_principal def_princ; + krb5_get_init_creds_opt opt; + krb5_ccache ccache; + krb5_keytab keytab; + krb5_error_code kret; + + keytab = NULL; + ccache = NULL; + def_princ = NULL; + ret = GSS_S_FAILURE; + memset(&cred, 0, sizeof(cred)); + + kret = krb5_cc_default(gssapi_krb5_context, &ccache); + if (kret) + goto end; + kret = krb5_cc_get_principal(gssapi_krb5_context, ccache, + &def_princ); + if (kret != 0) { + /* we'll try to use a keytab below */ + krb5_cc_destroy(gssapi_krb5_context, ccache); + ccache = NULL; + kret = 0; + } else if (handle->principal == NULL) { + kret = krb5_copy_principal(gssapi_krb5_context, def_princ, + &handle->principal); + if (kret) + goto end; + } else if (handle->principal != NULL && + krb5_principal_compare(gssapi_krb5_context, handle->principal, + def_princ) == FALSE) { + kret = KRB5_PRINC_NOMATCH; + goto end; + } + if (def_princ == NULL) { + /* We have no existing credentials cache, + * so attempt to get a TGT using a keytab. + */ + if (handle->principal == NULL) { + kret = krb5_get_default_principal(gssapi_krb5_context, + &handle->principal); + if (kret) + goto end; + } + kret = get_keytab(&keytab); + if (kret) + goto end; + krb5_get_init_creds_opt_init(&opt); + kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred, + handle->principal, keytab, 0, NULL, &opt); + if (kret) + goto end; + kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops, + &ccache); + if (kret) + goto end; + kret = krb5_cc_initialize(gssapi_krb5_context, ccache, cred.client); + if (kret) + goto end; + kret = krb5_cc_store_cred(gssapi_krb5_context, ccache, &cred); + if (kret) + goto end; + } + handle->ccache = ccache; + ret = GSS_S_COMPLETE; + +end: + if (cred.client != NULL) + krb5_free_creds_contents(gssapi_krb5_context, &cred); + if (def_princ != NULL) + krb5_free_principal(gssapi_krb5_context, def_princ); + if (keytab != NULL) + krb5_kt_close(gssapi_krb5_context, keytab); + if (ret != GSS_S_COMPLETE) { + if (ccache != NULL) + krb5_cc_close(gssapi_krb5_context, ccache); + if (kret != 0) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + } + } + return (ret); +} + +static OM_uint32 acquire_acceptor_cred + (OM_uint32 * minor_status, + const gss_name_t desired_name, + OM_uint32 time_req, + const gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t handle, + gss_OID_set * actual_mechs, + OM_uint32 * time_rec + ) +{ + OM_uint32 ret; + krb5_error_code kret; + + kret = 0; + ret = GSS_S_FAILURE; + if (handle->principal == NULL) { + kret = krb5_sname_to_principal(gssapi_krb5_context, NULL, NULL, + KRB5_NT_SRV_HST, &handle->principal); + if (kret) + goto end; + } + kret = get_keytab(&handle->keytab); + if (kret) + goto end; + ret = GSS_S_COMPLETE; + +end: + if (ret != GSS_S_COMPLETE) { + if (handle->keytab != NULL) + krb5_kt_close(gssapi_krb5_context, handle->keytab); + if (kret != 0) { + *minor_status = kret; + gssapi_krb5_set_error_string (); + } + } + return (ret); +} + OM_uint32 gss_acquire_cred (OM_uint32 * minor_status, const gss_name_t desired_name, @@ -48,141 +200,56 @@ OM_uint32 gss_acquire_cred { gss_cred_id_t handle; OM_uint32 ret; - krb5_error_code kret = 0; - krb5_ccache ccache; gssapi_krb5_init (); + *minor_status = 0; handle = (gss_cred_id_t)malloc(sizeof(*handle)); if (handle == GSS_C_NO_CREDENTIAL) - return GSS_S_FAILURE; + return (GSS_S_FAILURE); memset(handle, 0, sizeof (*handle)); if (desired_name != NULL) { - ret = gss_duplicate_name(minor_status, desired_name, &handle->principal); - if (ret) { + ret = gss_duplicate_name(minor_status, desired_name, + &handle->principal); + if (ret != GSS_S_COMPLETE) { free(handle); - return ret; + return (ret); } } - - if (krb5_cc_default(gssapi_krb5_context, &ccache) == 0) { - krb5_principal def_princ; - - if (krb5_cc_get_principal(gssapi_krb5_context, ccache, - &def_princ) != 0) { - krb5_cc_close(gssapi_krb5_context, ccache); - goto try_keytab; + if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) { + ret = acquire_initiator_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, handle, actual_mechs, time_rec); + if (ret != GSS_S_COMPLETE) { + free(handle); + return (ret); } - if (handle->principal == NULL) { - ret = gss_duplicate_name(minor_status, def_princ, &handle->principal); - if (ret) { - free(handle); - krb5_free_principal(gssapi_krb5_context, def_princ); - krb5_cc_close(gssapi_krb5_context, ccache); - return ret; - } - } else if (krb5_principal_compare(gssapi_krb5_context, handle->principal, - def_princ) == FALSE) { - krb5_free_principal(gssapi_krb5_context, def_princ); - krb5_cc_close(gssapi_krb5_context, ccache); - goto try_keytab; - } - handle->ccache = ccache; - handle->keytab = NULL; - krb5_free_principal(gssapi_krb5_context, def_princ); - } else { - krb5_creds cred; - krb5_get_init_creds_opt opt; - - try_keytab: - if (gssapi_krb5_keytab != NULL) { - char kt_name[256]; - - kret = krb5_kt_get_name(gssapi_krb5_context, - gssapi_krb5_keytab, - kt_name, sizeof(kt_name)); - if (kret) - goto krb5_bad; - kret = krb5_kt_resolve(gssapi_krb5_context, kt_name, - &handle->keytab); - if (kret) - goto krb5_bad; - } else { - kret = krb5_kt_default(gssapi_krb5_context, &handle->keytab); - if (kret != 0) - goto krb5_bad; - } - - krb5_get_init_creds_opt_init(&opt); - memset(&cred, 0, sizeof(cred)); - - kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred, - handle->principal, handle->keytab, - 0, NULL, &opt); - if (kret != 0) - goto krb5_bad; - - kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops, - &handle->ccache); - if (kret != 0) { - krb5_free_creds_contents(gssapi_krb5_context, &cred); - goto krb5_bad; - } - - kret = krb5_cc_initialize(gssapi_krb5_context, handle->ccache, - cred.client); - if (kret != 0) { - krb5_free_creds_contents(gssapi_krb5_context, &cred); - goto krb5_bad; - } - - kret = krb5_cc_store_cred(gssapi_krb5_context, handle->ccache, &cred); - if (kret != 0) { - krb5_free_creds_contents(gssapi_krb5_context, &cred); - goto krb5_bad; - } - - krb5_free_creds_contents(gssapi_krb5_context, &cred); } - + if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) { + ret = acquire_acceptor_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, handle, actual_mechs, time_rec); + if (ret != GSS_S_COMPLETE) { + free(handle); + return (ret); + } + } + ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, + &handle->mechanisms); + if (ret == GSS_S_COMPLETE) + ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, + actual_mechs); + if (ret != GSS_S_COMPLETE) { + if (handle->mechanisms != NULL) + gss_release_oid_set(NULL, &handle->mechanisms); + free(handle); + return (ret); + } /* XXX */ handle->lifetime = time_req; handle->usage = cred_usage; - - ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms); - if (ret) - goto gssapi_bad; - - ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM, - &handle->mechanisms); - if (ret) - goto gssapi_bad; - - ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL, - actual_mechs); - if (ret) - goto gssapi_bad; - *output_cred_handle = handle; return (GSS_S_COMPLETE); - - krb5_bad: - ret = GSS_S_FAILURE; - *minor_status = kret; - gssapi_krb5_set_error_string (); - - gssapi_bad: - krb5_free_principal(gssapi_krb5_context, handle->principal); - if (handle->ccache != NULL) - krb5_cc_close(gssapi_krb5_context, handle->ccache); - if (handle->keytab != NULL) - krb5_kt_close(gssapi_krb5_context, handle->keytab); - if (handle->mechanisms != NULL) - gss_release_oid_set(NULL, &handle->mechanisms); - - free(handle); - - return (ret); }