diff options
author | Theodore Tso <tytso@mit.edu> | 1993-12-18 03:14:21 +0000 |
---|---|---|
committer | Theodore Tso <tytso@mit.edu> | 1993-12-18 03:14:21 +0000 |
commit | 870d5a01e997b76cae1ad120c6c003edddab5205 (patch) | |
tree | c4acc37dae89d396cdb00706d878af4d47972d49 /src/lib/gssapi/krb5/acquire_cred.c | |
parent | bb08b522cb5381f36cb012220a1ecb47d75dee10 (diff) | |
download | krb5-870d5a01e997b76cae1ad120c6c003edddab5205.tar.gz krb5-870d5a01e997b76cae1ad120c6c003edddab5205.tar.xz krb5-870d5a01e997b76cae1ad120c6c003edddab5205.zip |
As submitted by Openvision Technologies:
To: tytso@MIT.EDU
Subject: gssapi
Date: Fri, 17 Dec 1993 17:55:06 -0500
From: Marc Horowitz <marc@security.ov.com>
This is named in my RCS tree as MIT931217. The copyright notice
included is (hopefully) final. Good luck!
Marc
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@3205 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src/lib/gssapi/krb5/acquire_cred.c')
-rw-r--r-- | src/lib/gssapi/krb5/acquire_cred.c | 418 |
1 files changed, 418 insertions, 0 deletions
diff --git a/src/lib/gssapi/krb5/acquire_cred.c b/src/lib/gssapi/krb5/acquire_cred.c new file mode 100644 index 0000000000..d09c708094 --- /dev/null +++ b/src/lib/gssapi/krb5/acquire_cred.c @@ -0,0 +1,418 @@ +/* + * Copyright 1993 by OpenVision Technologies, Inc. + * + * Permission to use, copy, modify, distribute, and sell this software + * and its documentation for any purpose is hereby granted without fee, + * provided that the above copyright notice appears in all copies and + * that both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of OpenVision not be used + * in advertising or publicity pertaining to distribution of the software + * without specific, written prior permission. OpenVision makes no + * representations about the suitability of this software for any + * purpose. It is provided "as is" without express or implied warranty. + * + * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, + * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO + * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF + * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR + * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR + * PERFORMANCE OF THIS SOFTWARE. + */ + +#include "gssapiP_krb5.h" + +/* + * $Id$ + */ + +/* get credentials corresponding to a key in the krb5 keytab. + If the default name is requested, return the name in output_princ. + If output_princ is non-NULL, the caller will use or free it, regardless + of the return value. + If successful, set the keytab-specific fields in cred + */ + +static OM_uint32 +acquire_accept_cred(OM_uint32 *minor_status, + gss_name_t desired_name, + krb5_principal *output_princ, + krb5_gss_cred_id_rec *cred) +{ + krb5_error_code code; + krb5_principal princ; + krb5_keytab kt; + krb5_keytab_entry entry; + krb5_kt_cursor cur; + + *output_princ = NULL; + cred->keytab = NULL; + + /* open the default keytab */ + + if (code = krb5_kt_default(&kt)) { + *minor_status = code; + return(GSS_S_CRED_UNAVAIL); + } + + /* figure out what principal to use. If the default name is + requested, use the default sn2princ output */ + + if (desired_name == GSS_C_NO_NAME) { + if (code = krb5_sname_to_principal(NULL, NULL, KRB5_NT_SRV_HST, + &princ)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + *output_princ = princ; + } else { + princ = (krb5_principal) desired_name; + } + + /* iterate over the keytab searching for the principal */ + + if (code = krb5_kt_start_seq_get(kt, &cur)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + + while (!(code = krb5_kt_next_entry(kt, &entry, &cur))) { + if (krb5_principal_compare(entry.principal, princ)) { + code = 0; + krb5_kt_free_entry(&entry); + break; + } + krb5_kt_free_entry(&entry); + } + + if (code == KRB5_KT_END) { + /* this means that the principal wasn't in the keytab */ + (void)krb5_kt_end_seq_get(kt, &cur); + *minor_status = KG_KEYTAB_NOMATCH; + return(GSS_S_CRED_UNAVAIL); + } else if (code) { + /* this means some error occurred reading the keytab */ + (void)krb5_kt_end_seq_get(kt, &cur); + *minor_status = code; + return(GSS_S_FAILURE); + } else { + /* this means that we found a matching entry */ + if (code = krb5_kt_end_seq_get(kt, &cur)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + } + + /* hooray. we made it */ + + cred->keytab = kt; + return(GSS_S_COMPLETE); +} + +/* get credentials corresponding to the default credential cache. + If the default name is requested, return the name in output_princ. + If output_princ is non-NULL, the caller will use or free it, regardless + of the return value. + If successful, set the ccache-specific fields in cred. + */ + +static OM_uint32 +acquire_init_cred(OM_uint32 *minor_status, + gss_name_t desired_name, + krb5_principal *output_princ, + krb5_gss_cred_id_rec *cred) +{ + krb5_error_code code; + krb5_ccache ccache; + krb5_principal princ; + krb5_flags flags; + krb5_cc_cursor cur; + krb5_creds creds; + int got_endtime; + + cred->ccache = NULL; + + /* open the default credential cache */ + + if (code = krb5_cc_default(&ccache)) { + *minor_status = code; + return(GSS_S_CRED_UNAVAIL); + } + + /* turn off OPENCLOSE mode while extensive frobbing is going on */ + + flags = 0; /* turns off OPENCLOSE mode */ + if (code = krb5_cc_set_flags(ccache, flags)) { + *minor_status = code; + return(GSS_S_FAILURE); + } + + /* get out the principal name and see if it matches */ + + if (code = krb5_cc_get_principal(ccache, &princ)) { + (void)krb5_cc_close(ccache); + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (desired_name != GSS_C_NO_NAME) { + if (! krb5_principal_compare(princ, (krb5_principal) desired_name)) { + (void)krb5_free_principal(princ); + (void)krb5_cc_close(ccache); + *minor_status = KG_CCACHE_NOMATCH; + return(GSS_S_CRED_UNAVAIL); + } + (void)krb5_free_principal(princ); + princ = (krb5_principal) desired_name; + } else { + *output_princ = princ; + } + + /* iterate over the ccache, find the tgt */ + + if (code = krb5_cc_start_seq_get(ccache, &cur)) { + (void)krb5_cc_close(ccache); + *minor_status = code; + return(GSS_S_FAILURE); + } + + /* this is hairy. If there's a tgt for the principal's local realm + in here, that's what we want for the expire time. But if + there's not, then we want to use the first key. */ + + got_endtime = 0; + + while (!(code = krb5_cc_next_cred(ccache, &cur, &creds))) { + if ((creds.server->length == 2) && + (strcmp(creds.server->realm.data, princ->realm.data) == 0) && + (strcmp((char *) creds.server->data[0].data, "krbtgt") == 0) && + (strcmp((char *) creds.server->data[1].data, + princ->realm.data) == 0)) { + cred->tgt_expire = creds.times.endtime; + got_endtime = 1; + *minor_status = 0; + code = 0; + krb5_free_cred_contents(&creds); + break; + } + if (got_endtime == 0) { + cred->tgt_expire = creds.times.endtime; + got_endtime = 1; + *minor_status = KG_TGT_MISSING; + } + krb5_free_cred_contents(&creds); + } + + if (code && code != KRB5_CC_END) { + /* this means some error occurred reading the ccache */ + (void)krb5_cc_end_seq_get(ccache, &cur); + (void)krb5_cc_close(ccache); + *minor_status = code; + return(GSS_S_FAILURE); + } else { + /* this means that we found an endtime to use. */ + if (code = krb5_cc_end_seq_get(ccache, &cur)) { + (void)krb5_cc_close(ccache); + *minor_status = code; + return(GSS_S_FAILURE); + } + flags = KRB5_TC_OPENCLOSE; /* turns on OPENCLOSE mode */ + if (code = krb5_cc_set_flags(ccache, flags)) { + (void)krb5_cc_close(ccache); + *minor_status = code; + return(GSS_S_FAILURE); + } + } + + /* the credentials match and are valid */ + + cred->ccache = ccache; + /* minor_status is set while we are iterating over the ccache */ + return(GSS_S_COMPLETE); +} + +/*ARGSUSED*/ +OM_uint32 +krb5_gss_acquire_cred(OM_uint32 *minor_status, + gss_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + int cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + int i; + krb5_gss_cred_id_t cred; + gss_OID_set mechs; + OM_uint32 ret; + krb5_error_code code; + + /* make sure all outputs are valid */ + + *output_cred_handle = NULL; + if (actual_mechs) + *actual_mechs = NULL; + if (time_rec) + *time_rec = 0; + + /* validate the name */ + + /*SUPPRESS 29*/ + if ((desired_name != GSS_C_NO_NAME) && + (! kg_validate_name(desired_name))) { + *minor_status = G_VALIDATE_FAILED; + return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); + } + + /* verify that the requested mechanism set is the default, or + contains krb5 */ + + if (desired_mechs != GSS_C_NULL_OID_SET) { + for (i=0; i<desired_mechs->count; i++) + if (g_OID_equal(gss_mech_krb5, &(desired_mechs->elements[i]))) + break; + if (i == desired_mechs->count) { + *minor_status = 0; + return(GSS_S_BAD_MECH); + } + } + + /* create the gss cred structure */ + + if ((cred = + (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) == NULL) { + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + + cred->usage = cred_usage; + cred->princ = NULL; + + cred->keytab = NULL; + cred->ccache = NULL; + + if ((cred_usage != GSS_C_INITIATE) && + (cred_usage != GSS_C_ACCEPT) && + (cred_usage != GSS_C_BOTH)) { + xfree(cred); + *minor_status = G_BAD_USAGE; + return(GSS_S_FAILURE); + } + + /* if requested, acquire credentials for accepting */ + /* this will fill in cred->princ if the desired_name is not specified */ + + if ((cred_usage == GSS_C_ACCEPT) || + (cred_usage == GSS_C_BOTH)) + if ((ret = acquire_accept_cred(minor_status, desired_name, + &(cred->princ), cred)) + != GSS_S_COMPLETE) { + if (cred->princ) + krb5_free_principal(cred->princ); + xfree(cred); + /* minor_status set by acquire_accept_cred() */ + return(ret); + } + + /* if requested, acquire credentials for initiation */ + /* this will fill in cred->princ if it wasn't set above, and + the desired_name is not specified */ + + if ((cred_usage == GSS_C_INITIATE) || + (cred_usage == GSS_C_BOTH)) + if ((ret = + acquire_init_cred(minor_status, + cred->princ?cred->princ:desired_name, + &(cred->princ), cred)) + != GSS_S_COMPLETE) { + if (cred->keytab) + krb5_kt_close(cred->keytab); + if (cred->princ) + krb5_free_principal(cred->princ); + xfree(cred); + /* minor_status set by acquire_init_cred() */ + return(ret); + } + + /* if the princ wasn't filled in already, fill it in now */ + + if (!cred->princ) + if (code = krb5_copy_principal((krb5_principal) desired_name, + &(cred->princ))) { + if (cred->ccache) + (void)krb5_cc_close(cred->ccache); + if (cred->keytab) + (void)krb5_kt_close(cred->keytab); + xfree(cred); + *minor_status = code; + return(GSS_S_FAILURE); + } + + /*** at this point, the cred structure has been completely created */ + + /* compute time_rec */ + + if (cred_usage == GSS_C_ACCEPT) { + if (time_rec) + *time_rec = GSS_C_INDEFINITE; + } else { + krb5_timestamp now; + + if (code = krb5_timeofday(&now)) { + if (cred->ccache) + (void)krb5_cc_close(cred->ccache); + if (cred->keytab) + (void)krb5_kt_close(cred->keytab); + if (cred->princ) + krb5_free_principal(cred->princ); + xfree(cred); + *minor_status = code; + return(GSS_S_FAILURE); + } + + if (time_rec) + *time_rec = cred->tgt_expire - now; + } + + /* create mechs */ + + if (actual_mechs) { + if (! g_copy_OID_set(gss_mech_set_krb5, &mechs)) { + if (cred->ccache) + (void)krb5_cc_close(cred->ccache); + if (cred->keytab) + (void)krb5_kt_close(cred->keytab); + if (cred->princ) + krb5_free_principal(cred->princ); + xfree(cred); + *minor_status = ENOMEM; + return(GSS_S_FAILURE); + } + } + + /* intern the credential handle */ + + if (! kg_save_cred_id((gss_cred_id_t) cred)) { + free(mechs->elements); + free(mechs); + if (cred->ccache) + (void)krb5_cc_close(cred->ccache); + if (cred->keytab) + (void)krb5_kt_close(cred->keytab); + if (cred->princ) + krb5_free_principal(cred->princ); + xfree(cred); + *minor_status = G_VALIDATE_FAILED; + return(GSS_S_FAILURE); + } + + /* return success */ + + *minor_status = 0; + *output_cred_handle = (gss_cred_id_t) cred; + if (actual_mechs) + *actual_mechs = mechs; + + return(GSS_S_COMPLETE); +} |