예제 #1
0
static void
store_tgts(krb5_context context, krb5_ccache ccache, krb5_creds **tgts)
{
    size_t n;

    for (n = 0; tgts && tgts[n]; n++) {
	krb5_const_principal server = tgts[n]->server; 

	if (krb5_principal_is_krbtgt(context, server) && strcmp(server->name.name_string.val[1], server->realm) != 0)
	    krb5_cc_store_cred(context, ccache, tgts[n]);
    }
    for (n = 0; tgts && tgts[n]; n++)
	krb5_free_creds(context, tgts[n]);
}
예제 #2
0
static krb5_error_code
get_cred_kdc_referral(krb5_context context,
		      krb5_kdc_flags flags,
		      krb5_ccache ccache,
		      krb5_creds *in_creds,
		      krb5_principal impersonate_principal,
		      Ticket *second_ticket,			
		      krb5_creds **out_creds,
		      krb5_creds ***ret_tgts)
{
    krb5_const_realm client_realm;
    krb5_error_code ret;
    krb5_creds tgt, referral, ticket;
    int loop = 0;
    int ok_as_delegate = 1;

    if (in_creds->server->name.name_string.len < 2 && !flags.b.canonicalize) {
	krb5_set_error_message(context, KRB5KDC_ERR_PATH_NOT_ACCEPTED,
			       N_("Name too short to do referals, skipping", ""));
	return KRB5KDC_ERR_PATH_NOT_ACCEPTED;
    }

    memset(&tgt, 0, sizeof(tgt));
    memset(&ticket, 0, sizeof(ticket));

    flags.b.canonicalize = 1;

    *out_creds = NULL;

    client_realm = krb5_principal_get_realm(context, in_creds->client);

    /* find tgt for the clients base realm */
    {
	krb5_principal tgtname;
	
	ret = krb5_make_principal(context, &tgtname,
				  client_realm,
				  KRB5_TGS_NAME,
				  client_realm,
				  NULL);
	if(ret)
	    return ret;
	
	ret = find_cred(context, ccache, tgtname, *ret_tgts, &tgt);
	krb5_free_principal(context, tgtname);
	if (ret)
	    return ret;
    }

    referral = *in_creds;
    ret = krb5_copy_principal(context, in_creds->server, &referral.server);
    if (ret) {
	krb5_free_cred_contents(context, &tgt);
	return ret;
    }
    ret = krb5_principal_set_realm(context, referral.server, client_realm);
    if (ret) {
	krb5_free_cred_contents(context, &tgt);
	krb5_free_principal(context, referral.server);
	return ret;
    }

    while (loop++ < 17) {
	krb5_creds **tickets;
	krb5_creds mcreds;
	char *referral_realm;

	/* Use cache if we are not doing impersonation or contrainte deleg */
	if (impersonate_principal == NULL || flags.b.constrained_delegation) {
	    krb5_cc_clear_mcred(&mcreds);
	    mcreds.server = referral.server;
	    ret = krb5_cc_retrieve_cred(context, ccache, 0, &mcreds, &ticket);
	} else
	    ret = EINVAL;

	if (ret) {
	    ret = get_cred_kdc_address(context, ccache, flags, NULL,
				       &referral, &tgt, impersonate_principal,
				       second_ticket, &ticket);
	    if (ret)
		goto out;
	}

	/* Did we get the right ticket ? */
	if (krb5_principal_compare_any_realm(context,
					     referral.server,
					     ticket.server))
	    break;

	if (!krb5_principal_is_krbtgt(context, ticket.server)) {
	    krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US,
				   N_("Got back an non krbtgt "
				      "ticket referrals", ""));
	    ret = KRB5KRB_AP_ERR_NOT_US;
	    goto out;
	}

	referral_realm = ticket.server->name.name_string.val[1];

	/* check that there are no referrals loops */
	tickets = *ret_tgts;

	krb5_cc_clear_mcred(&mcreds);
	mcreds.server = ticket.server;

	while(tickets && *tickets){
	    if(krb5_compare_creds(context,
				  KRB5_TC_DONT_MATCH_REALM,
				  &mcreds,
				  *tickets))
	    {
		krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
				       N_("Referral from %s "
					  "loops back to realm %s", ""),
				       tgt.server->realm,
				       referral_realm);
		ret = KRB5_GET_IN_TKT_LOOP;
                goto out;
	    }
	    tickets++;
	}	

	/* 
	 * if either of the chain or the ok_as_delegate was stripped
	 * by the kdc, make sure we strip it too.
	 */

	if (ok_as_delegate == 0 || ticket.flags.b.ok_as_delegate == 0) {
	    ok_as_delegate = 0;
	    ticket.flags.b.ok_as_delegate = 0;
	}

	ret = add_cred(context, &ticket, ret_tgts);
	if (ret)
	    goto out;

	/* try realm in the referral */
	ret = krb5_principal_set_realm(context,
				       referral.server,
				       referral_realm);
	krb5_free_cred_contents(context, &tgt);
	tgt = ticket;
	memset(&ticket, 0, sizeof(ticket));
	if (ret)
	    goto out;
    }

    ret = krb5_copy_creds(context, &ticket, out_creds);

out:
    krb5_free_principal(context, referral.server);
    krb5_free_cred_contents(context, &tgt);
    krb5_free_cred_contents(context, &ticket);
    return ret;
}
예제 #3
0
static krb5_error_code
tkt_referral_recv(krb5_context context,
		  krb5_tkt_creds_context ctx,
		  krb5_data *in,
		  krb5_data *out,
		  krb5_realm *realm,
		  unsigned int *flags)
{
    krb5_error_code ret;
    krb5_creds outcred, mcred;
    unsigned long n;

    _krb5_debugx(context, 10, "tkt_referral_recv: %s", ctx->server_name);
    
    memset(&outcred, 0, sizeof(outcred));

    ret = parse_tgs_rep(context, ctx, in, &outcred);
    if (ret) {
	_krb5_debugx(context, 10, "tkt_referral_recv: parse_tgs_rep %d", ret);
	tkt_reset(context, ctx);
	ctx->state = tkt_capath_init;
	return 0;
    }
    
    /*
     * Check if we found the right ticket
     */
    
    if (krb5_principal_compare_any_realm(context, ctx->next.server, outcred.server)) {
	ret = krb5_copy_creds(context, &outcred, &ctx->cred);
	if (ret)
	    return (ctx->error = ret);
	krb5_free_cred_contents(context, &outcred);
	ctx->state = tkt_store;
	return 0;
    }

    if (!krb5_principal_is_krbtgt(context, outcred.server)) {
	krb5_set_error_message(context, KRB5KRB_AP_ERR_NOT_US,
			       N_("Got back an non krbtgt "
				      "ticket referrals", ""));
	krb5_free_cred_contents(context, &outcred);
	ctx->state = tkt_capath_init;
	return 0;
    }
    
    _krb5_debugx(context, 10, "KDC for realm %s sends a referrals to %s",
		ctx->tgt.server->realm, outcred.server->name.name_string.val[1]);

    /*
     * check if there is a loop
     */
    krb5_cc_clear_mcred(&mcred);
    mcred.server = outcred.server;

    for (n = 0; ctx->tickets && ctx->tickets[n]; n++) {
	if(krb5_compare_creds(context,
			      KRB5_TC_DONT_MATCH_REALM,
			      &mcred,
			      ctx->tickets[n]))
	{
	    _krb5_debugx(context, 5, "Referral from %s loops back to realm %s",
				    ctx->tgt.server->realm,
				    outcred.server->realm);
	    ctx->state = tkt_capath_init;
	    return 0;
	}
    }
#define MAX_KDC_REFERRALS_LOOPS 15
    if (n > MAX_KDC_REFERRALS_LOOPS) {
	ctx->state = tkt_capath_init;
	return 0;
    }

    /*
     * filter out ok-as-delegate if needed
     */
    
    if (ctx->ok_as_delegate == 0 || outcred.flags.b.ok_as_delegate == 0) {
	ctx->ok_as_delegate = 0;
	outcred.flags.b.ok_as_delegate = 0;
    }

    /* add to iteration cache */
    ret = add_cred(context, &outcred, &ctx->tickets);
    if (ret) {
	ctx->state = tkt_capath_init;
	return 0;
    }

    /* set up next server to talk to */
    krb5_free_cred_contents(context, &ctx->tgt);
    ctx->tgt = outcred;
    
    /*
     * Setup next target principal to target
     */

    ret = krb5_principal_set_realm(context, ctx->next.server,
				   ctx->tgt.server->realm);
    if (ret) {
	ctx->state = tkt_capath_init;
	return 0;
    }
    
    ctx->state = tkt_referral_send;
    
    return 0;
}
예제 #4
0
파일: ticket.c 프로젝트: 2asoft/freebsd
static krb5_error_code
check_server_referral(krb5_context context,
		      krb5_kdc_rep *rep,
		      unsigned flags,
		      krb5_const_principal requested,
		      krb5_const_principal returned,
		      krb5_keyblock * key)
{
    krb5_error_code ret;
    PA_ServerReferralData ref;
    krb5_crypto session;
    EncryptedData ed;
    size_t len;
    krb5_data data;
    PA_DATA *pa;
    int i = 0, cmp;

    if (rep->kdc_rep.padata == NULL)
	goto noreferral;

    pa = krb5_find_padata(rep->kdc_rep.padata->val,
			  rep->kdc_rep.padata->len,
			  KRB5_PADATA_SERVER_REFERRAL, &i);
    if (pa == NULL)
	goto noreferral;

    memset(&ed, 0, sizeof(ed));
    memset(&ref, 0, sizeof(ref));

    ret = decode_EncryptedData(pa->padata_value.data,
			       pa->padata_value.length,
			       &ed, &len);
    if (ret)
	return ret;
    if (len != pa->padata_value.length) {
	free_EncryptedData(&ed);
	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
			       N_("Referral EncryptedData wrong for realm %s",
				  "realm"), requested->realm);
	return KRB5KRB_AP_ERR_MODIFIED;
    }

    ret = krb5_crypto_init(context, key, 0, &session);
    if (ret) {
	free_EncryptedData(&ed);
	return ret;
    }

    ret = krb5_decrypt_EncryptedData(context, session,
				     KRB5_KU_PA_SERVER_REFERRAL,
				     &ed, &data);
    free_EncryptedData(&ed);
    krb5_crypto_destroy(context, session);
    if (ret)
	return ret;

    ret = decode_PA_ServerReferralData(data.data, data.length, &ref, &len);
    if (ret) {
	krb5_data_free(&data);
	return ret;
    }
    krb5_data_free(&data);

    if (strcmp(requested->realm, returned->realm) != 0) {
	free_PA_ServerReferralData(&ref);
	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
			       N_("server ref realm mismatch, "
				  "requested realm %s got back %s", ""),
			       requested->realm, returned->realm);
	return KRB5KRB_AP_ERR_MODIFIED;
    }

    if (krb5_principal_is_krbtgt(context, returned)) {
	const char *realm = returned->name.name_string.val[1];

	if (ref.referred_realm == NULL
	    || strcmp(*ref.referred_realm, realm) != 0)
	{
	    free_PA_ServerReferralData(&ref);
	    krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
				   N_("tgt returned with wrong ref", ""));
	    return KRB5KRB_AP_ERR_MODIFIED;
	}
    } else if (krb5_principal_compare(context, returned, requested) == 0) {
	free_PA_ServerReferralData(&ref);
	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
			       N_("req princ no same as returned", ""));
	return KRB5KRB_AP_ERR_MODIFIED;
    }

    if (ref.requested_principal_name) {
	cmp = _krb5_principal_compare_PrincipalName(context,
						    requested,
						    ref.requested_principal_name);
	if (!cmp) {
	    free_PA_ServerReferralData(&ref);
	    krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
				   N_("referred principal not same "
				      "as requested", ""));
	    return KRB5KRB_AP_ERR_MODIFIED;
	}
    } else if (flags & EXTRACT_TICKET_AS_REQ) {
	free_PA_ServerReferralData(&ref);
	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
			       N_("Requested principal missing on AS-REQ", ""));
	return KRB5KRB_AP_ERR_MODIFIED;
    }

    free_PA_ServerReferralData(&ref);

    return ret;
noreferral:
    /*
     * Expect excact match or that we got a krbtgt
     */
    if (krb5_principal_compare(context, requested, returned) != TRUE &&
	(krb5_realm_compare(context, requested, returned) != TRUE &&
	 krb5_principal_is_krbtgt(context, returned) != TRUE))
    {
	krb5_set_error_message(context, KRB5KRB_AP_ERR_MODIFIED,
			       N_("Not same server principal returned "
				  "as requested", ""));
	return KRB5KRB_AP_ERR_MODIFIED;
    }
    return 0;
}