From b512f16eda5d2b4920490d2409d6a900030b32d0 Mon Sep 17 00:00:00 2001 From: Chris Provenzano Date: Wed, 26 Apr 1995 03:03:26 +0000 Subject: [PATCH] * Makefile.in : Added gc_via_tkt.c and removed get_fcreds.c * auth_con.c (krb5_auth_con_setaddrs()) : Fixed so it allocates space and copies addresses, not just pointer. * mk_cred.c: Completely rewritten from sources donated by asriniva. * rd_cred.c: Completely rewritten from sources donated by asriniva. * mk_priv.c (krb5_mk_priv()), mk_safe.c (krb5_mk_safe()), rd_priv.c (krb5_rd_priv()), and rd_safe (krb5_rd_safe()) : Try using a subkey before using the session key for encryption. * recvauth.c (krb5_recvauth()): Don't close the rcache on success. git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@5489 dc483132-0cff-0310-8789-dd5450dbe970 --- src/lib/krb5/krb/ChangeLog | 12 + src/lib/krb5/krb/Makefile.in | 4 +- src/lib/krb5/krb/auth_con.c | 39 ++- src/lib/krb5/krb/gc_via_tkt.c | 234 ++++++++++++++++++ src/lib/krb5/krb/mk_cred.c | 452 +++++++++++++++++++++++----------- src/lib/krb5/krb/mk_priv.c | 30 ++- src/lib/krb5/krb/mk_safe.c | 28 ++- src/lib/krb5/krb/rd_cred.c | 437 ++++++++++++++++++-------------- src/lib/krb5/krb/rd_priv.c | 25 +- src/lib/krb5/krb/rd_safe.c | 22 +- src/lib/krb5/krb/recvauth.c | 147 ++++++----- 11 files changed, 994 insertions(+), 436 deletions(-) create mode 100644 src/lib/krb5/krb/gc_via_tkt.c diff --git a/src/lib/krb5/krb/ChangeLog b/src/lib/krb5/krb/ChangeLog index 9f18889b4..b963cb4e4 100644 --- a/src/lib/krb5/krb/ChangeLog +++ b/src/lib/krb5/krb/ChangeLog @@ -1,3 +1,15 @@ +Tue Apr 25 21:58:23 1995 Chris Provenzano (proven@mit.edu) + + * Makefile.in : Added gc_via_tkt.c and removed get_fcreds.c + * auth_con.c (krb5_auth_con_setaddrs()) : Fixed so it allocates + space and copies addresses, not just pointer. + * mk_cred.c: Completely rewritten from sources donated by asriniva. + * rd_cred.c: Completely rewritten from sources donated by asriniva. + * mk_priv.c (krb5_mk_priv()), mk_safe.c (krb5_mk_safe()), + rd_priv.c (krb5_rd_priv()), and rd_safe (krb5_rd_safe()) : + Try using a subkey before using the session key for encryption. + * recvauth.c (krb5_recvauth()): Don't close the rcache on success. + Mon Apr 24 23:12:21 1995 Theodore Y. Ts'o * Makefile.in, configure.in (t_walk_rtree): Add WITH_NETLIBS and diff --git a/src/lib/krb5/krb/Makefile.in b/src/lib/krb5/krb/Makefile.in index c2053bd01..d0f176e96 100644 --- a/src/lib/krb5/krb/Makefile.in +++ b/src/lib/krb5/krb/Makefile.in @@ -31,11 +31,11 @@ OBJS= addr_comp.$(OBJEXT) \ faddr_ordr.$(OBJEXT) \ gc_frm_kdc.$(OBJEXT) \ gc_via_tgt.$(OBJEXT) \ + gc_via_tkt.$(OBJEXT) \ gc_2tgt.$(OBJEXT) \ gen_seqnum.$(OBJEXT) \ gen_subkey.$(OBJEXT) \ get_creds.$(OBJEXT) \ - get_fcreds.$(OBJEXT) \ get_in_tkt.$(OBJEXT) \ in_tkt_ktb.$(OBJEXT) \ in_tkt_pwd.$(OBJEXT) \ @@ -96,11 +96,11 @@ SRCS= $(srcdir)/addr_comp.c \ $(srcdir)/faddr_ordr.c \ $(srcdir)/gc_frm_kdc.c \ $(srcdir)/gc_via_tgt.c \ + $(srcdir)/gc_via_tkt.c \ $(srcdir)/gc_2tgt.c \ $(srcdir)/gen_seqnum.c \ $(srcdir)/gen_subkey.c \ $(srcdir)/get_creds.c \ - $(srcdir)/get_fcreds.c \ $(srcdir)/get_in_tkt.c \ $(srcdir)/in_tkt_ktb.c \ $(srcdir)/in_tkt_pwd.c \ diff --git a/src/lib/krb5/krb/auth_con.c b/src/lib/krb5/krb/auth_con.c index 134e07ba5..6821a05d8 100644 --- a/src/lib/krb5/krb/auth_con.c +++ b/src/lib/krb5/krb/auth_con.c @@ -45,8 +45,43 @@ krb5_auth_con_setaddrs(context, auth_context, local_addr, remote_addr) krb5_address * local_addr; krb5_address * remote_addr; { - auth_context->remote_addr = remote_addr; - auth_context->local_addr = local_addr; + /* Free old addresses */ + if (auth_context->local_addr) + free(auth_context->local_addr); + if (auth_context->remote_addr) + free(auth_context->remote_addr); + + if (local_addr) { + if ((auth_context->local_addr = (krb5_address *) + malloc(sizeof(krb5_address) + local_addr->length)) == NULL) { + return ENOMEM; + } + auth_context->local_addr->addrtype = local_addr->addrtype; + auth_context->local_addr->length = local_addr->length; + auth_context->local_addr->contents = (krb5_octet *) + auth_context->local_addr + sizeof(krb5_address); + memcpy(auth_context->local_addr->contents, + local_addr->contents, local_addr->length); + } else { + auth_context->local_addr = NULL; + } + + if (remote_addr) { + if ((auth_context->remote_addr = (krb5_address *) + malloc(sizeof(krb5_address) + remote_addr->length)) == NULL) { + if (auth_context->local_addr) + free(auth_context->local_addr); + return ENOMEM; + } + auth_context->remote_addr->addrtype = remote_addr->addrtype; + auth_context->remote_addr->length = remote_addr->length; + auth_context->remote_addr->contents = (krb5_octet *) + auth_context->remote_addr + sizeof(krb5_address); + memcpy(auth_context->remote_addr->contents, + remote_addr->contents, remote_addr->length); + } else { + auth_context->remote_addr = NULL; + } return 0; } diff --git a/src/lib/krb5/krb/gc_via_tkt.c b/src/lib/krb5/krb/gc_via_tkt.c new file mode 100644 index 000000000..c548b3d37 --- /dev/null +++ b/src/lib/krb5/krb/gc_via_tkt.c @@ -0,0 +1,234 @@ +/* + * lib/krb5/krb/gc_via_tgt.c + * + * Copyright 1990,1991 by the Massachusetts Institute of Technology. + * All Rights Reserved. + * + * Export of this software from the United States of America may + * require a specific license from the United States Government. + * It is the responsibility of any person or organization contemplating + * export to obtain such a license before exporting. + * + * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and + * distribute this software and its documentation for any purpose and + * without fee is hereby granted, provided that the above copyright + * notice appear in all copies and that both that copyright notice and + * this permission notice appear in supporting documentation, and that + * the name of M.I.T. not be used in advertising or publicity pertaining + * to distribution of the software without specific, written prior + * permission. M.I.T. makes no representations about the suitability of + * this software for any purpose. It is provided "as is" without express + * or implied warranty. + * + * + * Given a tkt, and a target cred, get it. + * Assumes that the kdc_rep has been decrypted. + */ + +#include "k5-int.h" +#include "int-proto.h" + +static krb5_error_code +krb5_kdcrep2creds(context, pkdcrep, address, ppcreds) + krb5_context context; + krb5_kdc_rep * pkdcrep; + krb5_address *const * address; + krb5_creds ** ppcreds; +{ + krb5_error_code retval; + krb5_data *pdata; + + if ((*ppcreds = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) { + return ENOMEM; + } + + memset(*ppcreds, 0, sizeof(krb5_creds)); + + if (retval = krb5_copy_principal(context, pkdcrep->client, + &(*ppcreds)->client)) + goto cleanup; + + if (retval = krb5_copy_principal(context, pkdcrep->enc_part2->server, + &(*ppcreds)->server)) + goto cleanup; + + if (retval = krb5_copy_keyblock_contents(context, + pkdcrep->enc_part2->session, + &(*ppcreds)->keyblock)) + goto cleanup; + + (*ppcreds)->keyblock.etype = pkdcrep->ticket->enc_part.etype; + + (*ppcreds)->magic = KV5M_CREDS; + (*ppcreds)->is_skey = 0; /* unused */ + (*ppcreds)->times = pkdcrep->enc_part2->times; + (*ppcreds)->ticket_flags = pkdcrep->enc_part2->flags; + + (*ppcreds)->authdata = NULL; /* not used */ + memset(&(*ppcreds)->second_ticket, 0, sizeof((*ppcreds)->second_ticket)); + + if (pkdcrep->enc_part2->caddrs) { + if (retval = krb5_copy_addresses(context, pkdcrep->enc_part2->caddrs, + &(*ppcreds)->addresses)) + goto cleanup_keyblock; + } else { + /* no addresses in the list means we got what we had */ + if (retval = krb5_copy_addresses(context, address, + &(*ppcreds)->addresses)) + goto cleanup_keyblock; + } + + if (retval = encode_krb5_ticket(pkdcrep->ticket, &pdata)) + goto cleanup_keyblock; + + (*ppcreds)->ticket = *pdata; + return 0; + +cleanup_keyblock: + memset((*ppcreds)->keyblock.contents, 0, (*ppcreds)->keyblock.length); + +cleanup: + free (*ppcreds); + return retval; +} + +/* XXX This is to move to krb5_send_tgs, RSN -- CAP 950411 */ +extern krb5_cksumtype krb5_kdc_req_sumtype; + +krb5_error_code INTERFACE +krb5_get_cred_via_tkt (context, tkt, kdcoptions, address, in_cred, out_cred) + krb5_context context; + krb5_creds * tkt; + const krb5_flags kdcoptions; + krb5_address *const * address; + krb5_creds * in_cred; + krb5_creds ** out_cred; +{ + krb5_error_code retval; + krb5_principal tempprinc; + krb5_kdc_rep *dec_rep; + krb5_error *err_reply; + krb5_response tgsrep; + + /* tkt->client must be equal to in_cred->client */ + if (!krb5_principal_compare(context, tkt->client, in_cred->client)) + return KRB5_PRINC_NOMATCH; + + if (!tkt->ticket.length) + return KRB5_NO_TKT_SUPPLIED; + + /* check if we have the right TGT */ + /* tkt->server must be equal to */ + /* krbtgt/realmof(cred->server)@realmof(tgt->server) */ + +/* + if (retval = krb5_tgtname(context, + krb5_princ_realm(context, in_cred->server), + krb5_princ_realm(context, tkt->server), &tempprinc)) + return(retval); + + if (!krb5_principal_compare(context, tempprinc, tkt->server)) { + retval = KRB5_PRINC_NOMATCH; + goto error_5; + } +*/ + + if (retval = krb5_send_tgs(context, kdcoptions, &in_cred->times, NULL, + krb5_kdc_req_sumtype, /* To be removed */ + in_cred->server, address, in_cred->authdata, + 0, /* no padata */ + 0, /* no second ticket */ + tkt, &tgsrep)) + goto error_5; + + switch (tgsrep.message_type) { + case KRB5_TGS_REP: + break; + case KRB5_ERROR: + default: + if (krb5_is_krb_error(&tgsrep.response)) + retval = decode_krb5_error(&tgsrep.response, &err_reply); + else + retval = KRB5KRB_AP_ERR_MSG_TYPE; + + if (retval) /* neither proper reply nor error! */ + goto error_4; + +#if 0 + /* XXX need access to the actual assembled request... + need a change to send_tgs */ + if ((err_reply->ctime != request.ctime) || + !krb5_principal_compare(context, err_reply->server, request.server) || + !krb5_principal_compare(context, err_reply->client, request.client)) + retval = KRB5_KDCREP_MODIFIED; + else +#endif + retval = err_reply->error + ERROR_TABLE_BASE_krb5; + + krb5_free_error(context, err_reply); + goto error_4; + } + + if (retval = krb5_decode_kdc_rep(context, &tgsrep.response, &tkt->keyblock, + tkt->keyblock.etype, &dec_rep)) + goto error_4; + + if (dec_rep->msg_type != KRB5_TGS_REP) { + retval = KRB5KRB_AP_ERR_MSG_TYPE; + goto error_3; + } + + /* now it's decrypted and ready for prime time */ + if (!krb5_principal_compare(context, dec_rep->client, tkt->client)) { + retval = KRB5_KDCREP_MODIFIED; + goto error_3; + } + + retval = krb5_kdcrep2creds(context, dec_rep, address, out_cred); + + +#if 0 + /* XXX probably need access to the request */ + /* check the contents for sanity: */ + if (!krb5_principal_compare(context, dec_rep->client, request.client) + || !krb5_principal_compare(context, dec_rep->enc_part2->server, request.server) + || !krb5_principal_compare(context, dec_rep->ticket->server, request.server) + || (request.nonce != dec_rep->enc_part2->nonce) + /* XXX check for extraneous flags */ + /* XXX || (!krb5_addresses_compare(context, addrs, dec_rep->enc_part2->caddrs)) */ + || ((request.from != 0) && + (request.from != dec_rep->enc_part2->times.starttime)) + || ((request.till != 0) && + (dec_rep->enc_part2->times.endtime > request.till)) + || ((request.kdc_options & KDC_OPT_RENEWABLE) && + (request.rtime != 0) && + (dec_rep->enc_part2->times.renew_till > request.rtime)) + || ((request.kdc_options & KDC_OPT_RENEWABLE_OK) && + (dec_rep->enc_part2->flags & KDC_OPT_RENEWABLE) && + (request.till != 0) && + (dec_rep->enc_part2->times.renew_till > request.till)) + ) + retval = KRB5_KDCREP_MODIFIED; + + if (!request.from && !in_clock_skew(dec_rep->enc_part2->times.starttime)) { + retval = KRB5_KDCREP_SKEW; + goto error_1; + } + +#endif + +error_1:; + if (retval) + +error_3:; + memset(dec_rep->enc_part2->session->contents, 0, + dec_rep->enc_part2->session->length); + krb5_free_kdc_rep(context, dec_rep); + +error_4:; + free(tgsrep.response.data); + +error_5:; + krb5_free_principal(context, tempprinc); + return retval; +} diff --git a/src/lib/krb5/krb/mk_cred.c b/src/lib/krb5/krb/mk_cred.c index 12df2c88a..6b95301a3 100644 --- a/src/lib/krb5/krb/mk_cred.c +++ b/src/lib/krb5/krb/mk_cred.c @@ -1,174 +1,350 @@ -/* - * lib/krb5/krb/mk_cred.c +/* + * NAME + * cred.c + * + * DESCRIPTION + * Provide an interface to assemble and disassemble krb5_cred + * structures. * - * Copyright 1994 by the Massachusetts Institute of Technology. - * All Rights Reserved. + * MODIFIED + * $Log$ + * Revision 5.8 1995/04/26 03:03:11 proven + * * Makefile.in : Added gc_via_tkt.c and removed get_fcreds.c + * * auth_con.c (krb5_auth_con_setaddrs()) : Fixed so it allocates + * space and copies addresses, not just pointer. + * * mk_cred.c: Completely rewritten from sources donated by asriniva. + * * rd_cred.c: Completely rewritten from sources donated by asriniva. + * * mk_priv.c (krb5_mk_priv()), mk_safe.c (krb5_mk_safe()), + * rd_priv.c (krb5_rd_priv()), and rd_safe (krb5_rd_safe()) : + * Try using a subkey before using the session key for encryption. + * * recvauth.c (krb5_recvauth()): Don't close the rcache on success. + * + * Revision 1.3 1995/01/26 00:09:24 asriniva + * Completely rewrote API to credential passing code. + * + * Revision 1.2 1994/12/30 21:57:17 asriniva + * Killed compile time warnings/errors. + * Fixed runtime bugs. + * Require a ticket when calling krb5_initcred. + * Cleaned up krb5_addticket. + * + * Revision 1.1 1994/12/29 17:03:30 asriniva + * Initial revision * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - * - * krb5_mk_cred() */ +#include +#include "auth_con.h" +#include /* NULL */ +#include /* malloc */ +#include /* ENOMEM */ -/* XXX This API is going to change; what's here isn't general enough! */ -/* XXX Once we finalize the API, it should go into func-proto.h and */ -/* into the API doc. */ - -#include "k5-int.h" +/*-------------------- encrypt_credencpart --------------------*/ -/* Create asn.1 encoded KRB-CRED message from the kdc reply. */ -krb5_error_code -krb5_mk_cred(context, dec_rep, etype, key, sender_addr, recv_addr, outbuf) - krb5_context context; - krb5_kdc_rep *dec_rep; - krb5_enctype etype; - krb5_keyblock *key; - krb5_address *sender_addr; - krb5_address *recv_addr; - krb5_data *outbuf; +/* + * encrypt the enc_part of krb5_cred + */ +static krb5_error_code +encrypt_credencpart(context, pcredpart, pkeyblock, pencdata) + krb5_context context; + krb5_cred_enc_part * pcredpart; + krb5_keyblock * pkeyblock; + krb5_enc_data * pencdata; { - krb5_error_code retval; - krb5_encrypt_block eblock; - krb5_cred ret_cred; - krb5_cred_enc_part cred_enc_part; - krb5_data *scratch; - - if (!valid_etype(etype)) - return KRB5_PROG_ETYPE_NOSUPP; - - ret_cred.tickets = (krb5_ticket **) calloc(2, sizeof(*ret_cred.tickets)); - if (!ret_cred.tickets) - return ENOMEM; - ret_cred.tickets[0] = dec_rep->ticket; - ret_cred.tickets[1] = 0; - - ret_cred.enc_part.etype = etype; - ret_cred.enc_part.kvno = 0; - - cred_enc_part.ticket_info = (krb5_cred_info **) - calloc(2, sizeof(*cred_enc_part.ticket_info)); - if (!cred_enc_part.ticket_info) { - krb5_free_tickets(context, ret_cred.tickets); - return ENOMEM; + krb5_error_code retval; + krb5_encrypt_block eblock; + krb5_data * scratch; + + if (!valid_etype(pkeyblock->etype)) + return KRB5_PROG_ETYPE_NOSUPP; + + /* start by encoding to-be-encrypted part of the message */ + if (retval = encode_krb5_enc_cred_part(pcredpart, &scratch)) + return retval; + + /* put together an eblock for this encryption */ + + pencdata->kvno = 0; + pencdata->etype = pkeyblock->etype; + + krb5_use_cstype(context, &eblock, pkeyblock->etype); + pencdata->ciphertext.length = krb5_encrypt_size(scratch->length, + eblock.crypto_entry); + + /* add padding area, and zero it */ + if (!(scratch->data = (char *)realloc(scratch->data, + pencdata->ciphertext.length))) { + /* may destroy scratch->data */ + krb5_xfree(scratch); + return ENOMEM; } - cred_enc_part.ticket_info[0] = (krb5_cred_info *) - malloc(sizeof(*cred_enc_part.ticket_info[0])); - if (!cred_enc_part.ticket_info[0]) { - krb5_free_tickets(context, ret_cred.tickets); - krb5_free_cred_enc_part(context, &cred_enc_part); - return ENOMEM; + + memset(scratch->data + scratch->length, 0, + pencdata->ciphertext.length - scratch->length); + if (!(pencdata->ciphertext.data = + (char *)malloc(pencdata->ciphertext.length))) { + retval = ENOMEM; + goto clean_scratch; } - cred_enc_part.nonce = 0; - if (retval = krb5_us_timeofday(context, &cred_enc_part.timestamp, - &cred_enc_part.usec)) - return retval; + /* do any necessary key pre-processing */ + if (retval = krb5_process_key(context, &eblock, pkeyblock)) { + goto clean_encpart; + } - cred_enc_part.s_address = (krb5_address *)sender_addr; - cred_enc_part.r_address = (krb5_address *)recv_addr; + /* call the encryption routine */ + if (retval = krb5_encrypt(context, (krb5_pointer)scratch->data, + (krb5_pointer)pencdata->ciphertext.data, + scratch->length, &eblock, 0)) { + krb5_finish_key(context, &eblock); + goto clean_encpart; + } + + retval = krb5_finish_key(context, &eblock); - cred_enc_part.ticket_info[0]->session = dec_rep->enc_part2->session; - cred_enc_part.ticket_info[0]->client = dec_rep->client; - cred_enc_part.ticket_info[0]->server = dec_rep->enc_part2->server; - cred_enc_part.ticket_info[0]->flags = dec_rep->enc_part2->flags; - cred_enc_part.ticket_info[0]->times = dec_rep->enc_part2->times; - cred_enc_part.ticket_info[0]->caddrs = dec_rep->enc_part2->caddrs; +clean_encpart: + if (retval) { + memset(pencdata->ciphertext.data, 0, pencdata->ciphertext.length); + free(pencdata->ciphertext.data); + pencdata->ciphertext.length = 0; + pencdata->ciphertext.data = 0; + } - cred_enc_part.ticket_info[1] = 0; +clean_scratch: + memset(scratch->data, 0, scratch->length); + krb5_free_data(context, scratch); - /* start by encoding to-be-encrypted part of the message */ + return retval; +} - if (retval = encode_krb5_enc_cred_part(&cred_enc_part, &scratch)) - return retval; +/*----------------------- krb5_mk_ncred_basic -----------------------*/ -#define cleanup_scratch() { (void) memset(scratch->data, 0, scratch->length); krb5_free_data(context, scratch); } +static krb5_error_code +krb5_mk_ncred_basic(context, ppcreds, nppcreds, keyblock, + replaydata, local_addr, remote_addr, pcred) + krb5_context context; + krb5_creds ** ppcreds; + krb5_int32 nppcreds; + krb5_keyblock * keyblock; + krb5_replay_data * replaydata; + krb5_address * local_addr; + krb5_address * remote_addr; + krb5_cred * pcred; +{ + krb5_cred_enc_part credenc; + krb5_error_code retval; + char * tmp; + int i; - /* put together an eblock for this encryption */ + credenc.magic = KV5M_CRED_ENC_PART; - krb5_use_cstype(context, &eblock, etype); - ret_cred.enc_part.ciphertext.length = krb5_encrypt_size(scratch->length, - eblock.crypto_entry); - /* add padding area, and zero it */ - if (!(scratch->data = realloc(scratch->data, - ret_cred.enc_part.ciphertext.length))) { - /* may destroy scratch->data */ - krb5_xfree(scratch); - return ENOMEM; + credenc.s_address = local_addr; + credenc.r_address = remote_addr; + credenc.nonce = replaydata->seq; + credenc.usec = replaydata->usec; + credenc.timestamp = replaydata->timestamp; + + /* Get memory for creds and initialize it */ + if ((credenc.ticket_info = (krb5_cred_info **) + malloc(sizeof(krb5_cred_info *) * (nppcreds + 1))) == NULL) { + return ENOMEM; } - memset(scratch->data + scratch->length, 0, - ret_cred.enc_part.ciphertext.length - scratch->length); - if (!(ret_cred.enc_part.ciphertext.data = - malloc(ret_cred.enc_part.ciphertext.length))) { - retval = ENOMEM; - goto clean_scratch; + if ((tmp = (char *)malloc(sizeof(krb5_cred_info) * nppcreds)) == NULL) { + retval = ENOMEM; + goto cleanup_info; } + memset(tmp, 0, sizeof(krb5_cred_info) * nppcreds); -#define cleanup_encpart() {\ - (void) memset(ret_cred.enc_part.ciphertext.data, 0, \ - ret_cred.enc_part.ciphertext.length); \ - free(ret_cred.enc_part.ciphertext.data); \ - ret_cred.enc_part.ciphertext.length = 0; \ - ret_cred.enc_part.ciphertext.data = 0;} + /* + * For each credential in the list, initialize a cred info + * structure and copy the ticket into the ticket list. + */ + for (i = 0; i < nppcreds; i++) { + credenc.ticket_info[i] = (krb5_cred_info *)tmp + i; - /* do any necessary key pre-processing */ - if (retval = krb5_process_key(context, &eblock, key)) { - goto clean_encpart; + credenc.ticket_info[i]->magic = KV5M_CRED_INFO; + credenc.ticket_info[i]->times = ppcreds[i]->times; + credenc.ticket_info[i]->flags = ppcreds[i]->ticket_flags; + + if (retval = decode_krb5_ticket(&ppcreds[i]->ticket, + &pcred->tickets[i])) + goto cleanup_info_ptrs; + + if (retval = krb5_copy_keyblock(context, &ppcreds[i]->keyblock, + &credenc.ticket_info[i]->session)) + goto cleanup_info_ptrs; + + if (retval = krb5_copy_principal(context, ppcreds[i]->client, + &credenc.ticket_info[i]->client)) + goto cleanup_info_ptrs; + + if (retval = krb5_copy_principal(context, ppcreds[i]->server, + &credenc.ticket_info[i]->server)) + goto cleanup_info_ptrs; + + if (retval = krb5_copy_addresses(context, ppcreds[i]->addresses, + &credenc.ticket_info[i]->caddrs)) + goto cleanup_info_ptrs; } -#define cleanup_prockey() {(void) krb5_finish_key(context, &eblock);} + /* + * NULL terminate the lists. + */ + credenc.ticket_info[i] = NULL; + pcred->tickets[i] = NULL; - /* call the encryption routine */ - if (retval = krb5_encrypt(context, (krb5_pointer) scratch->data, - (krb5_pointer) - ret_cred.enc_part.ciphertext.data, - scratch->length, &eblock, - 0)) { - goto clean_prockey; + retval = encrypt_credencpart(context, &credenc, keyblock, &pcred->enc_part); + +cleanup_info_ptrs: + free(tmp); + +cleanup_info: + free(credenc.ticket_info); + return retval; +} + +/*----------------------- krb5_mk_ncred -----------------------*/ + +/* + * This functions takes as input an array of krb5_credentials, and + * outputs an encoded KRB_CRED message suitable for krb5_rd_cred + */ +krb5_error_code INTERFACE +krb5_mk_ncred(context, auth_context, ppcreds, ppdata, outdata) + + krb5_context context; + krb5_auth_context * auth_context; + krb5_creds ** ppcreds; + krb5_data ** ppdata; + krb5_replay_data * outdata; +{ + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_replay_data replaydata; + krb5_cred * pcred; + int ncred; + + if (ppcreds == NULL) { + return KRB5KRB_AP_ERR_BADADDR; } - - /* private message is now assembled-- do some cleanup */ - cleanup_scratch(); - if (retval = krb5_finish_key(context, &eblock)) { - cleanup_encpart(); - return retval; + /* + * Allocate memory for a NULL terminated list of tickets. + */ + for (ncred = 0; ppcreds[ncred]; ncred++); + + if ((pcred = (krb5_cred *)malloc(sizeof(krb5_cred))) == NULL) + return ENOMEM; + + if ((pcred->tickets + = (krb5_ticket **)malloc(sizeof(krb5_ticket *) * (ncred + 1))) == NULL) { + retval = ENOMEM; + free(pcred); } - /* encode private message */ - if (retval = encode_krb5_cred(&ret_cred, &scratch)) { - cleanup_encpart(); - return retval; + + /* Get keyblock */ + if ((keyblock = auth_context->local_subkey) == NULL) + if ((keyblock = auth_context->remote_subkey) == NULL) + keyblock = auth_context->keyblock; + + /* Get replay info */ + if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && + (auth_context->rcache == NULL)) + return KRB5_RC_REQUIRED; + + if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && + (outdata == NULL)) + /* Need a better error */ + return KRB5_RC_REQUIRED; + + if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) || + (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME)) { + if (retval = krb5_us_timeofday(context, &replaydata.timestamp, + &replaydata.usec)) + return retval; + if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { + outdata->timestamp = replaydata.timestamp; + outdata->usec = replaydata.usec; + } + if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) { + outdata->timestamp = replaydata.timestamp; + outdata->usec = replaydata.usec; + } + } + if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) || + (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { + replaydata.seq = auth_context->local_seq_number; + if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { + auth_context->local_seq_number++; + } else { + outdata->seq = replaydata.seq; + } + } + + /* Setup creds structure */ + if (retval = krb5_mk_ncred_basic(context, ppcreds, ncred, keyblock, + &replaydata, auth_context->local_addr, + auth_context->remote_addr, pcred)) + goto cleanup_tickets; + + if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { + krb5_donot_replay replay; + + if (retval = krb5_gen_replay_name(context, auth_context->local_addr, + "_forw", &replay.client)) + goto cleanup_tickets; + + replay.server = ""; /* XXX */ + replay.cusec = replaydata.usec; + replay.ctime = replaydata.timestamp; + if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) { + /* should we really error out here? XXX */ + krb5_xfree(replay.client); + goto cleanup_tickets; + } + krb5_xfree(replay.client); + } + + /* Encode creds structure */ + retval = encode_krb5_cred(pcred, ppdata); + +cleanup_tickets: + if (retval) { + 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--; + free(pcred->tickets); + free(pcred); } + return retval; +} - cleanup_encpart(); +/*----------------------- krb5_mk_1cred -----------------------*/ + +/* + * A convenience function that calls krb5_mk_ncred. + */ +krb5_error_code INTERFACE +krb5_mk_1cred(context, auth_context, pcreds, ppdata, outdata) + krb5_context context; + krb5_auth_context * auth_context; + krb5_creds * pcreds; + krb5_data ** ppdata; + krb5_replay_data * outdata; +{ + krb5_error_code retval; + krb5_creds **ppcreds; - *outbuf = *scratch; - krb5_xfree(scratch); - return 0; + if ((ppcreds = (krb5_creds **)malloc(sizeof(*ppcreds) * 2)) == NULL) { + return ENOMEM; + } - clean_prockey: - cleanup_prockey(); - clean_encpart: - cleanup_encpart(); - clean_scratch: - cleanup_scratch(); + ppcreds[0] = pcreds; + ppcreds[1] = NULL; + if (retval = krb5_mk_ncred(context, auth_context, ppcreds, ppdata, outdata)) + free(ppcreds); return retval; -#undef cleanup_prockey -#undef cleanup_encpart -#undef cleanup_scratch } diff --git a/src/lib/krb5/krb/mk_priv.c b/src/lib/krb5/krb/mk_priv.c index 6a804915b..40c9bfa57 100644 --- a/src/lib/krb5/krb/mk_priv.c +++ b/src/lib/krb5/krb/mk_priv.c @@ -135,15 +135,22 @@ clean_scratch: krb5_error_code krb5_mk_priv(context, auth_context, userdata, outbuf, outdata) - krb5_context context; - krb5_auth_context * auth_context; - const krb5_data * userdata; - krb5_data * outbuf; - krb5_replay_data * outdata; + krb5_context context; + krb5_auth_context * auth_context; + const krb5_data * userdata; + krb5_data * outbuf; + krb5_replay_data * outdata; { - krb5_replay_data replaydata; - krb5_error_code retval; + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_replay_data replaydata; + /* Get keyblock */ + if ((keyblock = auth_context->local_subkey) == NULL) + if ((keyblock = auth_context->remote_subkey) == NULL) + keyblock = auth_context->keyblock; + + /* Get replay info */ if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && (auth_context->rcache == NULL)) return KRB5_RC_REQUIRED; @@ -174,9 +181,10 @@ krb5_mk_priv(context, auth_context, userdata, outbuf, outdata) } } - if (retval = krb5_mk_priv_basic(context, userdata, auth_context->keyblock, - &replaydata, auth_context->local_addr, auth_context->remote_addr, - auth_context->i_vector, outbuf)) + if (retval = krb5_mk_priv_basic(context, userdata, keyblock, &replaydata, + auth_context->local_addr, + auth_context->remote_addr, + auth_context->i_vector, outbuf)) goto error; if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { @@ -193,7 +201,7 @@ krb5_mk_priv(context, auth_context, userdata, outbuf, outdata) replay.ctime = replaydata.timestamp; if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) { /* should we really error out here? XXX */ - krb5_xfree(outbuf); + krb5_xfree(replay.client); goto error; } krb5_xfree(replay.client); diff --git a/src/lib/krb5/krb/mk_safe.c b/src/lib/krb5/krb/mk_safe.c index 36670edff..47238c490 100644 --- a/src/lib/krb5/krb/mk_safe.c +++ b/src/lib/krb5/krb/mk_safe.c @@ -119,15 +119,22 @@ cleanup_scratch: krb5_error_code krb5_mk_safe(context, auth_context, userdata, outbuf, outdata) - krb5_context context; - krb5_auth_context * auth_context; - const krb5_data * userdata; - krb5_data * outbuf; - krb5_replay_data * outdata; + krb5_context context; + krb5_auth_context * auth_context; + const krb5_data * userdata; + krb5_data * outbuf; + krb5_replay_data * outdata; { - krb5_replay_data replaydata; - krb5_error_code retval; + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_replay_data replaydata; + + /* Get keyblock */ + if ((keyblock = auth_context->local_subkey) == NULL) + if ((keyblock = auth_context->remote_subkey) == NULL) + keyblock = auth_context->keyblock; + /* Get replay info */ if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && (auth_context->rcache == NULL)) return KRB5_RC_REQUIRED; @@ -156,9 +163,10 @@ krb5_mk_safe(context, auth_context, userdata, outbuf, outdata) } } - if (retval = krb5_mk_safe_basic(context, userdata, auth_context->keyblock, - &replaydata, auth_context->local_addr, auth_context->remote_addr, - auth_context->cksumtype, outbuf)) + if (retval = krb5_mk_safe_basic(context, userdata, keyblock, &replaydata, + auth_context->local_addr, + auth_context->remote_addr, + auth_context->cksumtype, outbuf)) goto error; if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { diff --git a/src/lib/krb5/krb/rd_cred.c b/src/lib/krb5/krb/rd_cred.c index dfe774b51..179a922b7 100644 --- a/src/lib/krb5/krb/rd_cred.c +++ b/src/lib/krb5/krb/rd_cred.c @@ -1,225 +1,286 @@ -/* - * lib/krb5/krb/rd_cred.c - * - * Copyright 1994 by the Massachusetts Institute of Technology. - * All Rights Reserved. - * - * Export of this software from the United States of America may - * require a specific license from the United States Government. - * It is the responsibility of any person or organization contemplating - * export to obtain such a license before exporting. - * - * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and - * distribute this software and its documentation for any purpose and - * without fee is hereby granted, provided that the above copyright - * notice appear in all copies and that both that copyright notice and - * this permission notice appear in supporting documentation, and that - * the name of M.I.T. not be used in advertising or publicity pertaining - * to distribution of the software without specific, written prior - * permission. M.I.T. makes no representations about the suitability of - * this software for any purpose. It is provided "as is" without express - * or implied warranty. - * - * krb5_rd_cred() - */ +#include +#include "auth_con.h" -/* XXX This API is going to change; what's here isn't general enough! */ -/* XXX Once we finalize the API, it should go into func-proto.h and */ -/* into the API doc. */ +#include /* NULL */ +#include /* malloc */ +#include /* ENOMEM */ -#include "k5-int.h" - -extern krb5_deltat krb5_clockskew; -#define in_clock_skew(date) (labs((date)-currenttime) < krb5_clockskew) +/*-------------------- decrypt_credencdata --------------------*/ -/* Decode the KRB-CRED message, and return creds */ -krb5_error_code -krb5_rd_cred(context, inbuf, key, creds, sender_addr, recv_addr) - krb5_context context; - const krb5_data *inbuf; - const krb5_keyblock *key; - krb5_creds *creds; /* Filled in */ - const krb5_address *sender_addr; /* optional */ - const krb5_address *recv_addr; /* optional */ +/* + * decrypt the enc_part of a krb5_cred + */ +static krb5_error_code +decrypt_credencdata(context, pcred, pkeyblock, pcredenc) + krb5_context context; + krb5_cred * pcred; + krb5_keyblock * pkeyblock; + krb5_cred_enc_part * pcredenc; { - krb5_error_code retval; - krb5_encrypt_block eblock; - krb5_cred *credmsg; - krb5_cred_enc_part *credmsg_enc_part; - krb5_data *scratch; - krb5_timestamp currenttime; - - if (!krb5_is_krb_cred(inbuf)) - return KRB5KRB_AP_ERR_MSG_TYPE; - - /* decode private message */ - if (retval = decode_krb5_cred(inbuf, &credmsg)) { - return retval; - } - -#define cleanup_credmsg() { \ - krb5_xfree(credmsg->enc_part.ciphertext.data); \ - krb5_xfree(credmsg); \ - } - - if (!(scratch = (krb5_data *) malloc(sizeof(*scratch)))) { - cleanup_credmsg(); - return ENOMEM; - } - -#define cleanup_scratch() { \ - (void)memset(scratch->data, 0, scratch->length); \ - krb5_xfree(scratch->data); \ - } - - if (retval = encode_krb5_ticket(credmsg->tickets[0], &scratch)) { - cleanup_credmsg(); - cleanup_scratch(); - return(retval); - } + krb5_cred_enc_part * ppart; + krb5_encrypt_block eblock; + krb5_error_code retval; + krb5_data scratch; - creds->ticket = *scratch; - if (!(creds->ticket.data = malloc(scratch->length))) { - krb5_xfree(creds->ticket.data); - return ENOMEM; - } - memcpy((char *)creds->ticket.data, (char *) scratch->data, scratch->length); - - cleanup_scratch(); - - if (!valid_etype(credmsg->enc_part.etype)) { - cleanup_credmsg(); - return KRB5_PROG_ETYPE_NOSUPP; - } + if (!valid_etype(pcred->enc_part.etype)) + return KRB5_PROG_ETYPE_NOSUPP; /* put together an eblock for this decryption */ - - krb5_use_cstype(context, &eblock, credmsg->enc_part.etype); - scratch->length = credmsg->enc_part.ciphertext.length; + krb5_use_cstype(context, &eblock, pcred->enc_part.etype); + scratch.length = pcred->enc_part.ciphertext.length; - if (!(scratch->data = malloc(scratch->length))) { - cleanup_credmsg(); + if (!(scratch.data = (char *)malloc(scratch.length))) return ENOMEM; - } /* do any necessary key pre-processing */ - if (retval = krb5_process_key(context, &eblock, key)) { - cleanup_credmsg(); - cleanup_scratch(); - return retval; - } - -#define cleanup_prockey() {(void) krb5_finish_key(context, &eblock);} + if (retval = krb5_process_key(context, &eblock, pkeyblock)) + goto cleanup; /* call the decryption routine */ - if (retval = krb5_decrypt(context, (krb5_pointer) credmsg->enc_part.ciphertext.data, - (krb5_pointer) scratch->data, - scratch->length, &eblock, - 0)) { - cleanup_credmsg(); - cleanup_scratch(); - cleanup_prockey(); - return retval; + if (retval = krb5_decrypt(context, + (krb5_pointer) pcred->enc_part.ciphertext.data, + (krb5_pointer) scratch.data, + scratch.length, &eblock, 0)) { + (void)krb5_finish_key(context, &eblock); + goto cleanup; } - /* cred message is now decrypted -- do some cleanup */ + if (retval = krb5_finish_key(context, &eblock)) + goto cleanup; - cleanup_credmsg(); + /* now decode the decrypted stuff */ + if (retval = decode_krb5_enc_cred_part(&scratch, &ppart)) + goto cleanup_encpart; - if (retval = krb5_finish_key(context, &eblock)) { - cleanup_scratch(); - return retval; - } + *pcredenc = *ppart; + retval = 0; - /* now decode the decrypted stuff */ - if (retval = decode_krb5_enc_cred_part(scratch, &credmsg_enc_part)) { - cleanup_scratch(); - return retval; - } - cleanup_scratch(); +cleanup_encpart: + memset(ppart, 0, sizeof(*ppart)); + krb5_xfree(ppart); -#define cleanup_mesg() {krb5_xfree(credmsg_enc_part);} +cleanup: + memset(scratch.data, 0, scratch.length); + krb5_xfree(scratch.data); - if (retval = krb5_timeofday(context, ¤ttime)) { - cleanup_mesg(); - return retval; - } - if (!in_clock_skew(credmsg_enc_part->timestamp)) { - cleanup_mesg(); - return KRB5KRB_AP_ERR_SKEW; + return retval; +} +/*----------------------- krb5_rd_cred_basic -----------------------*/ + +static krb5_error_code +krb5_rd_cred_basic(context, pcreddata, pkeyblock, local_addr, remote_addr, + replaydata, pppcreds) + krb5_context context; + krb5_data * pcreddata; + krb5_keyblock * pkeyblock; + krb5_address * local_addr; + krb5_address * remote_addr; + krb5_replay_data * replaydata; + krb5_creds *** pppcreds; +{ + krb5_error_code retval; + krb5_cred * pcred; + krb5_int32 ncreds; + krb5_int32 i = 0; + krb5_cred_enc_part encpart; + + /* decode cred message */ + if (retval = decode_krb5_cred(pcreddata, &pcred)) + return retval; + + if (retval = decrypt_credencdata(context, pcred, pkeyblock, &encpart)) + goto cleanup_cred; + + if (!krb5_address_compare(context, remote_addr, encpart.s_address)) { + KRB5KRB_AP_ERR_BADADDR; + goto cleanup_cred; } - if (sender_addr && credmsg_enc_part->s_address && - !krb5_address_compare(context, sender_addr, - credmsg_enc_part->s_address)) { - cleanup_mesg(); - return KRB5KRB_AP_ERR_BADADDR; - } - if (recv_addr && credmsg_enc_part->r_address && - !krb5_address_compare(context, recv_addr, - credmsg_enc_part->r_address)) { - cleanup_mesg(); - return KRB5KRB_AP_ERR_BADADDR; - } - - if (credmsg_enc_part->r_address) { - krb5_address **our_addrs; - - if (retval = krb5_os_localaddr(&our_addrs)) { - cleanup_mesg(); - return retval; - } - if (!krb5_address_search(context, credmsg_enc_part->r_address, - our_addrs)) { - krb5_free_addresses(context, our_addrs); - cleanup_mesg(); - return KRB5KRB_AP_ERR_BADADDR; - } - krb5_free_addresses(context, our_addrs); + if (encpart.r_address) { + if (local_addr) { + if (!krb5_address_compare(context, local_addr, encpart.r_address)) { + retval = KRB5KRB_AP_ERR_BADADDR; + goto cleanup_cred; + } + } else { + krb5_address **our_addrs; + + if (retval = krb5_os_localaddr(&our_addrs)) { + goto cleanup_cred; + } + if (!krb5_address_search(context, encpart.r_address, our_addrs)) { + krb5_free_addresses(context, our_addrs); + retval = KRB5KRB_AP_ERR_BADADDR; + goto cleanup_cred; + } + krb5_free_addresses(context, our_addrs); + } } - if (retval = krb5_copy_principal(context, credmsg_enc_part->ticket_info[0]->client, - &creds->client)) { - return(retval); + replaydata->timestamp = encpart.timestamp; + replaydata->usec = encpart.usec; + replaydata->seq = encpart.nonce; + + /* + * Allocate the list of creds. The memory is allocated so that + * krb5_free_tgt_creds can be used to free the list. + */ + for (ncreds = 0; pcred->tickets[ncreds]; ncreds++); + if ((*pppcreds = + (krb5_creds **)malloc(sizeof(krb5_creds *) * ncreds + 1)) == NULL) { + retval = ENOMEM; + goto cleanup_cred; } - if (retval = krb5_copy_principal(context, credmsg_enc_part->ticket_info[0]->server, - &creds->server)) { - return(retval); - } + /* + * For each credential, create a strcture in the list of + * credentials and copy the information. + */ + while (i < ncreds) { + krb5_cred_info * pinfo; + krb5_creds * pcur; + krb5_data * pdata; + + if ((pcur = (krb5_creds *)malloc(sizeof(krb5_creds))) == NULL) { + retval = ENOMEM; + goto cleanup; + } + + (*pppcreds)[i] = pcur; + pinfo = encpart.ticket_info[i++]; + memset(pcur, 0, sizeof(krb5_creds)); + + if (retval = krb5_copy_principal(context, pinfo->client, &pcur->client)) + goto cleanup; - if (retval = - krb5_copy_keyblock_contents(context, credmsg_enc_part->ticket_info[0]->session, - &creds->keyblock)) { - return(retval); + if (retval = krb5_copy_principal(context, pinfo->server, &pcur->server)) + goto cleanup; + + if (retval = krb5_copy_keyblock_contents(context, pinfo->session, + &pcur->keyblock)) + goto cleanup; + + if (retval = krb5_copy_addresses(context, pinfo->caddrs, + &pcur->addresses)) + goto cleanup; + + if (retval = encode_krb5_ticket(pcred->tickets[i - 1], &pdata)) + goto cleanup; + + pcur->ticket = *pdata; + krb5_free_data(context, pdata); + + + pcur->is_skey = FALSE; + pcur->magic = KV5M_CREDS; + pcur->times = pinfo->times; + pcur->ticket_flags = pinfo->flags; + pcur->authdata = NULL; /* not used */ + memset(&pcur->second_ticket, 0, sizeof(pcur->second_ticket)); } - creds->keyblock.magic = KV5M_KEYBLOCK; - creds->keyblock.etype = credmsg->tickets[0]->enc_part.etype; -#undef clean -#define clean() {\ - memset((char *)creds->keyblock.contents, 0, creds->keyblock.length);} + /* + * NULL terminate the list + */ + (*pppcreds)[i] = NULL; + +cleanup: + if (retval) + while (i >= 0) + free((*pppcreds)[i--]); - creds->times = credmsg_enc_part->ticket_info[0]->times; - creds->is_skey = FALSE; - creds->ticket_flags = credmsg_enc_part->ticket_info[0]->flags; +cleanup_cred: + krb5_free_cred(context, pcred); - if (retval = krb5_copy_addresses(context, credmsg_enc_part->ticket_info[0]->caddrs, - &creds->addresses)) { - clean(); - return(retval); + return retval; +} + +/*----------------------- krb5_rd_cred -----------------------*/ + +extern krb5_deltat krb5_clockskew; +#define in_clock_skew(date) (labs((date)-currenttime) < krb5_clockskew) + +/* + * This functions takes as input an KRB_CRED message, validates it, and + * outputs the nonce and an array of the forwarded credentials. + */ +krb5_error_code INTERFACE +krb5_rd_cred(context, auth_context, pcreddata, pppcreds, outdata) + krb5_context context; + krb5_auth_context * auth_context; + krb5_data * pcreddata; + krb5_creds *** pppcreds; + krb5_replay_data * outdata; +{ + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_replay_data replaydata; + + /* Get keyblock */ + if ((keyblock = auth_context->local_subkey) == NULL) + if ((keyblock = auth_context->remote_subkey) == NULL) + keyblock = auth_context->keyblock; + + if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && + (outdata == NULL)) + /* Need a better error */ + return KRB5_RC_REQUIRED; + + if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) && + (auth_context->rcache == NULL)) + return KRB5_RC_REQUIRED; + + if (retval = krb5_rd_cred_basic(context, pcreddata, keyblock, + auth_context->local_addr, auth_context->remote_addr, + &replaydata, pppcreds)) + return retval; + + if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_TIME) { + krb5_donot_replay replay; + krb5_timestamp currenttime; + + if (retval = krb5_timeofday(context, ¤ttime)) + goto error; + + if (!in_clock_skew(replaydata.timestamp)) { + retval = KRB5KRB_AP_ERR_SKEW; + goto error; + } + + if (retval = krb5_gen_replay_name(context, auth_context->remote_addr, + "_forw", &replay.client)) + goto error; + + replay.server = ""; /* XXX */ + replay.cusec = replaydata.usec; + replay.ctime = replaydata.timestamp; + if (retval = krb5_rc_store(context, auth_context->rcache, &replay)) { + krb5_xfree(replay.client); + goto error; + } + krb5_xfree(replay.client); } - creds->second_ticket.length = 0; + if (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_DO_SEQUENCE) { + if (auth_context->remote_seq_number != replaydata.seq) { + retval = KRB5KRB_AP_ERR_BADORDER; + goto error; + } + auth_context->remote_seq_number++; + } - creds->authdata = 0; + if ((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || + (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) { + outdata->timestamp = replaydata.timestamp; + outdata->usec = replaydata.usec; + outdata->seq = replaydata.seq; + } - cleanup_mesg(); - return 0; -#undef clean -#undef cleanup_credmsg -#undef cleanup_scratch -#undef cleanup_prockey -#undef cleanup_mesg +error:; + if (retval) + krb5_xfree(*pppcreds); + return retval; } + diff --git a/src/lib/krb5/krb/rd_priv.c b/src/lib/krb5/krb/rd_priv.c index 3c5a416ba..71bca1647 100644 --- a/src/lib/krb5/krb/rd_priv.c +++ b/src/lib/krb5/krb/rd_priv.c @@ -136,7 +136,8 @@ krb5_rd_priv_basic(context, inbuf, keyblock, local_addr, remote_addr, if (retval = krb5_os_localaddr(&our_addrs)) { goto cleanup_data; } - if (!krb5_address_search(context, privmsg_enc_part->r_address, our_addrs)) { + if (!krb5_address_search(context, privmsg_enc_part->r_address, + our_addrs)) { krb5_free_addresses(context, our_addrs); retval = KRB5KRB_AP_ERR_BADADDR; goto cleanup_data; @@ -174,14 +175,20 @@ cleanup_privmsg:; krb5_error_code krb5_rd_priv(context, auth_context, inbuf, outbuf, outdata) - krb5_context context; - krb5_auth_context * auth_context; - const krb5_data * inbuf; - krb5_data * outbuf; - krb5_replay_data * outdata; + krb5_context context; + krb5_auth_context * auth_context; + const krb5_data * inbuf; + krb5_data * outbuf; + krb5_replay_data * outdata; { - krb5_error_code retval; - krb5_replay_data replaydata; + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_replay_data replaydata; + + /* Get keyblock */ + if ((keyblock = auth_context->local_subkey) == NULL) + if ((keyblock = auth_context->remote_subkey) == NULL) + keyblock = auth_context->keyblock; if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && @@ -193,7 +200,7 @@ krb5_rd_priv(context, auth_context, inbuf, outbuf, outdata) (auth_context->rcache == NULL)) return KRB5_RC_REQUIRED; - if (retval = krb5_rd_priv_basic(context, inbuf, auth_context->keyblock, + if (retval = krb5_rd_priv_basic(context, inbuf, keyblock, auth_context->local_addr, auth_context->remote_addr, auth_context->i_vector, &replaydata, outbuf)) return retval; diff --git a/src/lib/krb5/krb/rd_safe.c b/src/lib/krb5/krb/rd_safe.c index b7798c16d..2f3f54471 100644 --- a/src/lib/krb5/krb/rd_safe.c +++ b/src/lib/krb5/krb/rd_safe.c @@ -163,14 +163,15 @@ cleanup: krb5_error_code krb5_rd_safe(context, auth_context, inbuf, outbuf, outdata) - krb5_context context; - krb5_auth_context * auth_context; - const krb5_data * inbuf; - krb5_data * outbuf; - krb5_replay_data * outdata; + krb5_context context; + krb5_auth_context * auth_context; + const krb5_data * inbuf; + krb5_data * outbuf; + krb5_replay_data * outdata; { - krb5_error_code retval; - krb5_replay_data replaydata; + krb5_error_code retval; + krb5_keyblock * keyblock; + krb5_replay_data replaydata; if (((auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_TIME) || (auth_context->auth_context_flags & KRB5_AUTH_CONTEXT_RET_SEQUENCE)) && @@ -182,7 +183,12 @@ krb5_rd_safe(context, auth_context, inbuf, outbuf, outdata) (auth_context->rcache == NULL)) return KRB5_RC_REQUIRED; - if (retval = krb5_rd_safe_basic(context, inbuf, auth_context->keyblock, + /* Get keyblock */ + if ((keyblock = auth_context->local_subkey) == NULL) + if ((keyblock = auth_context->remote_subkey) == NULL) + keyblock = auth_context->keyblock; + + if (retval = krb5_rd_safe_basic(context, inbuf, keyblock, auth_context->local_addr, auth_context->remote_addr, &replaydata, outbuf)) return retval; diff --git a/src/lib/krb5/krb/recvauth.c b/src/lib/krb5/krb/recvauth.c index b8e384a5d..d18f819ab 100644 --- a/src/lib/krb5/krb/recvauth.c +++ b/src/lib/krb5/krb/recvauth.c @@ -52,6 +52,7 @@ krb5_recvauth(context, auth_context, krb5_keytab keytab; krb5_ticket ** ticket; { + krb5_auth_context * new_auth_context; krb5_flags ap_option; krb5_error_code retval, problem; krb5_data inbuf; @@ -131,17 +132,19 @@ krb5_recvauth(context, auth_context, } if (problem) return(problem); - /* - * Setup the replay cache. - */ - if (server) { - problem = krb5_get_server_rcache(context, + +/* Were clear here */ + /* + * Setup the replay cache. + */ + if (server) { + problem = krb5_get_server_rcache(context, krb5_princ_component(context, server, 0), &rcache); - } else { - null_server.length = 7; - null_server.data = "default"; - problem = krb5_get_server_rcache(context, &null_server, &rcache); - } + } else { + null_server.length = 7; + null_server.data = "default"; + problem = krb5_get_server_rcache(context, &null_server, &rcache); + } if (!problem) { if (krb5_rc_recover(context, rcache)) { @@ -149,78 +152,80 @@ krb5_recvauth(context, auth_context, * If the rc_recover() didn't work, then try * initializing the replay cache. */ - if (krb5_rc_initialize(context, rcache, krb5_clockskew)) { + if (problem = 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); - return(retval); - } + /* + * Now, let's read the AP_REQ message and decode it + */ + if (retval = krb5_read_message(context, fd, &inbuf)) { + if (problem) /* Return top level problem */ + retval = problem; + goto cleanup; + } - if (*auth_context == NULL) { - if (retval = krb5_auth_con_init(context, auth_context)) - return(retval); + if (!problem) { + if (*auth_context == NULL) { + problem = krb5_auth_con_init(context, &new_auth_context); + *auth_context = new_auth_context; } - - krb5_auth_con_setrcache(context, *auth_context, rcache); - - if (!problem) - problem = krb5_rd_req(context, auth_context, &inbuf, server, + } + if (!problem) { + problem = krb5_auth_con_setrcache(context, *auth_context, rcache); + } + if (!problem) { + 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 there was a problem, send back a krb5_error message, - * preceeded by the length of the krb5_error message. If - * everything's ok, send back 0 for the length. - */ - if (problem) { - krb5_error error; - const char *message; + /* + * If there was a problem, send back a krb5_error message, + * preceeded by the length of the krb5_error message. If + * everything's ok, send back 0 for the length. + */ + if (problem) { + krb5_error error; + const char *message; - memset((char *)&error, 0, sizeof(error)); - krb5_us_timeofday(context, &error.stime, &error.susec); - error.server = server; - error.error = problem - ERROR_TABLE_BASE_krb5; - if (error.error > 127) - error.error = KRB_ERR_GENERIC; - message = error_message(problem); - error.text.length = strlen(message) + 1; - if (!(error.text.data = malloc(error.text.length))) - return(ENOMEM); - strcpy(error.text.data, message); - if (retval = krb5_mk_error(context, &error, &outbuf)) { - free(error.text.data); - return(retval); - } - free(error.text.data); - } else { - outbuf.length = 0; - outbuf.data = 0; + memset((char *)&error, 0, sizeof(error)); + krb5_us_timeofday(context, &error.stime, &error.susec); + error.server = server; + error.error = problem - ERROR_TABLE_BASE_krb5; + if (error.error > 127) + error.error = KRB_ERR_GENERIC; + message = error_message(problem); + error.text.length = strlen(message) + 1; + if (!(error.text.data = malloc(error.text.length))) { + retval = ENOMEM; + goto cleanup; } - if (retval = krb5_write_message(context, fd, &outbuf)) { - if (outbuf.data) - krb5_xfree(outbuf.data); - return(retval); - } - if (problem) { - /* - * We sent back an error, we need to return - */ - return(problem); + strcpy(error.text.data, message); + if (retval = krb5_mk_error(context, &error, &outbuf)) { + free(error.text.data); + goto cleanup; } + free(error.text.data); + } else { + outbuf.length = 0; + outbuf.data = 0; + } + + if (!problem) { + retval = krb5_write_message(context, fd, &outbuf); + if (outbuf.data) + krb5_xfree(outbuf.data); + if (retval) + goto cleanup; + } else { + /* We sent back an error, we need cleanup then return */ + retval = problem; + goto cleanup; + } /* Here lies the mutual authentication stuff... */ if ((ap_option & AP_OPTS_MUTUAL_REQUIRED)) { @@ -230,5 +235,11 @@ krb5_recvauth(context, auth_context, retval = krb5_write_message(context, fd, &outbuf); krb5_xfree(outbuf.data); } + +cleanup:; + if (retval) { + if (rcache) + krb5_rc_close(context, rcache); + } return retval; } -- 2.26.2