#include <krb5/copyright.h>
#include <krb5/krb5.h>
+#include <krb5/krb5_err.h>
+#include <errno.h>
+
+#include <krb5/ext-proto.h>
+#include "int-proto.h"
/*
* Retrieve credentials for principal creds->client,
* TGT credentials obtained in the process of contacting the KDC are
* returned in an array of credentials; tgts is filled in to point to an
* array of pointers to credential structures (if no TGT's were used, the
- * pointer is zeroed).
+ * pointer is zeroed). TGT's may be returned even if no useful end ticket
+ * was obtained.
*
* The returned credentials are NOT cached.
*
* returns errors, system errors.
*/
+/* helper function: convert flags to necessary KDC options */
+#define flags2options(flags) (flags & KDC_TKT_COMMON_MASK)
+
krb5_error_code
krb5_get_cred_from_kdc (ccache, cred, tgts)
krb5_ccache ccache;
krb5_creds ***tgts;
{
krb5_creds tgt, tgtq;
+ krb5_creds **ret_tgts = 0;
+ krb5_principal *tgs_list, next_server;
krb5_error_code retval;
+ int nservers;
+ /* in case we never get a TGT, zero the return */
+ tgts = 0;
+
/*
* we know that the desired credentials aren't in the cache yet.
*
* To get them, we first need a tgt for the realm of the server.
+ * first, we see if we have such a TGT in cache.
*/
-
- /* first, we see if we have a shortcut path to the server's realm. */
/*
* look for ticket with:
if (retval = krb5_tgtname(cred->server, cred->client, &tgtq.server))
return retval;
- /* go find it.. */
+
+ /* try to fetch it directly */
retval = krb5_cc_retrieve_cred (ccache,
- KRB5_CF_CLIENT|KRB5_CF_SERVER,
+ 0, /* default is client & server */
&tgtq,
&tgt);
krb5_free_principal(tgtq.server);
if (retval != 0) {
if (retval != KRB5_CC_NOTFOUND)
goto out;
- /* nope; attempt to get tgt */
+ /* don't have the right TGT in the cred cache. Time to iterate
+ across realms to get the right TGT. */
+
+ /* get a list of realms to consult */
+ retval = krb5_walk_realm_tree(cred->client, cred->server, &tgs_list);
+ if (retval)
+ goto out;
+ /* walk the list BACKWARDS until we find a cached
+ TGT, then move forward obtaining TGTs until we get the last
+ TGT needed */
+ for (next_server = tgs_list[0]; next_server; next_server++);
+ nservers = next_server - tgs_list[0];
+ next_server--;
+
+ /* next_server now points to the last TGT */
+ for (; next_server >= tgs_list[0]; next_server--) {
+ tgtq.server = next_server;
+ retval = krb5_cc_retrieve_cred (ccache,
+ 0, /* default is client & server */
+ &tgtq,
+ &tgt);
+ if (retval) {
+ if (retval != KRB5_CC_NOTFOUND) {
+ krb5_free_realm_tree(tgs_list);
+ goto out;
+ }
+ continue;
+ }
+ next_server++;
+ break; /* found one! */
+ }
+ /* allocate storage for TGT pointers. */
+ ret_tgts = (krb5_creds **)calloc(nservers+1, sizeof(krb5_creds));
+ if (!ret_tgts) {
+ retval = ENOMEM;
+ goto out;
+ }
+ for (nservers = 0; next_server; next_server++, nservers++) {
+ /* now get the TGTs */
+ tgtq.times = tgt.times;
+ tgtq.client = tgt.client;
+ tgtq.server = next_server;
+ tgtq.is_skey = FALSE;
+ tgtq.ticket_flags = tgt.ticket_flags;
+ if (retval = krb5_get_cred_via_tgt(&tgt,
+ flags2options(tgtq.ticket_flags),
+ 0, /* XXX etype */
+ 0, /* XXX sumtype */
+ 0, /* XXX addrs */
+ &tgtq))
+ goto out;
+ /* save tgt in return array */
+ if (retval = krb5_copy_cred(&tgtq, &ret_tgts[nservers]))
+ goto out;
+ /* XXX need to clean up stuff pointed to by tgtq? */
+ tgt = tgtq;
+ }
}
- /* got tgt! */
- retval = krb5_get_cred_via_tgt(&tgt, cred);
+ /* got/finally have tgt! */
+ retval = krb5_get_cred_via_tgt(&tgt,
+ flags2options(tgtq.ticket_flags),
+ 0, /* XXX etype */
+ 0, /* XXX sumtype */
+ 0, /* XXX addrs */
+ cred);
out:
- /* XXX what about tgts? */
return retval;
}
#include <stdio.h>
#include <krb5/libos-proto.h>
#include <krb5/ext-proto.h>
-
-static krb5_flags
-creds_to_kdcoptions(creds)
-krb5_creds *creds;
-{
- krb5_flags result;
-
- /* XXX this is a hack; we don't necessarily want all these! */
- result = creds->ticket_flags & KDC_TKT_COMMON_MASK;
- result |= KDC_OPT_RENEWABLE_OK;
- return result;
-}
+#include "int-proto.h"
krb5_error_code
-krb5_get_cred_via_tgt (tgt, cred)
- krb5_creds *tgt; /* IN */
- krb5_creds *cred; /* IN OUT */
+krb5_get_cred_via_tgt (DECLARG(krb5_creds *, tgt),
+ DECLARG(krb5_flags, kdcoptions),
+ DECLARG(krb5_enctype, etype),
+ DECLARG(krb5_cksumtype, sumtype),
+ DECLARG(krb5_address **, addrs),
+ DECLARG(krb5_creds *, cred))
+OLDDECLARG(krb5_creds *, tgt)
+OLDDECLARG(krb5_flags, kdcoptions)
+OLDDECLARG(krb5_enctype, etype)
+OLDDECLARG(krb5_cksumtype, sumtype)
+OLDDECLARG(krb5_address **, addrs)
+OLDDECLARG(krb5_creds *, cred)
{
krb5_tgs_req tgsreq;
krb5_real_tgs_req realreq;
krb5_error_code retval;
- krb5f_principal tempprinc;
+ krb5_principal tempprinc;
krb5_data *scratch, reply;
krb5_checksum ap_checksum;
krb5_kdc_rep *dec_rep;
bzero((char *)&realreq, sizeof(realreq));
- realreq.kdc_options = creds_to_kdcoptions(cred);
+ realreq.kdc_options = kdcoptions;
realreq.from = cred->times.starttime;
realreq.till = cred->times.endtime;
realreq.rtime = cred->times.renew_till;
if (retval = krb5_timeofday(&realreq.ctime))
return(retval);
- realreq.etype = xxx;
+ realreq.etype = etype;
realreq.server = cred->server;
- realreq.addresses = xxx;
+ realreq.addresses = addrs;
/* enc_part & enc_part2 are left blank for the moment. */
if (retval = encode_krb5_real_tgs_req(&realreq, &scratch))
return(retval);
/* xxx choose a checksum type */
- if (retval = (*(krb5_cksumarray[xxx]->sum_func))(scratch->data,
- 0, /* XXX? */
- (krb5_pointer) cred->keyblock.contents,
- scratch->length,
- cred->keyblock.length,
- &ap_checksum)) {
+ if (retval = (*(krb5_cksumarray[sumtype]->
+ sum_func))(scratch->data,
+ 0, /* XXX? */
+ (krb5_pointer) cred->keyblock.contents,
+ scratch->length,
+ cred->keyblock.length,
+ &ap_checksum)) {
krb5_free_data(scratch);
return retval;
}
tgsreq.tgs_request = *scratch;
xfree(scratch);
-#define cleanup() {(void) free(tgsreq.tgs_request.data);}
+#define cleanup() {(void) free((char *)tgsreq.tgs_request.data); \
+ (void) free((char *)ap_checksum.contents);}
/*
* Now get an ap_req.
/* we expect *reply to be either an error or a proper reply */
if (retval = krb5_decode_kdc_rep(&reply,
&tgt->keyblock,
- xxx, /* enctype */
+ realreq.etype, /* enctype */
&dec_rep)) {
if (decode_krb5_error(&reply, &err_reply)) {
cleanup();
if (!krb5_principal_compare(dec_rep->client, tgt->client)) {
cleanup();
- return XXX_MODIFIED;
+ return KRB5_KDCREP_MODIFIED;
}
/* put pieces into cred-> */
- if (retval = xxx_copy_keyblock(dec_rep->enc_part2->session,
- &cred->keyblock)) {
+ if (retval = krb5_copy_keyblock(dec_rep->enc_part2->session,
+ &cred->keyblock)) {
cleanup();
return retval;
}
/* check compatibility here first ? XXX */
cred->ticket_flags = dec_rep->enc_part2->flags;
cred->is_skey = FALSE;
- retval = xxx_copy_ticket(dec_rep->ticket, &cred->ticket);
+ retval = krb5_encode_ticket(dec_rep->ticket, &scratch);
+ if (!retval) {
+ cred->ticket = *scratch;
+ free((char *)scratch);
+ }
cleanup();
return retval;
}