Exemplo n.º 1
0
static int
set_ptypes(krb5_context context,
	   KRB_ERROR *error, 
	   const krb5_preauthtype **ptypes,
	   krb5_preauthdata **preauth)
{
    static krb5_preauthdata preauth2;
    static krb5_preauthtype ptypes2[] = { KRB5_PADATA_ENC_TIMESTAMP, KRB5_PADATA_NONE };

    if(error->e_data) {
	METHOD_DATA md;
	int i;
	decode_METHOD_DATA(error->e_data->data, 
			   error->e_data->length, 
			   &md, 
			   NULL);
	for(i = 0; i < md.len; i++){
	    switch(md.val[i].padata_type){
	    case KRB5_PADATA_ENC_TIMESTAMP:
		*ptypes = ptypes2;
		break;
	    case KRB5_PADATA_ETYPE_INFO:
		*preauth = &preauth2;
		ALLOC_SEQ(*preauth, 1);
		(*preauth)->val[0].type = KRB5_PADATA_ENC_TIMESTAMP;
		krb5_decode_ETYPE_INFO(context,
				       md.val[i].padata_value.data, 
				       md.val[i].padata_value.length,
				       &(*preauth)->val[0].info,
				       NULL);
		break;
	    default:
		break;
	    }
	}
	free_METHOD_DATA(&md);
    } else {
	*ptypes = ptypes2;
    }
    return(1);
}
Exemplo n.º 2
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_init_creds_step(krb5_context context,
		     krb5_init_creds_context ctx,
		     krb5_data *in,
		     krb5_data *out,
		     krb5_krbhst_info *hostinfo,
		     unsigned int *flags)
{
    krb5_error_code ret;
    size_t len;
    size_t size;

    krb5_data_zero(out);

    if (ctx->as_req.req_body.cname == NULL) {
	ret = init_as_req(context, ctx->flags, &ctx->cred,
			  ctx->addrs, ctx->etypes, &ctx->as_req);
	if (ret) {
	    free_init_creds_ctx(context, ctx);
	    return ret;
	}
    }

#define MAX_PA_COUNTER 10
    if (ctx->pa_counter > MAX_PA_COUNTER) {
	krb5_set_error_message(context, KRB5_GET_IN_TKT_LOOP,
			       N_("Looping %d times while getting "
				  "initial credentials", ""),
			       ctx->pa_counter);
	return KRB5_GET_IN_TKT_LOOP;
    }
    ctx->pa_counter++;

    /* Lets process the input packet */
    if (in && in->length) {
	krb5_kdc_rep rep;

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

	ret = decode_AS_REP(in->data, in->length, &rep.kdc_rep, &size);
	if (ret == 0) {
	    krb5_keyblock *key = NULL;
	    unsigned eflags = EXTRACT_TICKET_AS_REQ;

	    if (ctx->flags.canonicalize) {
		eflags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;
		eflags |= EXTRACT_TICKET_MATCH_REALM;
	    }
	    if (ctx->ic_flags & KRB5_INIT_CREDS_NO_C_CANON_CHECK)
		eflags |= EXTRACT_TICKET_ALLOW_CNAME_MISMATCH;

	    ret = process_pa_data_to_key(context, ctx, &ctx->cred,
					 &ctx->as_req, &rep.kdc_rep, hostinfo, &key);
	    if (ret) {
		free_AS_REP(&rep.kdc_rep);
		goto out;
	    }

	    ret = _krb5_extract_ticket(context,
				       &rep,
				       &ctx->cred,
				       key,
				       NULL,
				       KRB5_KU_AS_REP_ENC_PART,
				       NULL,
				       ctx->nonce,
				       eflags,
				       NULL,
				       NULL);
	    krb5_free_keyblock(context, key);

	    *flags = 0;

	    if (ret == 0)
		ret = copy_EncKDCRepPart(&rep.enc_part, &ctx->enc_part);

	    free_AS_REP(&rep.kdc_rep);
	    free_EncASRepPart(&rep.enc_part);

	    return ret;

	} else {
	    /* let's try to parse it as a KRB-ERROR */

	    free_KRB_ERROR(&ctx->error);

	    ret = krb5_rd_error(context, in, &ctx->error);
	    if(ret && in->length && ((char*)in->data)[0] == 4)
		ret = KRB5KRB_AP_ERR_V4_REPLY;
	    if (ret)
		goto out;

	    ret = krb5_error_from_rd_error(context, &ctx->error, &ctx->cred);

	    /*
	     * If no preauth was set and KDC requires it, give it one
	     * more try.
	     */

	    if (ret == KRB5KDC_ERR_PREAUTH_REQUIRED) {

	        free_METHOD_DATA(&ctx->md);
	        memset(&ctx->md, 0, sizeof(ctx->md));

		if (ctx->error.e_data) {
		    ret = decode_METHOD_DATA(ctx->error.e_data->data,
					     ctx->error.e_data->length,
					     &ctx->md,
					     NULL);
		    if (ret)
			krb5_set_error_message(context, ret,
					       N_("Failed to decode METHOD-DATA", ""));
		} else {
		    krb5_set_error_message(context, ret,
					   N_("Preauth required but no preauth "
					      "options send by KDC", ""));
		}
	    } else if (ret == KRB5KRB_AP_ERR_SKEW && context->kdc_sec_offset == 0) {
		/* 
		 * Try adapt to timeskrew when we are using pre-auth, and
		 * if there was a time skew, try again.
		 */
		krb5_set_real_time(context, ctx->error.stime, -1);
		if (context->kdc_sec_offset)
		    ret = 0; 
	    } else if (ret == KRB5_KDC_ERR_WRONG_REALM && ctx->flags.canonicalize) {
	        /* client referal to a new realm */
		if (ctx->error.crealm == NULL) {
		    krb5_set_error_message(context, ret,
					   N_("Got a client referral, not but no realm", ""));
		    goto out;
		}
		ret = krb5_principal_set_realm(context, 
					       ctx->cred.client,
					       *ctx->error.crealm);
	    }
	    if (ret)
		goto out;
	}
    }

    if (ctx->as_req.padata) {
	free_METHOD_DATA(ctx->as_req.padata);
	free(ctx->as_req.padata);
	ctx->as_req.padata = NULL;
    }

    /* Set a new nonce. */
    ctx->as_req.req_body.nonce = ctx->nonce;

    /* fill_in_md_data */
    ret = process_pa_data_to_md(context, &ctx->cred, &ctx->as_req, ctx,
				&ctx->md, &ctx->as_req.padata,
				ctx->prompter, ctx->prompter_data);
    if (ret)
	goto out;

    krb5_data_free(&ctx->req_buffer);

    ASN1_MALLOC_ENCODE(AS_REQ,
		       ctx->req_buffer.data, ctx->req_buffer.length,
		       &ctx->as_req, &len, ret);
    if (ret)
	goto out;
    if(len != ctx->req_buffer.length)
	krb5_abortx(context, "internal error in ASN.1 encoder");

    out->data = ctx->req_buffer.data;
    out->length = ctx->req_buffer.length;

    *flags = 1;

    return 0;
 out:
    return ret;
}