Пример #1
0
/*
 * try_kdc()
 *
 * Using CUR_TGT, attempt to get desired NXT_TGT.  Update NXT_KDC if
 * successful.
 */
static krb5_error_code
try_kdc(struct tr_state *ts, krb5_creds *tgtq)
{
    krb5_error_code retval;
    krb5_creds ltgtq;

    TR_DBG(ts, "try_kdc");
    /* This check should probably be in gc_via_tkt. */
    if (!krb5_c_valid_enctype(ts->cur_tgt->keyblock.enctype))
	return KRB5_PROG_ETYPE_NOSUPP;

    ltgtq = *tgtq;
    ltgtq.is_skey = FALSE;
    ltgtq.ticket_flags = ts->cur_tgt->ticket_flags;
    retval = krb5_get_cred_via_tkt(ts->ctx, ts->cur_tgt,
				   FLAGS2OPTS(ltgtq.ticket_flags),
				   ts->cur_tgt->addresses,
				   &ltgtq, &ts->kdc_tgts[ts->ntgts++]);
    if (retval) {
	ts->ntgts--;
	ts->nxt_tgt = ts->cur_tgt;
	TR_DBG_RET(ts, "try_kdc", retval);
	return retval;
    }
    ts->nxt_tgt = ts->kdc_tgts[ts->ntgts-1];
    retval = find_nxt_kdc(ts);
    TR_DBG_RET(ts, "try_kdc", retval);
    return retval;
}
Пример #2
0
/*
 * find_nxt_kdc()
 *
 * A NXT_TGT gotten from an intermediate KDC might actually be a
 * referral.  Search KDC_LIST forward starting from CUR_KDC, looking
 * for the KDC with the same remote realm as NXT_TGT.  If we don't
 * find it, the intermediate KDC is leading us off the transit path.
 *
 * Match on CUR_KDC's remote realm, not local realm, because, among
 * other reasons, we can get a referral to the final realm; e.g.,
 * given
 *
 *     KDC_LIST == { krbtgt/R1@R1, krbtgt/R2@R1, krbtgt/R3@R2,
 *                   krbtgt/R4@R3, NULL }
 *     CUR_TGT->SERVER == krbtgt/R2@R1
 *     NXT_TGT->SERVER == krbtgt/R4@R2
 *
 * i.e., we got a ticket issued by R2 with remote realm R4, we want to
 * find krbtgt/R4@R3, not krbtgt/R3@R2, even though we have no TGT
 * with R3 as its local realm.
 *
 * Set up for next iteration of do_traversal() loop by pointing
 * NXT_KDC to one entry forward of the match.
 */
static krb5_error_code
find_nxt_kdc(struct tr_state *ts)
{
    krb5_data *r1, *r2;
    krb5_principal *kdcptr;

    TR_DBG(ts, "find_nxt_kdc");
    assert(ts->ntgts > 0);
    assert(ts->nxt_tgt == ts->kdc_tgts[ts->ntgts-1]);
    if (krb5_princ_size(ts->ctx, ts->nxt_tgt->server) != 2)
	return KRB5_KDCREP_MODIFIED;

    r1 = krb5_princ_component(ts->ctx, ts->nxt_tgt->server, 1);

    for (kdcptr = ts->cur_kdc + 1; *kdcptr != NULL; kdcptr++) {

	r2 = krb5_princ_component(ts->ctx, *kdcptr, 1);

	if (r1 != NULL && r2 != NULL && data_eq(*r1, *r2)) {
	    break;
	}
    }
    if (*kdcptr != NULL) {
	ts->nxt_kdc = kdcptr;
	TR_DBG_RET(ts, "find_nxt_kdc", 0);
	return 0;
    }

    r2 = krb5_princ_component(ts->ctx, ts->kdc_list[0], 1);
    if (r1 != NULL && r2 != NULL &&
	r1->length == r2->length &&
	!memcmp(r1->data, r2->data, r1->length)) {
	TR_DBG_RET(ts, "find_nxt_kdc: looped back to local",
		   KRB5_KDCREP_MODIFIED);
	return KRB5_KDCREP_MODIFIED;
    }

    /*
     * Realm is not in our list; we probably got an unexpected realm
     * referral.
     */
    ts->offpath_tgt = ts->nxt_tgt;
    if (ts->cur_kdc == ts->kdc_list) {
	/*
	 * Local KDC referred us off path; trust it for caching
	 * purposes.
	 */
	return 0;
    }
    /*
     * Unlink the off-path TGT from KDC_TGTS but don't free it,
     * because we should return it.
     */
    ts->kdc_tgts[--ts->ntgts] = NULL;
    ts->nxt_tgt = ts->cur_tgt;
    TR_DBG_RET(ts, "find_nxt_kdc", 0);
    return 0;
}
Пример #3
0
/*
 * try_kdc()
 *
 * Using CUR_TGT, attempt to get desired NXT_TGT.  Update NXT_KDC if
 * successful.
 */
static krb5_error_code
try_kdc(struct tr_state *ts, krb5_creds *tgtq)
{
    krb5_error_code retval;
    krb5_creds ltgtq;
    krb5_creds *tmp_out_cred;

    TR_DBG(ts, "try_kdc");
    /* This check should probably be in gc_via_tkt. */
    if (!krb5_c_valid_enctype(ts->cur_tgt->keyblock.enctype))
	return KRB5_PROG_ETYPE_NOSUPP;

    ltgtq = *tgtq;
    ltgtq.is_skey = FALSE;
    ltgtq.ticket_flags = ts->cur_tgt->ticket_flags;
    /*
     * Solaris Kerberos:
     * Store credential in a temporary ticket as we may not
     * want to add it to ts->kdc_tgts if it is already in
     * the cache.
     */
    retval = krb5_get_cred_via_tkt(ts->ctx, ts->cur_tgt,
				   FLAGS2OPTS(ltgtq.ticket_flags),
				   ts->cur_tgt->addresses,
				   &ltgtq, &tmp_out_cred);
    if (retval) {
	ts->ntgts--;
	ts->nxt_tgt = ts->cur_tgt;
	TR_DBG_RET(ts, "try_kdc", retval);
	return retval;
    }

    /*
     * Solaris Kerberos:
     * See if the returned creds are different to the requested creds.
     * This can happen when the server returns a TGT "closer" to the
     * desired realm.
     */ 
    if (!(krb5_principal_compare(ts->ctx, tgtq->server, tmp_out_cred->server))) {
	    /* Not equal, ticket may already be in the cache */
	    retval = try_ccache(ts, tmp_out_cred);
	    if (!retval) {
	        krb5_free_creds(ts->ctx, tmp_out_cred);
	        retval = find_nxt_kdc(ts);
	        return retval;
	    }
	}

    ts->kdc_tgts[ts->ntgts++] = tmp_out_cred;
    ts->nxt_tgt = ts->kdc_tgts[ts->ntgts-1];
    retval = find_nxt_kdc(ts);
    TR_DBG_RET(ts, "try_kdc", retval);
    return retval;
}
Пример #4
0
/*
 * try_ccache()
 *
 * Attempt to retrieve desired NXT_TGT from ccache.  Point NXT_TGT to
 * it if successful.
 */
static krb5_error_code
try_ccache(struct tr_state *ts, krb5_creds *tgtq)
{
    krb5_error_code retval;
    krb5_timestamp saved_endtime;

    TR_DBG(ts, "try_ccache");
    /*
     * Solaris Kerberos:
     * Ensure the retrieved cred isn't stale.
     * Set endtime to now so krb5_cc_retrieve_cred won't return an expired ticket.
     */
    saved_endtime = tgtq->times.endtime;
    if ((retval = krb5_timeofday(ts->ctx, &(tgtq->times.endtime))) != 0) {
    	tgtq->times.endtime = saved_endtime;
    	return retval;
    }
    retval = krb5_cc_retrieve_cred(ts->ctx, ts->ccache, RETR_FLAGS,
				   tgtq, ts->nxt_cc_tgt);
    if (!retval) {
	shift_cc_tgts(ts);
	ts->nxt_tgt = ts->cur_cc_tgt;
    }
    /*
     * Solaris Kerberos:
     * Ensure that tgtq->times.endtime is reset back to its original value so
     * that if tgtq is used to request a ticket from the KDC it doesn't request
     * a ticket with an endtime set to "now".
     */
    tgtq->times.endtime = saved_endtime;
    TR_DBG_RET(ts, "try_ccache", retval);
    return retval;
}
Пример #5
0
/*
 * try_ccache()
 *
 * Attempt to retrieve desired NXT_TGT from ccache.  Point NXT_TGT to
 * it if successful.
 */
static krb5_error_code
try_ccache(struct tr_state *ts, krb5_creds *tgtq)
{
    krb5_error_code retval;

    TR_DBG(ts, "try_ccache");
    retval = krb5_cc_retrieve_cred(ts->ctx, ts->ccache, RETR_FLAGS,
				   tgtq, ts->nxt_cc_tgt);
    if (!retval) {
	shift_cc_tgts(ts);
	ts->nxt_tgt = ts->cur_cc_tgt;
    }
    TR_DBG_RET(ts, "try_ccache", retval);
    return retval;
}
Пример #6
0
/*
 * find_nxt_kdc()
 *
 * A NXT_TGT gotten from an intermediate KDC might actually be a
 * referral.  Search KDC_LIST forward starting from CUR_KDC, looking
 * for the KDC with the same remote realm as NXT_TGT.  If we don't
 * find it, the intermediate KDC is leading us off the transit path.
 *
 * Match on CUR_KDC's remote realm, not local realm, because, among
 * other reasons, we can get a referral to the final realm; e.g.,
 * given
 *
 *     KDC_LIST == { krbtgt/R1@R1, krbtgt/R2@R1, krbtgt/R3@R2,
 *                   krbtgt/R4@R3, NULL }
 *     CUR_TGT->SERVER == krbtgt/R2@R1
 *     NXT_TGT->SERVER == krbtgt/R4@R2
 *
 * i.e., we got a ticket issued by R2 with remote realm R4, we want to
 * find krbtgt/R4@R3, not krbtgt/R3@R2, even though we have no TGT
 * with R3 as its local realm.
 *
 * Set up for next iteration of do_traversal() loop by pointing
 * NXT_KDC to one entry forward of the match.
 */
static krb5_error_code
find_nxt_kdc(struct tr_state *ts)
{
    krb5_data *r1, *r2;
    krb5_principal *kdcptr;

    TR_DBG(ts, "find_nxt_kdc");
  /*
   * Solaris Kerberos:
   * The following assertion is not be true for the case when
   * ts->nxt points to a cached ticket and not to a freshly
   * fetched TGT in ts->kdc_tgts. See changes in try_kdc()
   */
  /*  assert(ts->nxt_tgt == ts->kdc_tgts[ts->ntgts-1]); */
    if (krb5_princ_size(ts->ctx, ts->nxt_tgt->server) != 2) {
	/* Solaris Kerberos */
	char *s_name = NULL;
	int err = krb5_unparse_name(ts->ctx, ts->nxt_tgt->server, &s_name);
	if (!err) {
	    krb5_set_error_message(ts->ctx, KRB5_KDCREP_MODIFIED,
				dgettext(TEXT_DOMAIN,
					"KDC reply did not match expectations: server '%s' principal size should be 2"),
				s_name);
	    krb5_free_unparsed_name(ts->ctx, s_name);
	} else
	    krb5_set_error_message(ts->ctx, KRB5_KDCREP_MODIFIED,
				dgettext(TEXT_DOMAIN,
					"KDC reply did not match expectations: server principal size should be 2"));
	return KRB5_KDCREP_MODIFIED;
    }
    r1 = krb5_princ_component(ts->ctx, ts->nxt_tgt->server, 1);

    for (kdcptr = ts->cur_kdc + 1; *kdcptr != NULL; kdcptr++) {

	r2 = krb5_princ_component(ts->ctx, *kdcptr, 1);

	if (r1 != NULL && r2 != NULL &&
	    r1->length == r2->length &&
	    !memcmp(r1->data, r2->data, r1->length)) {
	    break;
	}
    }
    if (*kdcptr == NULL) {
	/*
	 * Not found; we probably got an unexpected realm referral.
	 * Don't touch NXT_KDC, thus allowing next_closest_tgt() to
	 * continue looping backwards.
	 */
	/*
	 * Solaris Kerberos:
	 * Only free the allocated creds if they are in kdc_tgts. If they
	 * are in cc_tgts no freeing is necessary.
	 */
	if (ts->ntgts > 0 && ts->nxt_tgt == ts->kdc_tgts[ts->ntgts-1]) {
	    /* Punt NXT_TGT from KDC_TGTS if bogus. */
	    krb5_free_creds(ts->ctx, ts->kdc_tgts[--ts->ntgts]);
	    ts->kdc_tgts[ts->ntgts] = NULL;
	}
	TR_DBG_RET(ts, "find_nxt_kdc", KRB5_KDCREP_MODIFIED);
	krb5_set_error_message(ts->ctx, KRB5_KDCREP_MODIFIED,
			    dgettext(TEXT_DOMAIN,
				    "KDC reply did not match expectation: KDC not found.  Probably got an unexpected realm referral"));
	return KRB5_KDCREP_MODIFIED;
    }
    ts->nxt_kdc = kdcptr;
    TR_DBG_RET(ts, "find_nxt_kdc", 0);
    return 0;
}