Example #1
0
void KRB5_LIB_FUNCTION
krb5_free_error_contents (krb5_context context,
			  krb5_error *error)
{
    free_KRB_ERROR(error);
    memset(error, 0, sizeof(*error));
}
Example #2
0
void KRB5_LIB_FUNCTION
_krb5_get_init_creds_opt_free_krb5_error(krb5_get_init_creds_opt *opt)
{
    if (opt->opt_private == NULL || opt->opt_private->error == NULL)
        return;
    free_KRB_ERROR(opt->opt_private->error);
    free(opt->opt_private->error);
    opt->opt_private->error = NULL;
}
Example #3
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_free_kdc_rep(krb5_context context, krb5_kdc_rep *rep)
{
    free_KDC_REP(&rep->kdc_rep);
    free_EncTGSRepPart(&rep->enc_part);
    free_KRB_ERROR(&rep->error);
    memset(rep, 0, sizeof(*rep));
    return 0;
}
Example #4
0
static void
free_init_creds_ctx(krb5_context context, krb5_init_creds_context ctx)
{
    if (ctx->etypes)
	free(ctx->etypes);
    if (ctx->pre_auth_types)
	free (ctx->pre_auth_types);
    if (ctx->in_tkt_service)
	free(ctx->in_tkt_service);
    if (ctx->keytab_data)
	free(ctx->keytab_data);
    krb5_data_free(&ctx->req_buffer);
    krb5_free_cred_contents(context, &ctx->cred);
    free_METHOD_DATA(&ctx->md);
    free_AS_REP(&ctx->as_rep);
    free_EncKDCRepPart(&ctx->enc_part);
    free_KRB_ERROR(&ctx->error);
    free_AS_REQ(&ctx->as_req);
    memset(ctx, 0, sizeof(*ctx));
}
Example #5
0
static krb5_error_code
process_reply (krb5_context context,
	       krb5_auth_context auth_context,
	       int is_stream,
	       int sock,
	       int *result_code,
	       krb5_data *result_code_string,
	       krb5_data *result_string,
	       const char *host)
{
    krb5_error_code ret;
    u_char reply[1024 * 3];
    ssize_t len;
    u_int16_t pkt_len, pkt_ver;
    krb5_data ap_rep_data;
    int save_errno;

    len = 0;
    if (is_stream) {
	while (len < sizeof(reply)) {
	    unsigned long size;

	    ret = recvfrom (sock, reply + len, sizeof(reply) - len, 
			    0, NULL, NULL);
	    if (ret < 0) {
		save_errno = errno;
		krb5_set_error_string(context, "recvfrom %s: %s",
				      host, strerror(save_errno));
		return save_errno;
	    } else if (ret == 0) {
		krb5_set_error_string(context, "recvfrom timeout %s", host);
		return 1;
	    }
	    len += ret;
	    if (len < 4)
		continue;
	    _krb5_get_int(reply, &size, 4);
	    if (size + 4 < len)
		continue;
	    memmove(reply, reply + 4, size);		
	    len = size;
	    break;
	}
	if (len == sizeof(reply)) {
	    krb5_set_error_string(context, "message too large from %s",
				  host);
	    return ENOMEM;
	}
    } else {
	ret = recvfrom (sock, reply, sizeof(reply), 0, NULL, NULL);
	if (ret < 0) {
	    save_errno = errno;
	    krb5_set_error_string(context, "recvfrom %s: %s",
				  host, strerror(save_errno));
	    return save_errno;
	}
	len = ret;
    }

    if (len < 6) {
	str2data (result_string, "server %s sent to too short message "
		  "(%ld bytes)", host, (long)len);
	*result_code = KRB5_KPASSWD_MALFORMED;
	return 0;
    }

    pkt_len = (reply[0] << 8) | (reply[1]);
    pkt_ver = (reply[2] << 8) | (reply[3]);

    if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
	KRB_ERROR error;
	size_t size;
	u_char *p;

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

	ret = decode_KRB_ERROR(reply, len, &error, &size);
	if (ret)
	    return ret;

	if (error.e_data->length < 2) {
	    str2data(result_string, "server %s sent too short "
		     "e_data to print anything usable", host);
	    free_KRB_ERROR(&error);
	    *result_code = KRB5_KPASSWD_MALFORMED;
	    return 0;
	}

	p = error.e_data->data;
	*result_code = (p[0] << 8) | p[1];
	if (error.e_data->length == 2)
	    str2data(result_string, "server only sent error code");
	else 
	    krb5_data_copy (result_string,
			    p + 2,
			    error.e_data->length - 2);
	free_KRB_ERROR(&error);
	return 0;
    }

    if (pkt_len != len) {
	str2data (result_string, "client: wrong len in reply");
	*result_code = KRB5_KPASSWD_MALFORMED;
	return 0;
    }
    if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
	str2data (result_string,
		  "client: wrong version number (%d)", pkt_ver);
	*result_code = KRB5_KPASSWD_MALFORMED;
	return 0;
    }

    ap_rep_data.data = reply + 6;
    ap_rep_data.length  = (reply[4] << 8) | (reply[5]);
  
    if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
	str2data (result_string, "client: wrong AP len in reply");
	*result_code = KRB5_KPASSWD_MALFORMED;
	return 0;
    }

    if (ap_rep_data.length) {
	krb5_ap_rep_enc_part *ap_rep;
	krb5_data priv_data;
	u_char *p;

	priv_data.data   = (u_char*)ap_rep_data.data + ap_rep_data.length;
	priv_data.length = len - ap_rep_data.length - 6;

	ret = krb5_rd_rep (context,
			   auth_context,
			   &ap_rep_data,
			   &ap_rep);
	if (ret)
	    return ret;

	krb5_free_ap_rep_enc_part (context, ap_rep);

	ret = krb5_rd_priv (context,
			    auth_context,
			    &priv_data,
			    result_code_string,
			    NULL);
	if (ret) {
	    krb5_data_free (result_code_string);
	    return ret;
	}

	if (result_code_string->length < 2) {
	    *result_code = KRB5_KPASSWD_MALFORMED;
	    str2data (result_string,
		      "client: bad length in result");
	    return 0;
	}

        p = result_code_string->data;
      
        *result_code = (p[0] << 8) | p[1];
        krb5_data_copy (result_string,
                        (unsigned char*)result_code_string->data + 2,
                        result_code_string->length - 2);
        return 0;
    } else {
	KRB_ERROR error;
	size_t size;
	u_char *p;
      
	ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
	if (ret) {
	    return ret;
	}
	if (error.e_data->length < 2) {
	    krb5_warnx (context, "too short e_data to print anything usable");
	    return 1;		/* XXX */
	}

	p = error.e_data->data;
	*result_code = (p[0] << 8) | p[1];
	krb5_data_copy (result_string,
			p + 2,
			error.e_data->length - 2);
	return 0;
    }
}
Example #6
0
static bool torture_krb5_post_recv_test(struct torture_krb5_context *test_context, const krb5_data *recv_buf)
{
	KRB_ERROR error;
	size_t used;
	switch (test_context->test)
	{
	case TORTURE_KRB5_TEST_PLAIN:
		if (test_context->packet_count == 0) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
			   && (test_context->packet_count == 1)) {
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else {
			torture_assert_int_equal(test_context->tctx,
						 decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx,
						 test_context->as_rep.pvno, 5,
						 "Got wrong as_rep->pvno");
			torture_assert_int_equal(test_context->tctx,
						 test_context->as_rep.ticket.tkt_vno, 5,
						 "Got wrong as_rep->ticket.tkt_vno");
			torture_assert(test_context->tctx,
				       test_context->as_rep.ticket.enc_part.kvno,
				       "Did not get a KVNO in test_context->as_rep.ticket.enc_part.kvno");
			if (torture_setting_bool(test_context->tctx, "expect_cached_at_rodc", false)) {
				torture_assert_int_not_equal(test_context->tctx,
							     *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
							     0, "Did not get a RODC number in the KVNO");
			} else {
				torture_assert_int_equal(test_context->tctx,
							 *test_context->as_rep.ticket.enc_part.kvno & 0xFFFF0000,
							 0, "Unexpecedly got a RODC number in the KVNO");
			}
			free_AS_REP(&test_context->as_rep);
		}
		torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
		free_AS_REQ(&test_context->as_req);
		break;

		/* 
		 * Confirm correct error codes when we ask for the PAC.  This behaviour is rather odd...
		 */
	case TORTURE_KRB5_TEST_PAC_REQUEST:
		if (test_context->packet_count == 0) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else if (test_context->packet_count == 1) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else if ((decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used) == 0)
			   && (test_context->packet_count == 2)) {
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_ERR_RESPONSE_TOO_BIG - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else {
			torture_assert_int_equal(test_context->tctx,
						 decode_AS_REP(recv_buf->data, recv_buf->length, &test_context->as_rep, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, test_context->as_rep.pvno, 5, "Got wrong as_rep->pvno");
			free_AS_REP(&test_context->as_rep);
		}
		torture_assert(test_context->tctx, test_context->packet_count < 3, "too many packets");
		free_AS_REQ(&test_context->as_req);
		break;

		/* 
		 * Confirm correct error codes when we deliberatly send the wrong password
		 */
	case TORTURE_KRB5_TEST_BREAK_PW:
		if (test_context->packet_count == 0) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else if (test_context->packet_count == 1) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_FAILED - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		}
		torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
		free_AS_REQ(&test_context->as_req);
		break;

		/* 
		 * Confirm correct error codes when we deliberatly skew the client clock
		 */
	case TORTURE_KRB5_TEST_CLOCK_SKEW:
		if (test_context->packet_count == 0) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KDC_ERR_PREAUTH_REQUIRED - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		} else if (test_context->packet_count == 1) {
			torture_assert_int_equal(test_context->tctx,
						 decode_KRB_ERROR(recv_buf->data, recv_buf->length, &error, &used), 0,
						 "decode_AS_REP failed");
			torture_assert_int_equal(test_context->tctx, used, recv_buf->length, "length mismatch");
			torture_assert_int_equal(test_context->tctx, error.pvno, 5, "Got wrong error.pvno");
			torture_assert_int_equal(test_context->tctx, error.error_code, KRB5KRB_AP_ERR_SKEW - KRB5KDC_ERR_NONE,
						 "Got wrong error.error_code");
			free_KRB_ERROR(&error);
		}
		torture_assert(test_context->tctx, test_context->packet_count < 2, "too many packets");
		free_AS_REQ(&test_context->as_req);
		break;
	}
	return true;
}
Example #7
0
static krb5_error_code
process_reply(krb5_context context,
              krb5_auth_context auth_context,
              krb5_data *data,
              int *result_code,
              krb5_data *result_code_string,
              krb5_data *result_string)
{
    krb5_error_code ret;
    ssize_t len;
    uint16_t pkt_len, pkt_ver;
    krb5_data ap_rep_data;
    uint8_t *reply;

    krb5_auth_con_clear(context, auth_context,
                        KRB5_AUTH_CONTEXT_CLEAR_LOCAL_ADDR|KRB5_AUTH_CONTEXT_CLEAR_REMOTE_ADDR);
    len = data->length;
    reply = data->data;;

    if (len < 6) {
        krb5_data_format(result_string, "server sent to too short message "
                         "(%ld bytes)", (long)len);
        *result_code = KRB5_KPASSWD_MALFORMED;
        return 0;
    }

    pkt_len = (reply[0] << 8) | (reply[1]);
    pkt_ver = (reply[2] << 8) | (reply[3]);

    if ((pkt_len != len) || (reply[1] == 0x7e || reply[1] == 0x5e)) {
        KRB_ERROR error;
        size_t size;
        u_char *p;

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

        ret = decode_KRB_ERROR(reply, len, &error, &size);
        if (ret)
            return ret;

        if (error.e_data->length < 2) {
            krb5_data_format(result_string, "server sent too short "
                             "e_data to print anything usable");
            free_KRB_ERROR(&error);
            *result_code = KRB5_KPASSWD_MALFORMED;
            return 0;
        }

        p = error.e_data->data;
        *result_code = (p[0] << 8) | p[1];
        if (error.e_data->length == 2)
            krb5_data_format(result_string, "server only sent error code");
        else
            krb5_data_copy (result_string,
                            p + 2,
                            error.e_data->length - 2);
        free_KRB_ERROR(&error);
        return 0;
    }

    if (pkt_len != len) {
        krb5_data_format(result_string, "client: wrong len in reply");
        *result_code = KRB5_KPASSWD_MALFORMED;
        return 0;
    }
    if (pkt_ver != KRB5_KPASSWD_VERS_CHANGEPW) {
        krb5_data_format(result_string,
                         "client: wrong version number (%d)", pkt_ver);
        *result_code = KRB5_KPASSWD_MALFORMED;
        return 0;
    }

    ap_rep_data.data = reply + 6;
    ap_rep_data.length  = (reply[4] << 8) | (reply[5]);

    if (reply + len < (u_char *)ap_rep_data.data + ap_rep_data.length) {
        krb5_data_format(result_string, "client: wrong AP len in reply");
        *result_code = KRB5_KPASSWD_MALFORMED;
        return 0;
    }

    if (ap_rep_data.length) {
        krb5_ap_rep_enc_part *ap_rep;
        krb5_data priv_data;
        u_char *p;

        priv_data.data   = (u_char*)ap_rep_data.data + ap_rep_data.length;
        priv_data.length = len - ap_rep_data.length - 6;

        ret = krb5_rd_rep (context,
                           auth_context,
                           &ap_rep_data,
                           &ap_rep);
        if (ret)
            return ret;

        krb5_free_ap_rep_enc_part (context, ap_rep);

        ret = krb5_rd_priv (context,
                            auth_context,
                            &priv_data,
                            result_code_string,
                            NULL);
        if (ret) {
            krb5_data_free (result_code_string);
            return ret;
        }

        if (result_code_string->length < 2) {
            *result_code = KRB5_KPASSWD_MALFORMED;
            krb5_data_format(result_string,
                             "client: bad length in result");
            return 0;
        }

        p = result_code_string->data;

        *result_code = (p[0] << 8) | p[1];
        krb5_data_copy (result_string,
                        (unsigned char*)result_code_string->data + 2,
                        result_code_string->length - 2);
        return 0;
    } else {
        KRB_ERROR error;
        size_t size;
        u_char *p;

        ret = decode_KRB_ERROR(reply + 6, len - 6, &error, &size);
        if (ret) {
            return ret;
        }
        if (error.e_data->length < 2) {
            krb5_warnx (context, "too short e_data to print anything usable");
            return 1;		/* XXX */
        }

        p = error.e_data->data;
        *result_code = (p[0] << 8) | p[1];
        krb5_data_copy (result_string,
                        p + 2,
                        error.e_data->length - 2);
        return 0;
    }
}
Example #8
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;
}
Example #9
0
krb5_error_code KRB5_LIB_FUNCTION
krb5_get_in_cred(krb5_context context,
		 krb5_flags options,
		 const krb5_addresses *addrs,
		 const krb5_enctype *etypes,
		 const krb5_preauthtype *ptypes,
		 const krb5_preauthdata *preauth,
		 krb5_key_proc key_proc,
		 krb5_const_pointer keyseed,
		 krb5_decrypt_proc decrypt_proc,
		 krb5_const_pointer decryptarg,
		 krb5_creds *creds,
		 krb5_kdc_rep *ret_as_reply)
{
    krb5_error_code ret;
    AS_REQ a;
    krb5_kdc_rep rep;
    krb5_data req, resp;
    size_t len;
    krb5_salt salt;
    krb5_keyblock *key;
    size_t size;
    KDCOptions opts;
    PA_DATA *pa;
    krb5_enctype etype;
    krb5_preauthdata *my_preauth = NULL;
    unsigned nonce;
    int done;

    opts = int2KDCOptions(options);

    krb5_generate_random_block (&nonce, sizeof(nonce));
    nonce &= 0xffffffff;

    do {
	done = 1;
	ret = init_as_req (context,
			   opts,
			   creds,
			   addrs,
			   etypes,
			   ptypes,
			   preauth,
			   key_proc,
			   keyseed,
			   nonce,
			   &a);
	if (my_preauth) {
	    free_ETYPE_INFO(&my_preauth->val[0].info);
	    free (my_preauth->val);
	    my_preauth = NULL;
	}
	if (ret)
	    return ret;

	ASN1_MALLOC_ENCODE(AS_REQ, req.data, req.length, &a, &len, ret);
	free_AS_REQ(&a);
	if (ret)
	    return ret;
	if(len != req.length)
	    krb5_abortx(context, "internal error in ASN.1 encoder");

	ret = krb5_sendto_kdc (context, &req, &creds->client->realm, &resp);
	krb5_data_free(&req);
	if (ret)
	    return ret;

	memset (&rep, 0, sizeof(rep));
	ret = decode_AS_REP(resp.data, resp.length, &rep.kdc_rep, &size);
	if(ret) {
	    /* let's try to parse it as a KRB-ERROR */
	    KRB_ERROR error;
	    int ret2;

	    ret2 = krb5_rd_error(context, &resp, &error);
	    if(ret2 && resp.data && ((char*)resp.data)[0] == 4)
		ret = KRB5KRB_AP_ERR_V4_REPLY;
	    krb5_data_free(&resp);
	    if (ret2 == 0) {
		ret = krb5_error_from_rd_error(context, &error, creds);
		/* if no preauth was set and KDC requires it, give it
                   one more try */
		if (!ptypes && !preauth
		    && ret == KRB5KDC_ERR_PREAUTH_REQUIRED
#if 0
			|| ret == KRB5KDC_ERR_BADOPTION
#endif
		    && set_ptypes(context, &error, &ptypes, &my_preauth)) {
		    done = 0;
		    preauth = my_preauth;
		    krb5_free_error_contents(context, &error);
		    krb5_clear_error_string(context);
		    continue;
		}
		if(ret_as_reply)
		    ret_as_reply->error = error;
		else
		    free_KRB_ERROR (&error);
		return ret;
	    }
	    return ret;
	}
	krb5_data_free(&resp);
    } while(!done);
    
    pa = NULL;
    etype = rep.kdc_rep.enc_part.etype;
    if(rep.kdc_rep.padata){
	int i = 0;
	pa = krb5_find_padata(rep.kdc_rep.padata->val, rep.kdc_rep.padata->len, 
			      KRB5_PADATA_PW_SALT, &i);
	if(pa == NULL) {
	    i = 0;
	    pa = krb5_find_padata(rep.kdc_rep.padata->val, 
				  rep.kdc_rep.padata->len, 
				  KRB5_PADATA_AFS3_SALT, &i);
	}
    }
    if(pa) {
	salt.salttype = pa->padata_type;
	salt.saltvalue = pa->padata_value;
	
	ret = (*key_proc)(context, etype, salt, keyseed, &key);
    } else {
	/* make a v5 salted pa-data */
	ret = krb5_get_pw_salt (context, creds->client, &salt);
	
	if (ret)
	    goto out;
	ret = (*key_proc)(context, etype, salt, keyseed, &key);
	krb5_free_salt(context, salt);
    }
    if (ret)
	goto out;
	
    {
	unsigned flags = 0;
	if (opts.request_anonymous)
	    flags |= EXTRACT_TICKET_ALLOW_SERVER_MISMATCH;

	ret = _krb5_extract_ticket(context, 
				   &rep, 
				   creds, 
				   key, 
				   keyseed, 
				   KRB5_KU_AS_REP_ENC_PART,
				   NULL, 
				   nonce, 
				   flags,
				   decrypt_proc, 
				   decryptarg);
    }
    memset (key->keyvalue.data, 0, key->keyvalue.length);
    krb5_free_keyblock_contents (context, key);
    free (key);

out:
    if (ret == 0 && ret_as_reply)
	*ret_as_reply = rep;
    else
	krb5_free_kdc_rep (context, &rep);
    return ret;
}