* Makefile.in : Added gc_via_tkt.c and removed get_fcreds.c
authorChris Provenzano <proven@mit.edu>
Wed, 26 Apr 1995 03:03:26 +0000 (03:03 +0000)
committerChris Provenzano <proven@mit.edu>
Wed, 26 Apr 1995 03:03:26 +0000 (03:03 +0000)
* 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
src/lib/krb5/krb/Makefile.in
src/lib/krb5/krb/auth_con.c
src/lib/krb5/krb/gc_via_tkt.c [new file with mode: 0644]
src/lib/krb5/krb/mk_cred.c
src/lib/krb5/krb/mk_priv.c
src/lib/krb5/krb/mk_safe.c
src/lib/krb5/krb/rd_cred.c
src/lib/krb5/krb/rd_priv.c
src/lib/krb5/krb/rd_safe.c
src/lib/krb5/krb/recvauth.c

index 9f18889b499eb1770037946f1848ea3691cdc279..b963cb4e4ea4acac7b1bd69f71ae30de65bf325d 100644 (file)
@@ -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  <tytso@dcl>
 
        * Makefile.in, configure.in (t_walk_rtree): Add WITH_NETLIBS and
index c2053bd01a8d1b981d05d74a63297ab7521dee77..d0f176e96b398bebdd3dce42a34d1e1750647bb9 100644 (file)
@@ -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  \
index 134e07ba5d906b9bd16724cfb948f03af818959b..6821a05d83092e84eda24516de30bc47b1c86cba 100644 (file)
@@ -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 (file)
index 0000000..c548b3d
--- /dev/null
@@ -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;
+}
index 12df2c88a37219f0c3cf8f4df73b516f11defac7..6b95301a3b2652c76401a788c0eb7b238c2816bf 100644 (file)
-/*
- * 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 <k5-int.h>
+#include "auth_con.h"
 
+#include <stddef.h>           /* NULL */
+#include <stdlib.h>           /* malloc */
+#include <errno.h>            /* 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
 }
 
index 6a804915bfc1e4ae151d883a9ec745c4bbf8c792..40c9bfa578109e6e5797a1c67f95c844cc3ce04e 100644 (file)
@@ -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);
index 36670edff72ca8d5ed5ad3daac28dc164254c0e5..47238c4906c010e2b161d36049e6e32f0acc9ec6 100644 (file)
@@ -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) {
index dfe774b5126156081f33ed56af0f70f28ced1c14..179a922b70d971698cdb6eb3397b74a182803c00 100644 (file)
-/*
- * 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 <k5-int.h>
+#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 <stddef.h>           /* NULL */
+#include <stdlib.h>           /* malloc */
+#include <errno.h>            /* 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, &currenttime)) {
-       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, &currenttime))
+            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;
 }
 
+
index 3c5a416ba589ec2e76cbd7364f8880110d255850..71bca16473e53ef1ef60d5243bd6960dcf712ed9 100644 (file)
@@ -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;
index b7798c16d16bdb57a166d67c2ad69a6c756dbd12..2f3f54471c39c727c1fba4ec1472f1fa1add5239 100644 (file)
@@ -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;
index b8e384a5df9c02e04f3d54f867ad4fd50e73d9ca..d18f819ab1fad596aedf3fdb9f7056261028e1ed 100644 (file)
@@ -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;
 }