From 6c721c6f56bc77ea1537c9cfcaa9856ec14a4b71 Mon Sep 17 00:00:00 2001 From: Chris Provenzano Date: Mon, 27 Mar 1995 14:49:55 +0000 Subject: [PATCH] * Makefile.in: Removed rd_req_sim.c * auth_con.c: Default cksumtype is now CKSUMTYPE_RSA_MD4_DES. * auth_con.c: Added krb5_auth_con_setuseruserkey(), krb5_auth_con_getkey(), krb5_auth_con_getremotesubkey(), krb5_auth_con_getauthenticator(), krb5_auth_con_getremoteseqnumber(), krb5_auth_con_initivector(). * auth_con.c: Fixed krb5_auth_con_getlocalsubkey() to check for a valid local_subkey before calling krb5_copy_keyblock(). * auth_con.h: Fixed some comments. * mk_req_ext.c (krb5_mk_req_extended()): Always pass in a seed (the keyblock contents) to krb5_calculate_checksum() * rd_rep.c (krb5_rd_rep()): Use appropriate key to decode reply. * rd_safe.c (krb5_rd_safe()): Don't pass checksum to krb5_rd_safe_basic(), it's unnecessary. * compat_recv.c (krb5_compat_recvauth()): * mk_rep.c (krb5_mk_rep()): * rd_req.c (krb5_rd_req()): * rd_req_dec.c (krb5_rd_req_decode()): * recvauth.c (krb5_recvauth()): Added a krb5_auth_context argument and eliminated many of the other arguments because they are included in the krb5_auth_context structure. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5265 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/krb/ChangeLog | 38 +++++ src/lib/krb5/krb/Makefile.in | 2 - src/lib/krb5/krb/auth_con.c | 88 +++++++++- src/lib/krb5/krb/auth_con.h | 4 +- src/lib/krb5/krb/compat_recv.c | 33 ++-- src/lib/krb5/krb/mk_rep.c | 101 ++++++------ src/lib/krb5/krb/mk_req_ext.c | 18 ++- src/lib/krb5/krb/rd_rep.c | 16 +- src/lib/krb5/krb/rd_req.c | 72 ++++++--- src/lib/krb5/krb/rd_req_dec.c | 282 +++++++++++++++++---------------- src/lib/krb5/krb/rd_safe.c | 4 +- src/lib/krb5/krb/recvauth.c | 196 +++++++---------------- 12 files changed, 462 insertions(+), 392 deletions(-) diff --git a/src/lib/krb5/krb/ChangeLog b/src/lib/krb5/krb/ChangeLog index 80fef45ef..ae4ffe843 100644 --- a/src/lib/krb5/krb/ChangeLog +++ b/src/lib/krb5/krb/ChangeLog @@ -1,8 +1,46 @@ + +Mon Mar 27 08:34:49 1995 Chris Provenzano (proven@mit.edu) + + * Makefile.in: Removed rd_req_sim.c + + * auth_con.c: Default cksumtype is now CKSUMTYPE_RSA_MD4_DES. + + * auth_con.c: Added krb5_auth_con_setuseruserkey(), + krb5_auth_con_getkey(), + krb5_auth_con_getremotesubkey(), + krb5_auth_con_getauthenticator(), + krb5_auth_con_getremoteseqnumber(), + krb5_auth_con_initivector(). + + * auth_con.c: Fixed krb5_auth_con_getlocalsubkey() to check for + a valid local_subkey before calling krb5_copy_keyblock(). + + * auth_con.h: Fixed some comments. + + * mk_req_ext.c (krb5_mk_req_extended()): Always pass in a seed + (the keyblock contents) to krb5_calculate_checksum() + + * rd_rep.c (krb5_rd_rep()): Use appropriate key to decode reply. + + * rd_safe.c (krb5_rd_safe()): Don't pass checksum to + krb5_rd_safe_basic(), it's unnecessary. + + * compat_recv.c (krb5_compat_recvauth()): + * mk_rep.c (krb5_mk_rep()): + * rd_req.c (krb5_rd_req()): + * rd_req_dec.c (krb5_rd_req_decode()): + * recvauth.c (krb5_recvauth()): + Added a krb5_auth_context argument and eliminated many of + the other arguments because they are included in the + krb5_auth_context structure. + + Tue Mar 21 19:22:51 1995 Keith Vetter (keithv@fusion.com) * mk_safe.c: fixed signed/unsigned mismatch. * rd_safe.c: removed unused local variable currentime. * mk_req_e.c: fixed signed/unsigned mismatch. + Sat Mar 18 18:58:02 1995 John Gilmore (gnu at toad.com) * bld_pr_ext.c, bld_princ.c: Replace STDARG_PROTOTYPES with diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index 9407ee57e..b61596224 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -59,7 +59,6 @@ OBJS= addr_comp.$(OBJEXT) \ rd_priv.$(OBJEXT) \ rd_rep.$(OBJEXT) \ rd_req.$(OBJEXT) \ - rd_req_sim.$(OBJEXT) \ rd_req_dec.$(OBJEXT) \ rd_safe.$(OBJEXT) \ recvauth.$(OBJEXT) \ @@ -125,7 +124,6 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/rd_priv.c \ $(srcdir)/rd_rep.c \ $(srcdir)/rd_req.c \ - $(srcdir)/rd_req_sim.c \ $(srcdir)/rd_req_dec.c \ $(srcdir)/rd_safe.c \ $(srcdir)/recvauth.c \ diff --git a/src/lib/krb5/krb/auth_con.c b/src/lib/krb5/krb/auth_con.c index 571e38c3f..ebf72a790 100644 --- a/src/lib/krb5/krb/auth_con.c +++ b/src/lib/krb5/krb/auth_con.c @@ -14,7 +14,8 @@ krb5_auth_con_init(context, auth_context) (*auth_context)->auth_context_flags = KRB5_AUTH_CONTEXT_DO_TIME | KRB5_AUTH_CONN_INITIALIZED; - (*auth_context)->cksumtype = CKSUMTYPE_CRC32; + (*auth_context)->cksumtype = CKSUMTYPE_RSA_MD4_DES; + /* (*auth_context)->cksumtype = CKSUMTYPE_CRC32; */ return 0; } return ENOMEM; @@ -61,13 +62,58 @@ krb5_auth_con_setkey(context, auth_context, keyblock) return(krb5_copy_keyblock(context, keyblock, &(auth_context->keyblock))); } +/* + * This function overloads the keyblock field. It is only useful prior to + * a krb5_rd_req_decode() call for user to user authentication where the + * server has the key and needs to use it to decrypt the incoming request. + * Once decrypted this key is no longer necessary and is then overwritten + * with the session key sent by the client. + */ +krb5_error_code INTERFACE +krb5_auth_con_setuseruserkey(context, auth_context, keyblock) + krb5_context context; + krb5_auth_context * auth_context; + krb5_keyblock * keyblock; +{ + if (auth_context->keyblock) + krb5_free_keyblock(context, auth_context->keyblock); + return(krb5_copy_keyblock(context, keyblock, &(auth_context->keyblock))); +} + +krb5_error_code INTERFACE +krb5_auth_con_getkey(context, auth_context, keyblock) + krb5_context context; + krb5_auth_context * auth_context; + krb5_keyblock ** keyblock; +{ + if (auth_context->keyblock) + return krb5_copy_keyblock(context, auth_context->keyblock, keyblock); + *keyblock = NULL; + return 0; +} + krb5_error_code INTERFACE krb5_auth_con_getlocalsubkey(context, auth_context, keyblock) krb5_context context; krb5_auth_context * auth_context; krb5_keyblock ** keyblock; { - return(krb5_copy_keyblock(context, auth_context->local_subkey, keyblock)); + if (auth_context->local_subkey) + return krb5_copy_keyblock(context,auth_context->local_subkey,keyblock); + *keyblock = NULL; + return 0; +} + +krb5_error_code INTERFACE +krb5_auth_con_getremotesubkey(context, auth_context, keyblock) + krb5_context context; + krb5_auth_context * auth_context; + krb5_keyblock ** keyblock; +{ + if (auth_context->remote_subkey) + return krb5_copy_keyblock(context,auth_context->remote_subkey,keyblock); + *keyblock = NULL; + return 0; } krb5_error_code INTERFACE @@ -90,6 +136,44 @@ krb5_auth_con_getlocalseqnumber(context, auth_context, seqnumber) return 0; } +krb5_error_code INTERFACE +krb5_auth_con_getauthenticator(context, auth_context, authenticator) + krb5_context context; + krb5_auth_context * auth_context; + krb5_authenticator ** authenticator; +{ + return (krb5_copy_authenticator(context, auth_context->authentp, + authenticator)); +} + +krb5_error_code INTERFACE +krb5_auth_con_getremoteseqnumber(context, auth_context, seqnumber) + krb5_context context; + krb5_auth_context * auth_context; + krb5_int32 * seqnumber; +{ + *seqnumber = auth_context->remote_seq_number; + return 0; +} + +krb5_error_code INTERFACE +krb5_auth_con_initivector(context, auth_context) + krb5_context context; + krb5_auth_context * auth_context; +{ + if (auth_context->keyblock) { + int size = krb5_keytype_array[auth_context->keyblock->keytype]-> + system->block_length; + + if (auth_context->i_vector = (krb5_pointer)malloc(size)) { + memset(auth_context->i_vector, 0, size); + return 0; + } + return ENOMEM; + } + return EINVAL; /* XXX need an error for no keyblock */ +} + krb5_error_code INTERFACE krb5_auth_con_setivector(context, auth_context, ivector) krb5_context context; diff --git a/src/lib/krb5/krb/auth_con.h b/src/lib/krb5/krb/auth_con.h index 0cf2ed7a2..2188f742d 100644 --- a/src/lib/krb5/krb/auth_con.h +++ b/src/lib/krb5/krb/auth_con.h @@ -12,9 +12,9 @@ struct _krb5_auth_context { krb5_int32 auth_context_flags; krb5_int32 remote_seq_number; krb5_int32 local_seq_number; - krb5_authenticator *authentp; /* mk_req, rd_rep */ + krb5_authenticator *authentp; /* mk_req, rd_req, mk_rep, ...*/ krb5_cksumtype cksumtype; /* mk_safe, ... */ - krb5_pointer i_vector; /* mk_priv only */ + krb5_pointer i_vector; /* mk_priv, rd_priv only */ krb5_rcache rcache; }; diff --git a/src/lib/krb5/krb/compat_recv.c b/src/lib/krb5/krb/compat_recv.c index 8b245ff53..db35f7733 100644 --- a/src/lib/krb5/krb/compat_recv.c +++ b/src/lib/krb5/krb/compat_recv.c @@ -52,30 +52,25 @@ static int krb_v4_recvauth(); #define KRB5_RECVAUTH_V5 5 krb5_error_code -krb5_compat_recvauth(context, - /* IN */ - fdp, appl_version, server, sender_addr, fetch_from, - keyproc, keyprocarg, rc_type, flags, +krb5_compat_recvauth(context, auth_context, + /* IN */ + fdp, appl_version, server, rc_type, flags, keytab, v4_options, v4_service, v4_instance, v4_faddr, v4_laddr, v4_filename, /* OUT */ - auth_sys, seq_number, client, ticket, authent, - v4_kdata, v4_schedule, v4_version) + ticket, + auth_sys, v4_kdata, v4_schedule, v4_version) krb5_context context; + krb5_auth_context **auth_context; krb5_pointer fdp; char *appl_version; krb5_principal server; - krb5_address *sender_addr; - krb5_pointer fetch_from; - krb5_int32 *seq_number; char *rc_type; krb5_int32 flags; - krb5_rdreq_key_proc keyproc; - krb5_pointer keyprocarg; - krb5_principal *client; - krb5_ticket **ticket; - krb5_authenticator **authent; - krb5_int32 *auth_sys; + krb5_keytab keytab; + krb5_ticket ** ticket; + krb5_int32 *auth_sys; + /* * Version 4 arguments */ @@ -189,11 +184,9 @@ krb5_compat_recvauth(context, *auth_sys = KRB5_RECVAUTH_V5; - retval = krb5_recvauth(context, fdp, appl_version, server, sender_addr, - fetch_from, - keyproc, keyprocarg, rc_type, - flags | KRB5_RECVAUTH_SKIP_VERSION, - seq_number, client, ticket, authent); + retval = krb5_recvauth(context, auth_context, fdp, appl_version, server, + rc_type, flags | KRB5_RECVAUTH_SKIP_VERSION, + keytab, ticket); return retval; } diff --git a/src/lib/krb5/krb/mk_rep.c b/src/lib/krb5/krb/mk_rep.c index 27543cac2..b25e67c9a 100644 --- a/src/lib/krb5/krb/mk_rep.c +++ b/src/lib/krb5/krb/mk_rep.c @@ -25,13 +25,11 @@ */ #include "k5-int.h" +#include "auth_con.h" /* Formats a KRB_AP_REP message into outbuf. - The reply in repl is encrypted under the key in kblock, and the resulting - message encoded and left in outbuf. - The outbuf buffer storage is allocated, and should be freed by the caller when finished. @@ -39,37 +37,54 @@ */ krb5_error_code INTERFACE -krb5_mk_rep(context, repl, kblock, outbuf) - krb5_context context; - const krb5_ap_rep_enc_part *repl; - const krb5_keyblock *kblock; - krb5_data *outbuf; +krb5_mk_rep(context, auth_context, outbuf) + krb5_context context; + krb5_auth_context * auth_context; + krb5_data * outbuf; { - krb5_error_code retval; - krb5_data *scratch; - krb5_ap_rep reply; - krb5_enctype etype; - krb5_encrypt_block eblock; - krb5_data *toutbuf; + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_keytype keytype; + krb5_enctype etype; + krb5_ap_rep_enc_part repl; + krb5_encrypt_block eblock; + krb5_ap_rep reply; + krb5_data * scratch; + krb5_data * toutbuf; + + if (auth_context->remote_subkey) + keyblock = auth_context->remote_subkey; + else + keyblock = auth_context->keyblock; /* verify a valid etype is available */ - if (!valid_keytype(kblock->keytype)) + if (!valid_keytype(keytype = keyblock->keytype)) return KRB5_PROG_KEYTYPE_NOSUPP; - etype = krb5_keytype_array[kblock->keytype]->system->proto_enctype; + etype = krb5_keytype_array[keytype]->system->proto_enctype; if (!valid_etype(etype)) return KRB5_PROG_ETYPE_NOSUPP; + /* Make the reply */ + if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || + (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && + (auth_context->local_seq_number == 0)) { + if (retval = krb5_generate_seq_number(context, keyblock, + &auth_context->local_seq_number)) + return(retval); + } + + repl.ctime = auth_context->authentp->ctime; + repl.cusec = auth_context->authentp->cusec; + repl.subkey = auth_context->authentp->subkey; + repl.seq_number = auth_context->local_seq_number; + /* encode it before encrypting */ - if (retval = encode_krb5_ap_rep_enc_part(repl, &scratch)) + if (retval = encode_krb5_ap_rep_enc_part(&repl, &scratch)) return retval; -#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); \ -krb5_free_data(context, scratch); } - /* put together an eblock for this encryption */ - krb5_use_cstype(context, &eblock, etype); reply.enc_part.etype = etype; reply.enc_part.kvno = 0; /* XXX user set? */ @@ -88,50 +103,38 @@ krb5_free_data(context, scratch); } if (!(reply.enc_part.ciphertext.data = malloc(reply.enc_part.ciphertext.length))) { retval = ENOMEM; - goto clean_scratch; + goto cleanup_scratch; } -#define cleanup_encpart() {\ -(void) memset(reply.enc_part.ciphertext.data, 0,\ - reply.enc_part.ciphertext.length); \ -free(reply.enc_part.ciphertext.data); \ -reply.enc_part.ciphertext.length = 0; reply.enc_part.ciphertext.data = 0;} - /* do any necessary key pre-processing */ - if (retval = krb5_process_key(context, &eblock, kblock)) { - goto clean_encpart; - } - -#define cleanup_prockey() {(void) krb5_finish_key(context, &eblock);} + if (retval = krb5_process_key(context, &eblock, keyblock)) + goto cleanup_encpart; /* call the encryption routine */ if (retval = krb5_encrypt(context, (krb5_pointer) scratch->data, (krb5_pointer) reply.enc_part.ciphertext.data, scratch->length, &eblock, 0)) { - goto clean_prockey; + krb5_finish_key(context, &eblock); + goto cleanup_encpart; } - /* encrypted part now assembled-- do some cleanup */ - cleanup_scratch(); - - if (retval = krb5_finish_key(context, &eblock)) { - cleanup_encpart(); - return retval; - } + if (retval = krb5_finish_key(context, &eblock)) + goto cleanup_encpart; if (!(retval = encode_krb5_ap_rep(&reply, &toutbuf))) { *outbuf = *toutbuf; krb5_xfree(toutbuf); } - cleanup_encpart(); - return retval; - clean_prockey: - cleanup_prockey(); - clean_encpart: - cleanup_encpart(); - clean_scratch: - cleanup_scratch(); +cleanup_encpart: + memset(reply.enc_part.ciphertext.data, 0, reply.enc_part.ciphertext.length); + free(reply.enc_part.ciphertext.data); + reply.enc_part.ciphertext.length = 0; + reply.enc_part.ciphertext.data = 0; + +cleanup_scratch: + memset(scratch->data, 0, scratch->length); + krb5_free_data(context, scratch); return retval; } diff --git a/src/lib/krb5/krb/mk_req_ext.c b/src/lib/krb5/krb/mk_req_ext.c index 8aac3917a..1011574e4 100644 --- a/src/lib/krb5/krb/mk_req_ext.c +++ b/src/lib/krb5/krb/mk_req_ext.c @@ -132,16 +132,18 @@ krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, in_creds, /* Generate checksum, XXX What should the seed be? */ - if ((checksum.contents = (krb5_octet *)malloc(krb5_checksum_size( - context, CKSUMTYPE_CRC32))) == NULL) { + if ((checksum.contents = (krb5_octet *)malloc(krb5_checksum_size(context, + (*auth_context)->cksumtype))) == NULL) { retval = ENOMEM; goto cleanup; } if (in_data == NULL) { if (retval = krb5_calculate_checksum(context, - (*auth_context)->cksumtype, - 0, 0, 0, 0, &checksum)) + (*auth_context)->cksumtype, 0, 0, + (*auth_context)->keyblock->contents, + (*auth_context)->keyblock->length, + &checksum)) goto cleanup_cksum; } else if ((*auth_context)->cksumtype == 0x8003) { @@ -151,9 +153,11 @@ krb5_mk_req_extended(context, auth_context, ap_req_options, in_data, in_creds, checksum.contents = (krb5_octet *) in_data->data; } else if (retval = krb5_calculate_checksum(context, - (*auth_context)->cksumtype, - in_data->data, in_data->length, - 0, 0, &checksum)) + (*auth_context)->cksumtype, + in_data->data, in_data->length, + (*auth_context)->keyblock->contents, + (*auth_context)->keyblock->length, + &checksum)) goto cleanup_cksum; /* Generate authenticator */ diff --git a/src/lib/krb5/krb/rd_rep.c b/src/lib/krb5/krb/rd_rep.c index 1dd981611..8ae69eb02 100644 --- a/src/lib/krb5/krb/rd_rep.c +++ b/src/lib/krb5/krb/rd_rep.c @@ -45,10 +45,11 @@ krb5_rd_rep(context, auth_context, inbuf, repl) const krb5_data * inbuf; krb5_ap_rep_enc_part **repl; { - krb5_error_code retval; - krb5_ap_rep *reply; - krb5_encrypt_block eblock; - krb5_data scratch; + krb5_error_code retval; + krb5_ap_rep * reply; + krb5_keyblock * keyblock; + krb5_encrypt_block eblock; + krb5_data scratch; if (!krb5_is_ap_rep(inbuf)) return KRB5KRB_AP_ERR_MSG_TYPE; @@ -72,8 +73,13 @@ krb5_rd_rep(context, auth_context, inbuf, repl) return(ENOMEM); } + if (auth_context->local_subkey) + keyblock = auth_context->local_subkey; + else + keyblock = auth_context->keyblock; + /* do any necessary key pre-processing */ - if (retval = krb5_process_key(context, &eblock, auth_context->keyblock)) { + if (retval = krb5_process_key(context, &eblock, keyblock)) { goto errout; } diff --git a/src/lib/krb5/krb/rd_req.c b/src/lib/krb5/krb/rd_req.c index 6a6875ab1..33f12cc71 100644 --- a/src/lib/krb5/krb/rd_req.c +++ b/src/lib/krb5/krb/rd_req.c @@ -25,18 +25,13 @@ */ #include "k5-int.h" +#include "auth_con.h" /* * Parses a KRB_AP_REQ message, returning its contents. * * server specifies the expected server's name for the ticket. * - * sender_addr specifies the address(es) expected to be present in the - * ticket. - * - * rcache specifies a replay detection cache used to store authenticators and - * server names - * * keyproc specifies a procedure to generate a decryption key for the * ticket. If keyproc is non-NULL, keyprocarg is passed to it, and the result * used as a decryption key. If keyproc is NULL, then fetchfrom is checked; @@ -44,27 +39,25 @@ * decryption key. If fetchfrom is NULL, then the default key store is * consulted. * - * authdat is set to point at allocated storage structures; the caller - * should free them when finished. - * * returns system errors, encryption errors, replay errors */ krb5_error_code INTERFACE -krb5_rd_req(context, inbuf, server, sender_addr, fetchfrom, keyproc, - keyprocarg, rcache, authdat) - krb5_context context; - const krb5_data *inbuf; - krb5_const_principal server; - const krb5_address *sender_addr; - const char * fetchfrom; - krb5_rdreq_key_proc keyproc; - krb5_pointer keyprocarg; - krb5_rcache rcache; - krb5_tkt_authent **authdat; +krb5_rd_req(context, auth_context, inbuf, server, keytab, + ap_req_options, ticket) + krb5_context context; + krb5_auth_context ** auth_context; + const krb5_data * inbuf; + krb5_const_principal server; /* XXX do we really need this */ + krb5_keytab keytab; + krb5_flags * ap_req_options; + krb5_ticket ** ticket; { - krb5_error_code retval; - krb5_ap_req *request; + krb5_error_code retval; + krb5_ap_req * request; + krb5_auth_context * new_auth_context; + krb5_rcache new_rcache; + krb5_keytab new_keytab = NULL; if (!krb5_is_ap_req(inbuf)) return KRB5KRB_AP_ERR_MSG_TYPE; @@ -75,12 +68,41 @@ krb5_rd_req(context, inbuf, server, sender_addr, fetchfrom, keyproc, default: return(retval); } + } + + /* Get an auth context if necessary. */ + new_auth_context = NULL; + if (*auth_context == NULL) { + if (retval = krb5_auth_con_init(context, &new_auth_context)) + goto cleanup_request; + *auth_context = new_auth_context; + } + /* Get an rcache if necessary. */ + if (((*auth_context)->rcache == NULL) && server) { + if (retval = krb5_get_server_rcache(context, + krb5_princ_component(context,server,0), &(*auth_context)->rcache)) + goto cleanup_auth_context; } - retval = krb5_rd_req_decoded(context, request, server, sender_addr, - fetchfrom, keyproc, keyprocarg, rcache, - authdat); + /* Get a keytab if necessary. */ + if (keytab == NULL) { + if (retval = krb5_kt_default(context, &new_keytab)) + goto cleanup_auth_context; + keytab = new_keytab; + } + + retval = krb5_rd_req_decoded(context, auth_context, request, server, + keytab, ap_req_options, ticket); + + if (new_keytab == NULL) + (void) krb5_kt_close(context, new_keytab); + +cleanup_auth_context: + if (new_auth_context && retval) + krb5_auth_con_free(context, new_auth_context); + +cleanup_request: krb5_free_ap_req(context, request); return retval; } diff --git a/src/lib/krb5/krb/rd_req_dec.c b/src/lib/krb5/krb/rd_req_dec.c index e8599795b..85552960a 100644 --- a/src/lib/krb5/krb/rd_req_dec.c +++ b/src/lib/krb5/krb/rd_req_dec.c @@ -27,6 +27,7 @@ */ #include "k5-int.h" +#include "auth_con.h" /* * essentially the same as krb_rd_req, but uses a decoded AP_REQ as @@ -39,9 +40,6 @@ * any server will be accepted if the key can be found, and the caller should * verify that the principal is something it trusts. * - * sender_addr specifies the address(es) expected to be present in the - * ticket. - * * rcache specifies a replay detection cache used to store authenticators and * server names * @@ -64,103 +62,80 @@ static krb5_error_code decrypt_authenticator extern krb5_deltat krb5_clockskew; #define in_clock_skew(date) (labs((date)-currenttime) < krb5_clockskew) -krb5_error_code INTERFACE -krb5_rd_req_decoded(context, req, server, sender_addr, fetchfrom, keyproc, - keyprocarg, rcache, authdat) - krb5_context context; - const krb5_ap_req *req; - krb5_const_principal server; - const krb5_address *sender_addr; - const char * fetchfrom; - krb5_rdreq_key_proc keyproc; - krb5_pointer keyprocarg; - krb5_rcache rcache; - krb5_tkt_authent **authdat; -{ - krb5_keytype keytype; - krb5_error_code retval = 0; - krb5_keyblock *tkt_key = NULL; - krb5_timestamp currenttime, starttime; - krb5_tkt_authent *tktauthent = NULL; +static krb5_error_code +krb5_rd_req_decrypt_tkt_part(context, req, keytab) + krb5_context context; + const krb5_ap_req * req; + krb5_keytab keytab; - if (server && !krb5_principal_compare(context, server, req->ticket->server)) - return KRB5KRB_AP_WRONG_PRINC; +{ + krb5_error_code retval; + krb5_keytype keytype; + krb5_keytab_entry ktent; - /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY) - do we need special processing here ? */ - /* * OK we know the encryption type req->ticket->enc_part.etype, * and now we need to get the keytype */ keytype = krb5_csarray[req->ticket->enc_part.etype]->system->proto_keytype; - /* fetch a server key */ - if (keyproc) { - retval = (*keyproc)(context, keyprocarg, req->ticket->server, - req->ticket->enc_part.kvno, keytype, &tkt_key); - } else { - krb5_keytab keytabid; - krb5_keytab_entry ktentry; - - if (fetchfrom) { - /* use the named keytab */ - retval = krb5_kt_resolve(context, fetchfrom, &keytabid); - } else { - /* use default keytab */ - retval = krb5_kt_default(context, &keytabid); - } - if (!retval) { - retval = krb5_kt_get_entry(context, keytabid, req->ticket->server, - req->ticket->enc_part.kvno, keytype, - &ktentry); - (void) krb5_kt_close(context, keytabid); - if (!retval) { - retval = krb5_copy_keyblock(context, &ktentry.key, &tkt_key); - (void) krb5_kt_free_entry(context, &ktentry); - } - } - } - if (retval) - return retval; /* some error in getting the key */ + if (retval = krb5_kt_get_entry(context, keytab, req->ticket->server, + req->ticket->enc_part.kvno, keytype, &ktent)) + return retval; - /* decrypt the ticket */ - if (retval = krb5_decrypt_tkt_part(context, tkt_key, req->ticket)) { - krb5_free_keyblock(context, tkt_key); - return(retval); - } + if (retval = krb5_decrypt_tkt_part(context, &ktent.key, req->ticket)) + return retval; - /* - * Now we allocate space for the krb5_tkt_authent structure. If - * we ever have an error, we're responsible for freeing it. - */ - if (!(tktauthent = - (krb5_tkt_authent *) malloc(sizeof(*tktauthent)))) { - retval = ENOMEM; - goto cleanup; + (void) krb5_kt_free_entry(context, &ktent); + return retval; +} + +krb5_error_code INTERFACE +krb5_rd_req_decoded(context, auth_context, req, server, keytab, + ap_req_options, ticket) + krb5_context context; + krb5_auth_context ** auth_context; + const krb5_ap_req * req; + krb5_const_principal server; + krb5_keytab keytab; + krb5_flags * ap_req_options; + krb5_ticket ** ticket; +{ + krb5_error_code retval = 0; + krb5_timestamp currenttime, starttime; + + if (server && !krb5_principal_compare(context, server, req->ticket->server)) + return KRB5KRB_AP_WRONG_PRINC; + + /* if (req->ap_options & AP_OPTS_USE_SESSION_KEY) + do we need special processing here ? */ + + /* decrypt the ticket */ + if ((*auth_context)->keyblock) { /* User to User authentication */ + if (retval = krb5_decrypt_tkt_part(context, (*auth_context)->keyblock, + req->ticket)) + return retval; + krb5_free_keyblock(context, (*auth_context)->keyblock); + (*auth_context)->keyblock = NULL; + } else { + if (retval = krb5_rd_req_decrypt_tkt_part(context, req, keytab)) + return retval; } - - memset((char *)tktauthent, 0, sizeof(*tktauthent)); - if (retval = decrypt_authenticator(context, req, &tktauthent->authenticator)) + if (retval = decrypt_authenticator(context, req, + &((*auth_context)->authentp))) goto cleanup; - *authdat = NULL; /* Set authdat to tktauthent when we finish */ - if (!krb5_principal_compare(context, tktauthent->authenticator->client, + if (!krb5_principal_compare(context, (*auth_context)->authentp->client, req->ticket->enc_part2->client)) { retval = KRB5KRB_AP_ERR_BADMATCH; goto cleanup; } - if (sender_addr && !krb5_address_search(context, sender_addr, req->ticket->enc_part2->caddrs)) { - retval = KRB5KRB_AP_ERR_BADADDR; - goto cleanup; - } - - if (retval = krb5_timeofday(context, ¤ttime)) - goto cleanup; - if (!in_clock_skew(tktauthent->authenticator->ctime)) { - retval = KRB5KRB_AP_ERR_SKEW; + if ((*auth_context)->remote_addr && + !krb5_address_search(context, (*auth_context)->remote_addr, + req->ticket->enc_part2->caddrs)) { + retval = KRB5KRB_AP_ERR_BADADDR; goto cleanup; } @@ -170,33 +145,37 @@ krb5_rd_req_decoded(context, req, server, sender_addr, fetchfrom, keyproc, /* Single hop cross-realm tickets only */ - { krb5_transited *trans = &(req->ticket->enc_part2->transited); - - /* If the transited list is empty, then we have at most one hop */ + { + krb5_transited *trans = &(req->ticket->enc_part2->transited); - if (trans->tr_contents.data && trans->tr_contents.data[0]) { - retval = KRB5KRB_AP_ERR_ILL_CR_TKT; - } + /* If the transited list is empty, then we have at most one hop */ + if (trans->tr_contents.data && trans->tr_contents.data[0]) + retval = KRB5KRB_AP_ERR_ILL_CR_TKT; } #elif defined(_NO_CROSS_REALM) /* No cross-realm tickets */ - { char *lrealm; - krb5_data *realm = krb5_princ_realm(context, req->ticket->enc_part2->client); - krb5_transited *trans = &(req->ticket->enc_part2->transited); - - /* If the transited list is empty, then we have at most one hop */ - /* So we also have to check that the client's realm is the local one */ - - krb5_get_default_realm(context, &lrealm); - if ((trans->tr_contents.data && trans->tr_contents.data[0]) || + { + char * lrealm; + krb5_data * realm; + krb5_transited * trans; + + realm = krb5_princ_realm(context, req->ticket->enc_part2->client); + trans = &(req->ticket->enc_part2->transited); + + /* + * If the transited list is empty, then we have at most one hop + * So we also have to check that the client's realm is the local one + */ + krb5_get_default_realm(context, &lrealm); + if ((trans->tr_contents.data && trans->tr_contents.data[0]) || strlen(lrealm) != realm->length || memcmp(lrealm, realm->data, strlen(lrealm))) { - retval = KRB5KRB_AP_ERR_ILL_CR_TKT; - } - free(lrealm); + retval = KRB5KRB_AP_ERR_ILL_CR_TKT; + } + free(lrealm); } #else @@ -204,21 +183,25 @@ krb5_rd_req_decoded(context, req, server, sender_addr, fetchfrom, keyproc, /* Hierarchical Cross-Realm */ { - krb5_data lrealm; - krb5_data *realm = krb5_princ_realm(context, req->ticket->enc_part2->client); - krb5_transited *trans = &(req->ticket->enc_part2->transited); + krb5_data lrealm; + krb5_data * realm; + krb5_transited * trans; - /* If the transited list is not empty, then check that all realms */ - /* transited are within the hierarchy between the client's realm */ - /* and the local realm. */ - - if (trans->tr_contents.data && trans->tr_contents.data[0]) { - krb5_get_default_realm(context, &(lrealm.data)); - lrealm.length = strlen(lrealm.data); - retval = krb5_check_transited_list(context, &(trans->tr_contents), realm, - &lrealm); - free(lrealm.data); - } + realm = krb5_princ_realm(context, req->ticket->enc_part2->client); + trans = &(req->ticket->enc_part2->transited); + + /* + * If the transited list is not empty, then check that all realms + * transited are within the hierarchy between the client's realm + * and the local realm. + */ + if (trans->tr_contents.data && trans->tr_contents.data[0]) { + lrealm.length = strlen(lrealm.data); + krb5_get_default_realm(context, &(lrealm.data)); + retval = krb5_check_transited_list(context, &(trans->tr_contents), + realm, &lrealm); + free(lrealm.data); + } } #endif @@ -227,18 +210,19 @@ krb5_rd_req_decoded(context, req, server, sender_addr, fetchfrom, keyproc, /* only check rcache if sender has provided one---some services may not be able to use replay caches (such as datagram servers) */ - if (rcache) { - krb5_donot_replay rep; - tktauthent->ticket = req->ticket; /* Temporary; allocated below */ - retval = krb5_auth_to_rep(context, tktauthent, &rep); - tktauthent->ticket = 0; /* Don't allow cleanup to free - original ticket. */ - if (retval) - goto cleanup; - retval = krb5_rc_store(context, rcache, &rep); - krb5_xfree(rep.server); - krb5_xfree(rep.client); + if ((*auth_context)->rcache) { + krb5_donot_replay rep; + krb5_tkt_authent tktauthent; + + tktauthent.ticket = req->ticket; + tktauthent.authenticator = (*auth_context)->authentp; + if (!(retval = krb5_auth_to_rep(context, &tktauthent, &rep))) { + retval = krb5_rc_store(context, (*auth_context)->rcache, &rep); + krb5_xfree(rep.server); + krb5_xfree(rep.client); + } + if (retval) goto cleanup; } @@ -249,10 +233,16 @@ krb5_rd_req_decoded(context, req, server, sender_addr, fetchfrom, keyproc, else starttime = req->ticket->enc_part2->times.authtime; + if (retval = krb5_timeofday(context, ¤ttime)) + goto cleanup; if (starttime - currenttime > krb5_clockskew) { retval = KRB5KRB_AP_ERR_TKT_NYV; /* ticket not yet valid */ goto cleanup; } + if (!in_clock_skew((*auth_context)->authentp->ctime)) { + retval = KRB5KRB_AP_ERR_SKEW; + goto cleanup; + } if (currenttime - req->ticket->enc_part2->times.endtime > krb5_clockskew) { retval = KRB5KRB_AP_ERR_TKT_EXPIRED; /* ticket expired */ goto cleanup; @@ -261,25 +251,38 @@ krb5_rd_req_decoded(context, req, server, sender_addr, fetchfrom, keyproc, retval = KRB5KRB_AP_ERR_TKT_INVALID; goto cleanup; } - retval = krb5_copy_ticket(context, req->ticket, &tktauthent->ticket); + + (*auth_context)->remote_seq_number = (*auth_context)->authentp->seq_number; + (*auth_context)->remote_subkey = (*auth_context)->authentp->subkey; + if (retval = krb5_copy_keyblock(context, req->ticket->enc_part2->session, + &((*auth_context)->keyblock))) + goto cleanup; + + /* + * If not AP_OPTS_MUTUAL_REQUIRED then and sequence numbers are used + * then the default sequence number is the one's complement of the + * sequence number sent ot us. + */ + if ((!(req->ap_options & AP_OPTS_MUTUAL_REQUIRED)) && + (*auth_context)->remote_seq_number) { + (*auth_context)->local_seq_number ^= + (*auth_context)->remote_seq_number; + } + + if (ticket) + if (retval = krb5_copy_ticket(context, req->ticket, ticket)) + goto cleanup; + if (ap_req_options) + *ap_req_options = req->ap_options; + retval = 0; cleanup: - if (tktauthent) { - if (retval) { - krb5_free_tkt_authent(context, tktauthent); - } else { - tktauthent->ap_options = req->ap_options; - *authdat = tktauthent; - } - } - if (retval && req->ticket->enc_part2) { + if (retval) { /* only free if we're erroring out...otherwise some applications will need the output. */ krb5_free_enc_tkt_part(context, req->ticket->enc_part2); req->ticket->enc_part2 = NULL; } - if (tkt_key) - krb5_free_keyblock(context, tkt_key); return retval; } @@ -318,9 +321,10 @@ decrypt_authenticator(context, request, authpp) } /* call the encryption routine */ - if (retval = krb5_decrypt(context, (krb5_pointer) request->authenticator.ciphertext.data, - (krb5_pointer) scratch.data, - scratch.length, &eblock, 0)) { + if (retval = krb5_decrypt(context, + (krb5_pointer)request->authenticator.ciphertext.data, + (krb5_pointer)scratch.data, + scratch.length, &eblock, 0)) { (void) krb5_finish_key(context, &eblock); free(scratch.data); return retval; diff --git a/src/lib/krb5/krb/rd_safe.c b/src/lib/krb5/krb/rd_safe.c index 7c0a94ec3..aa5dd3538 100644 --- a/src/lib/krb5/krb/rd_safe.c +++ b/src/lib/krb5/krb/rd_safe.c @@ -164,7 +164,7 @@ cleanup: krb5_error_code INTERFACE krb5_rd_safe(context, auth_context, inbuf, outbuf, outdata) krb5_context context; - krb5_auth_context * auth_context; + krb5_auth_context * auth_context; const krb5_data * inbuf; krb5_data * outbuf; krb5_replay_data * outdata; @@ -184,7 +184,7 @@ krb5_rd_safe(context, auth_context, inbuf, outbuf, outdata) if (retval = krb5_rd_safe_basic(context, inbuf, auth_context->keyblock, auth_context->local_addr, auth_context->remote_addr, - auth_context->cksumtype, &replaydata, outbuf)) + &replaydata, outbuf)) return retval; if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { diff --git a/src/lib/krb5/krb/recvauth.c b/src/lib/krb5/krb/recvauth.c index 8b1e832e6..02c9e42cf 100644 --- a/src/lib/krb5/krb/recvauth.c +++ b/src/lib/krb5/krb/recvauth.c @@ -26,6 +26,7 @@ #define NEED_SOCKETS #include "k5-int.h" +#include "auth_con.h" #include "com_err.h" #include #include @@ -36,37 +37,29 @@ extern krb5_flags krb5_kdc_default_options; static char *sendauth_version = "KRB5_SENDAUTH_V1.0"; krb5_error_code INTERFACE -krb5_recvauth(context, +krb5_recvauth(context, auth_context, /* IN */ - fd, appl_version, server, sender_addr, fetch_from, - keyproc, keyprocarg, rc_type, flags, + fd, appl_version, server, rc_type, flags, keytab, /* OUT */ - seq_number, client, ticket, authent) - krb5_context context; - krb5_pointer fd; - char *appl_version; - krb5_principal server; - krb5_address *sender_addr; - krb5_pointer fetch_from; - krb5_int32 *seq_number; - char *rc_type; - krb5_int32 flags; - krb5_rdreq_key_proc keyproc; - krb5_pointer keyprocarg; - krb5_principal *client; - krb5_ticket **ticket; - krb5_authenticator **authent; + ticket) + krb5_context context; + krb5_auth_context ** auth_context; + krb5_pointer fd; + char * appl_version; + krb5_principal server; + char * rc_type; + krb5_int32 flags; + krb5_keytab keytab; + krb5_ticket ** ticket; { - krb5_error_code retval, problem; - krb5_data inbuf; - krb5_tkt_authent *authdat; - krb5_data outbuf; - krb5_rcache rcache; - krb5_octet response; - krb5_data *server_name, null_server; - char *cachename; - extern krb5_deltat krb5_clockskew; - static char *rc_base = "rc_"; + krb5_flags ap_option; + krb5_error_code retval, problem; + krb5_data inbuf; + krb5_data outbuf; + krb5_rcache rcache; + krb5_octet response; + krb5_data null_server; + extern krb5_deltat krb5_clockskew; /* * Zero out problem variable. If problem is set at the end of @@ -133,71 +126,60 @@ krb5_recvauth(context, * Now we actually write the response. If the response is non-zero, * exit with a return value of problem */ - if ((krb5_net_write(context, *((int *) fd), (char *)&response, 1)) < 0) { + if ((krb5_net_write(context, *((int *)fd), (char *)&response, 1)) < 0) { return(problem); /* We'll return the top-level problem */ } if (problem) return(problem); - rcache = NULL; /* * Setup the replay cache. */ - if (!(rcache = (krb5_rcache) malloc(sizeof(*rcache)))) - problem = ENOMEM; - if (!problem) - problem = krb5_rc_resolve_type(context, &rcache, - rc_type ? rc_type : "dfl"); - cachename = NULL; if (server) { - server_name = krb5_princ_component(context, server, 0); + problem = krb5_get_server_rcache(context, + krb5_princ_component(context, server, 0), &rcache); } else { - null_server.data = "default"; null_server.length = 7; - server_name = &null_server; - } - - if (!problem && !(cachename = malloc(server_name->length+1+strlen(rc_base)))) - problem = ENOMEM; - if (!problem) { - strcpy(cachename, rc_base ? rc_base : "rc_"); - strncat(cachename, server_name->data, server_name->length); - cachename[server_name->length+strlen(rc_base)] = '\0'; - problem = krb5_rc_resolve(context, rcache, cachename); + null_server.data = "default"; + problem = krb5_get_server_rcache(context, &null_server, &rcache); } - if (!problem) { - if (krb5_rc_recover(context, rcache)) - /* - * If the rc_recover didn't work, then try - * initializing the replay cache. - */ - problem = krb5_rc_initialize(context, rcache, krb5_clockskew); - if (problem) { - krb5_rc_close(context, rcache); - rcache = NULL; - } + + if (!problem) { + if (krb5_rc_recover(context, rcache)) { + /* + * If the rc_recover() didn't work, then try + * initializing the replay cache. + */ + if (krb5_rc_initialize(context, rcache, krb5_clockskew)) { + krb5_rc_close(context, rcache); + rcache = NULL; + } } + } /* * Now, let's read the AP_REQ message and decode it */ if (retval = krb5_read_message(context, fd, &inbuf)) { + if (rcache) (void) krb5_rc_close(context, rcache); - if (cachename) - free(cachename); return(retval); } - authdat = 0; /* so we can tell if we need to - free it later... */ + + if (*auth_context == NULL) { + if (retval = krb5_auth_con_init(context, auth_context)) + return(retval); + } + + krb5_auth_con_setrcache(context, *auth_context, rcache); + if (!problem) - problem = krb5_rd_req(context, &inbuf, server, sender_addr, fetch_from, - keyproc, keyprocarg, rcache, &authdat); + problem = krb5_rd_req(context, auth_context, &inbuf, server, + keytab, &ap_option, ticket); krb5_xfree(inbuf.data); if (rcache) retval = krb5_rc_close(context, rcache); if (!problem && retval) problem = retval; - if (cachename) - free(cachename); /* * If there was a problem, send back a krb5_error message, @@ -231,86 +213,22 @@ krb5_recvauth(context, if (retval = krb5_write_message(context, fd, &outbuf)) { if (outbuf.data) krb5_xfree(outbuf.data); - if (!problem) - krb5_free_tkt_authent(context, authdat); return(retval); } if (problem) { /* * We sent back an error, we need to return */ - if (authdat) krb5_free_tkt_authent(context, authdat); return(problem); } - /* - * Here lies the mutual authentication stuff... - * - * We're going to compose and send a AP_REP message. - */ - if ((authdat->ap_options & AP_OPTS_MUTUAL_REQUIRED)) { - krb5_ap_rep_enc_part repl; - /* - * Generate a random sequence number - */ - if (seq_number && - (retval = krb5_generate_seq_number(context, - authdat->ticket->enc_part2->session, seq_number))) { - krb5_free_tkt_authent(context, authdat); - return(retval); - } - - repl.ctime = authdat->authenticator->ctime; - repl.cusec = authdat->authenticator->cusec; - repl.subkey = authdat->authenticator->subkey; - if (seq_number) - repl.seq_number = *seq_number; - else - repl.seq_number = 0; - - if (retval = krb5_mk_rep(context, &repl, - authdat->ticket->enc_part2->session, - &outbuf)) { - krb5_free_tkt_authent(context, authdat); - return(retval); - } - if (retval = krb5_write_message(context, fd, &outbuf)) { - krb5_xfree(outbuf.data); - krb5_free_tkt_authent(context, authdat); - return(retval); - } - krb5_xfree(outbuf.data); + /* Here lies the mutual authentication stuff... */ + if ((ap_option & AP_OPTS_MUTUAL_REQUIRED)) { + if (retval = krb5_mk_rep(context, *auth_context, &outbuf)) { + return(retval); } - /* - * At this point, we've won. We just need to copy whatever - * parts of the authdat structure which the user wants, clean - * up, and exit. - */ - if (client) - if (retval = - krb5_copy_principal(context, authdat->ticket->enc_part2->client, - client)) { - krb5_free_tkt_authent(context, authdat); - return(retval); - } - /* - * The following efficiency hack assumes knowledge about the - * structure of krb5_tkt_authent. If we later add additional - * allocated substructures to krb5_tkt_authent, they will have - * to be reflected here; otherwise, we will probably have a - * memory leak. - * - * If the user wants that part of the authdat structure, - * return it; otherwise free it. - */ - if (ticket) - *ticket = authdat->ticket; - else - krb5_free_ticket(context, authdat->ticket); - if (authent) - *authent = authdat->authenticator; - else - krb5_free_authenticator(context, authdat->authenticator); - krb5_xfree(authdat); - return 0; + retval = krb5_write_message(context, fd, &outbuf); + krb5_xfree(outbuf.data); + } + return retval; } -- 2.26.2