コード例 #1
0
ファイル: keytab.c プロジェクト: InvLim/heimdal
static krb5_error_code
krb5_kt_get_entry_wrapped(krb5_context context,
			  krb5_keytab id,
			  krb5_const_principal principal,
			  krb5_kvno kvno,
			  krb5_enctype enctype,
			  krb5_keytab_entry *entry)
{
    krb5_keytab_entry tmp;
    krb5_error_code ret;
    krb5_kt_cursor cursor;

    if(id->get)
	return (*id->get)(context, id, principal, kvno, enctype, entry);

    ret = krb5_kt_start_seq_get (context, id, &cursor);
    if (ret) {
	/* This is needed for krb5_verify_init_creds, but keep error
	 * string from previous error for the human. */
	context->error_code = KRB5_KT_NOTFOUND;
	return KRB5_KT_NOTFOUND;
    }

    entry->vno = 0;
    while (krb5_kt_next_entry(context, id, &tmp, &cursor) == 0) {
	if (krb5_kt_compare(context, &tmp, principal, 0, enctype)) {
	    /* the file keytab might only store the lower 8 bits of
	       the kvno, so only compare those bits */
	    if (kvno == tmp.vno
		|| (tmp.vno < 256 && kvno % 256 == tmp.vno)) {
		krb5_kt_copy_entry_contents (context, &tmp, entry);
		krb5_kt_free_entry (context, &tmp);
		krb5_kt_end_seq_get(context, id, &cursor);
		return 0;
	    } else if (kvno == 0 && tmp.vno > entry->vno) {
		if (entry->vno)
		    krb5_kt_free_entry (context, entry);
		krb5_kt_copy_entry_contents (context, &tmp, entry);
	    }
	}
	krb5_kt_free_entry(context, &tmp);
    }
    krb5_kt_end_seq_get (context, id, &cursor);
    if (entry->vno == 0)
	return _krb5_kt_principal_not_found(context, KRB5_KT_NOTFOUND,
					    id, principal, enctype, kvno);
    return 0;
}
コード例 #2
0
ファイル: rd_req.c プロジェクト: aosm/Heimdal
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_rd_req_ctx(krb5_context context,
		krb5_auth_context *auth_context,
		const krb5_data *inbuf,
		krb5_const_principal server,
		krb5_rd_req_in_ctx inctx,
		krb5_rd_req_out_ctx *outctx)
{
    krb5_error_code ret;
    krb5_ap_req ap_req;
    krb5_rd_req_out_ctx o = NULL;
    krb5_keytab id = NULL, keytab = NULL;
    krb5_principal service = NULL;

    *outctx = NULL;

    o = calloc(1, sizeof(*o));
    if (o == NULL) {
	krb5_set_error_message(context, ENOMEM,
			       N_("malloc: out of memory", ""));
	return ENOMEM;
    }

    if (*auth_context == NULL) {
	ret = krb5_auth_con_init(context, auth_context);
	if (ret)
	    goto out;
    }

    ret = krb5_decode_ap_req(context, inbuf, &ap_req);
    if(ret)
	goto out;

    /* Save that principal that was in the request */
    ret = _krb5_principalname2krb5_principal(context,
					     &o->server,
					     ap_req.ticket.sname,
					     ap_req.ticket.realm);
    if (ret)
	goto out;

    if (ap_req.ap_options.use_session_key &&
	(*auth_context)->keyblock == NULL) {
	ret = KRB5KRB_AP_ERR_NOKEY;
	krb5_set_error_message(context, ret,
			       N_("krb5_rd_req: user to user auth "
				  "without session key given", ""));
	goto out;
    }

    if (inctx && inctx->keytab)
	id = inctx->keytab;

    if((*auth_context)->keyblock){
	ret = krb5_copy_keyblock(context,
				 (*auth_context)->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else if(inctx && inctx->keyblock){
	ret = krb5_copy_keyblock(context,
				 inctx->keyblock,
				 &o->keyblock);
	if (ret)
	    goto out;
    } else {

	if(id == NULL) {
	    krb5_kt_default(context, &keytab);
	    id = keytab;
	}
	if (id == NULL)
	    goto out;

	if (server == NULL) {
	    ret = _krb5_principalname2krb5_principal(context,
						     &service,
						     ap_req.ticket.sname,
						     ap_req.ticket.realm);
	    if (ret)
		goto out;
	    server = service;
	}

	ret = get_key_from_keytab(context,
				  &ap_req,
				  server,
				  id,
				  &o->keyblock);
	if (ret) {
	    /* If caller specified a server, fail. */
	    if (service == NULL && (context->flags & KRB5_CTX_F_RD_REQ_IGNORE) == 0)
		goto out;
	    /* Otherwise, fall back to iterating over the keytab. This
	     * have serious performace issues for larger keytab.
	     */
	    o->keyblock = NULL;
	}
    }

    if (o->keyblock) {
	/*
	 * We got an exact keymatch, use that.
	 */

	ret = krb5_verify_ap_req2(context,
				  auth_context,
				  &ap_req,
				  server,
				  o->keyblock,
				  0,
				  &o->ap_req_options,
				  &o->ticket,
				  KRB5_KU_AP_REQ_AUTH);

	if (ret)
	    goto out;

    } else {
	/*
	 * Interate over keytab to find a key that can decrypt the request.
	 */

	krb5_keytab_entry entry;
	krb5_kt_cursor cursor;
	int done = 0, kvno = 0;

	memset(&cursor, 0, sizeof(cursor));

	if (ap_req.ticket.enc_part.kvno)
	    kvno = *ap_req.ticket.enc_part.kvno;

	ret = krb5_kt_start_seq_get(context, id, &cursor);
	if (ret)
	    goto out;

	done = 0;
	while (!done) {
	    krb5_principal p;

	    ret = krb5_kt_next_entry(context, id, &entry, &cursor);
	    if (ret) {
		_krb5_kt_principal_not_found(context, ret, id, o->server,
					     ap_req.ticket.enc_part.etype,
					     kvno);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    if (entry.keyblock.keytype != ap_req.ticket.enc_part.etype) {
		krb5_kt_free_entry (context, &entry);
		continue;
	    }

	    ret = krb5_verify_ap_req2(context,
				      auth_context,
				      &ap_req,
				      server,
				      &entry.keyblock,
				      0,
				      &o->ap_req_options,
				      &o->ticket,
				      KRB5_KU_AP_REQ_AUTH);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		continue;
	    }

	    /*
	     * Found a match, save the keyblock for PAC processing,
	     * and update the service principal in the ticket to match
	     * whatever is in the keytab.
	     */

	    ret = krb5_copy_keyblock(context,
				     &entry.keyblock,
				     &o->keyblock);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }

	    ret = krb5_copy_principal(context, entry.principal, &p);
	    if (ret) {
		krb5_kt_free_entry(context, &entry);
		krb5_kt_end_seq_get(context, id, &cursor);
		goto out;
	    }
	    krb5_free_principal(context, o->ticket->server);
	    o->ticket->server = p;
	    
	    krb5_kt_free_entry(context, &entry);

	    done = 1;
	}
	krb5_kt_end_seq_get(context, id, &cursor);
    }

    /* If there is a PAC, verify its server signature */
    if (inctx == NULL || inctx->check_pac) {
	krb5_pac pac;
	krb5_data data;

	ret = krb5_ticket_get_authorization_data_type(context,
						      o->ticket,
						      KRB5_AUTHDATA_WIN2K_PAC,
						      &data);
	if (ret == 0) {
	    ret = krb5_pac_parse(context, data.data, data.length, &pac);
	    krb5_data_free(&data);
	    if (ret)
		goto out;

	    ret = krb5_pac_verify(context,
				  pac,
				  o->ticket->ticket.authtime,
				  o->ticket->client,
				  o->keyblock,
				  NULL);
	    krb5_pac_free(context, pac);
	    if (ret == 0)
		o->flags |= KRB5_RD_REQ_OUT_PAC_VALID;
	    ret = 0;
	} else
	    ret = 0;
    }
 out:

    if (ret || outctx == NULL) {
	krb5_rd_req_out_ctx_free(context, o);
    } else
	*outctx = o;

    free_AP_REQ(&ap_req);

    if (service)
	krb5_free_principal(context, service);

    if (keytab)
	krb5_kt_close(context, keytab);

    return ret;
}