Пример #1
0
static krb5_error_code
find_cred(krb5_context context,
	  krb5_ccache id,
	  krb5_principal server,
	  krb5_creds **tgts,
	  krb5_creds *out_creds)
{
    krb5_error_code ret;
    krb5_creds mcreds;

    krb5_cc_clear_mcred(&mcreds);
    mcreds.server = server;
    ret = krb5_cc_retrieve_cred(context, id, KRB5_TC_DONT_MATCH_REALM,
				&mcreds, out_creds);
    if(ret == 0)
	return 0;
    while(tgts && *tgts){
	if(krb5_compare_creds(context, KRB5_TC_DONT_MATCH_REALM,
			      &mcreds, *tgts)){
	    ret = krb5_copy_creds_contents(context, *tgts, out_creds);
	    return ret;
	}
	tgts++;
    }
    return not_found(context, server, KRB5_CC_NOTFOUND);
}
Пример #2
0
krb5_error_code
kcm_ccache_retrieve_cred_internal(krb5_context context,
			 	  kcm_ccache ccache,
			 	  krb5_flags whichfields,
			 	  const krb5_creds *mcreds,
			 	  krb5_creds **creds)
{
    krb5_boolean match;
    struct kcm_creds *c;
    krb5_error_code ret;

    memset(creds, 0, sizeof(*creds));

    ret = KRB5_CC_END;

    match = FALSE;
    for (c = ccache->creds; c != NULL; c = c->next) {
	match = krb5_compare_creds(context, whichfields, mcreds, &c->cred);
	if (match)
	    break;
    }

    if (match) {
	ret = 0;
	*creds = &c->cred;
    }

    return ret;
}
Пример #3
0
krb5_error_code
kcm_ccache_remove_cred_internal(krb5_context context,
				kcm_ccache ccache,
				krb5_flags whichfields,
				const krb5_creds *mcreds)
{
    krb5_error_code ret;
    struct kcm_creds **c;

    ret = KRB5_CC_NOTFOUND;

    for (c = &ccache->creds; *c != NULL; c = &(*c)->next) {
	if (krb5_compare_creds(context, whichfields, mcreds, &(*c)->cred)) {
	    struct kcm_creds *cred = *c;

	    *c = cred->next;
	    krb5_free_cred_contents(context, &cred->cred);
	    free(cred);
	    ret = 0;
	    if (*c == NULL)
		break;
	}
    }

    return ret;
}
Пример #4
0
static krb5_boolean
matchfunc(krb5_context context, void *ptr, const krb5_creds *creds)
{
    struct ctx *ctx = ptr;
    if (krb5_compare_creds(context, ctx->whichfields, &ctx->mcreds, creds))
	return TRUE;
    return FALSE;
}
Пример #5
0
static krb5_error_code
mcc_remove_cred(krb5_context context,
		 krb5_ccache id,
		 krb5_flags which,
		 krb5_creds *mcreds)
{
    krb5_mcache *m = MCACHE(id);
    struct link **q, *p;
    for(q = &m->creds, p = *q; p; p = *q) {
	if(krb5_compare_creds(context, which, mcreds, &p->cred)) {
	    *q = p->next;
	    krb5_free_cred_contents(context, &p->cred);
	    free(p);
	} else
	    q = &p->next;
    }
    return 0;
}
Пример #6
0
static int
is_primary_credential_p(krb5_context context,
			kcm_ccache ccache,
			krb5_creds *newcred)
{
    krb5_flags whichfields;

    if (ccache->client == NULL)
	return 0;

    if (newcred->client == NULL ||
	!krb5_principal_compare(context, ccache->client, newcred->client))
	return 0;

    /* XXX just checks whether it's the first credential in the cache */
    if (ccache->creds == NULL)
	return 0;

    whichfields = KRB5_TC_MATCH_KEYTYPE | KRB5_TC_MATCH_FLAGS_EXACT |
		  KRB5_TC_MATCH_TIMES_EXACT | KRB5_TC_MATCH_AUTHDATA |
		  KRB5_TC_MATCH_2ND_TKT | KRB5_TC_MATCH_IS_SKEY;

    return krb5_compare_creds(context, whichfields, newcred, &ccache->creds->cred);
}
Пример #7
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;
}
Пример #8
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;
}
Пример #9
0
static krb5_error_code KRB5_CALLCONV
scc_remove_cred(krb5_context context,
		 krb5_ccache id,
		 krb5_flags which,
		 krb5_creds *mcreds)
{
    krb5_scache *s = SCACHE(id);
    krb5_error_code ret;
    sqlite3_stmt *stmt;
    sqlite_uint64 credid = 0;
    const void *data = NULL;
    size_t len = 0;

    ret = make_database(context, s);
    if (ret)
	return ret;

    ret = prepare_stmt(context, s->db, &stmt,
		       "SELECT cred,oid FROM credentials "
		       "WHERE cid = ?");
    if (ret)
	return ret;

    sqlite3_bind_int(stmt, 1, s->cid);

    /* find credential... */
    while (1) {
	krb5_creds creds;

	ret = sqlite3_step(stmt);
	if (ret == SQLITE_DONE) {
	    ret = 0;
	    break;
	} else if (ret != SQLITE_ROW) {
	    ret = KRB5_CC_IO;
	    krb5_set_error_message(context, ret,
				   N_("scache Database failed: %s", ""),
				   sqlite3_errmsg(s->db));
	    break;
	}

	if (sqlite3_column_type(stmt, 0) != SQLITE_BLOB) {
	    ret = KRB5_CC_END;
	    krb5_set_error_message(context, ret,
				   N_("Credential of wrong type "
				      "for SCC:%s:%s", ""),
				   s->name, s->file);
	    break;
	}

	data = sqlite3_column_blob(stmt, 0);
	len = sqlite3_column_bytes(stmt, 0);

	ret = decode_creds(context, data, len, &creds);
	if (ret)
	    break;

	ret = krb5_compare_creds(context, which, mcreds, &creds);
	krb5_free_cred_contents(context, &creds);
	if (ret) {
	    credid = sqlite3_column_int64(stmt, 1);
	    ret = 0;
	    break;
	}
    }

    sqlite3_finalize(stmt);

    if (id) {
	ret = prepare_stmt(context, s->db, &stmt,
			   "DELETE FROM credentials WHERE oid=?");
	if (ret)
	    return ret;
	sqlite3_bind_int(stmt, 1, credid);

	do {
	    ret = sqlite3_step(stmt);
	} while (ret == SQLITE_ROW);
	sqlite3_finalize(stmt);
	if (ret != SQLITE_DONE) {
	    ret = KRB5_CC_IO;
	    krb5_set_error_message(context, ret,
				   N_("failed to delete scache credental", ""));
	} else
	    ret = 0;
    }

    return ret;
}