예제 #1
0
static OM_uint32
acceptor_wait_for_dcestyle(OM_uint32 * minor_status,
			   gsskrb5_ctx ctx,
			   krb5_context context,
			   const gss_cred_id_t acceptor_cred_handle,
			   const gss_buffer_t input_token_buffer,
			   const gss_channel_bindings_t input_chan_bindings,
			   gss_name_t * src_name,
			   gss_OID * mech_type,
			   gss_buffer_t output_token,
			   OM_uint32 * ret_flags,
			   OM_uint32 * time_rec,
			   gss_cred_id_t * delegated_cred_handle)
{
    OM_uint32 ret;
    krb5_error_code kret;
    krb5_data inbuf;
    int32_t r_seq_number, l_seq_number;

    /*
     * We know it's GSS_C_DCE_STYLE so we don't need to decapsulate the AP_REP
     */

    inbuf.length = input_token_buffer->length;
    inbuf.data = input_token_buffer->value;

    /*
     * We need to remeber the old remote seq_number, then check if the
     * client has replied with our local seq_number, and then reset
     * the remote seq_number to the old value
     */
    {
	kret = krb5_auth_con_getlocalseqnumber(context,
					       ctx->auth_context,
					       &l_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_auth_con_getremoteseqnumber(context,
						ctx->auth_context,
						&r_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_auth_con_setremoteseqnumber(context,
						ctx->auth_context,
						l_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
    }

    /*
     * We need to verify the AP_REP, but we need to flag that this is
     * DCE_STYLE, so don't check the timestamps this time, but put the
     * flag DO_TIME back afterward.
    */
    {
	krb5_ap_rep_enc_part *repl;
	int32_t auth_flags;

	krb5_auth_con_removeflags(context,
				  ctx->auth_context,
				  KRB5_AUTH_CONTEXT_DO_TIME,
				  &auth_flags);

	kret = krb5_rd_rep(context, ctx->auth_context, &inbuf, &repl);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
	krb5_free_ap_rep_enc_part(context, repl);
	krb5_auth_con_setflags(context, ctx->auth_context, auth_flags);
    }

    /* We need to check the liftime */
    {
	OM_uint32 lifetime_rec;

	ret = _gsskrb5_lifetime_left(minor_status,
				     context,
				     ctx->lifetime,
				     &lifetime_rec);
	if (ret) {
	    return ret;
	}
	if (lifetime_rec == 0) {
	    return GSS_S_CONTEXT_EXPIRED;
	}

	if (time_rec) *time_rec = lifetime_rec;
    }

    /* We need to give the caller the flags which are in use */
    if (ret_flags) *ret_flags = ctx->flags;

    if (src_name) {
	kret = krb5_copy_principal(context,
				   ctx->source,
				   (gsskrb5_name*)src_name);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
    }

    /*
     * After the krb5_rd_rep() the remote and local seq_number should
     * be the same, because the client just replies the seq_number
     * from our AP-REP in its AP-REP, but then the client uses the
     * seq_number from its AP-REQ for GSS_wrap()
     */
    {
	int32_t tmp_r_seq_number, tmp_l_seq_number;

	kret = krb5_auth_con_getremoteseqnumber(context,
						ctx->auth_context,
						&tmp_r_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_auth_con_getlocalseqnumber(context,
					       ctx->auth_context,
					       &tmp_l_seq_number);
	if (kret) {

	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	/*
	 * Here we check if the client has responsed with our local seq_number,
	 */
	if (tmp_r_seq_number != tmp_l_seq_number) {
	    return GSS_S_UNSEQ_TOKEN;
	}
    }

    /*
     * We need to reset the remote seq_number, because the client will use,
     * the old one for the GSS_wrap() calls
     */
    {
	kret = krb5_auth_con_setremoteseqnumber(context,
						ctx->auth_context,
						r_seq_number);
	if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}
    }

    return gsskrb5_acceptor_ready(minor_status, ctx, context,
				  delegated_cred_handle);
}
예제 #2
0
파일: rd_rep.c 프로젝트: gojdic/samba
krb5_error_code KRB5_LIB_FUNCTION
krb5_rd_rep(krb5_context context,
	    krb5_auth_context auth_context,
	    const krb5_data *inbuf,
	    krb5_ap_rep_enc_part **repl)
{
    krb5_error_code ret;
    AP_REP ap_rep;
    size_t len;
    krb5_data data;
    krb5_crypto crypto;

    krb5_data_zero (&data);
    ret = 0;

    ret = decode_AP_REP(inbuf->data, inbuf->length, &ap_rep, &len);
    if (ret)
	return ret;
    if (ap_rep.pvno != 5) {
	ret = KRB5KRB_AP_ERR_BADVERSION;
	krb5_clear_error_message (context);
	goto out;
    }
    if (ap_rep.msg_type != krb_ap_rep) {
	ret = KRB5KRB_AP_ERR_MSG_TYPE;
	krb5_clear_error_message (context);
	goto out;
    }

    ret = krb5_crypto_init(context, auth_context->keyblock, 0, &crypto);
    if (ret)
	goto out;
    ret = krb5_decrypt_EncryptedData (context,
				      crypto,	
				      KRB5_KU_AP_REQ_ENC_PART,
				      &ap_rep.enc_part,
				      &data);
    krb5_crypto_destroy(context, crypto);
    if (ret)
	goto out;

    *repl = malloc(sizeof(**repl));
    if (*repl == NULL) {
	ret = ENOMEM;
	krb5_set_error_message(context, ret, N_("malloc: out of memory", ""));
	goto out;
    }
    ret = krb5_decode_EncAPRepPart(context,
				   data.data,
				   data.length,
				   *repl,
				   &len);
    if (ret)
	return ret;

    if (auth_context->flags & KRB5_AUTH_CONTEXT_DO_TIME) {
	if ((*repl)->ctime != auth_context->authenticator->ctime ||
	    (*repl)->cusec != auth_context->authenticator->cusec)
	{
	    krb5_free_ap_rep_enc_part(context, *repl);
	    *repl = NULL;
	    ret = KRB5KRB_AP_ERR_MUT_FAIL;
	    krb5_clear_error_message (context);
	    goto out;
	}
    }
    if ((*repl)->seq_number)
	krb5_auth_con_setremoteseqnumber(context, auth_context,
					 *((*repl)->seq_number));
    if ((*repl)->subkey)
	krb5_auth_con_setremotesubkey(context, auth_context, (*repl)->subkey);

 out:
    krb5_data_free (&data);
    free_AP_REP (&ap_rep);
    return ret;
}
예제 #3
0
파일: rd_req.c 프로젝트: aosm/Heimdal
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_ap_req2(krb5_context context,
		    krb5_auth_context *auth_context,
		    krb5_ap_req *ap_req,
		    krb5_const_principal server,
		    krb5_keyblock *keyblock,
		    krb5_flags flags,
		    krb5_flags *ap_req_options,
		    krb5_ticket **ticket,
		    krb5_key_usage usage)
{
    krb5_ticket *t;
    krb5_auth_context ac;
    krb5_error_code ret;
    EtypeList etypes;

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

    if(ticket)
	*ticket = NULL;

    if (auth_context && *auth_context) {
	ac = *auth_context;
    } else {
	ret = krb5_auth_con_init(context, &ac);
	if (ret)
	    return ret;
    }

    t = calloc(1, sizeof(*t));
    if (t == NULL) {
	ret = ENOMEM;
	krb5_clear_error_message(context);
	goto out;
    }

    if (ap_req->ap_options.use_session_key && ac->keyblock){
	ret = krb5_decrypt_ticket(context, &ap_req->ticket,
				  ac->keyblock,
				  &t->ticket,
				  flags);
	krb5_free_keyblock(context, ac->keyblock);
	ac->keyblock = NULL;
    }else
	ret = krb5_decrypt_ticket(context, &ap_req->ticket,
				  keyblock,
				  &t->ticket,
				  flags);

    if(ret)
	goto out;

    ret = _krb5_principalname2krb5_principal(context,
					     &t->server,
					     ap_req->ticket.sname,
					     ap_req->ticket.realm);
    if (ret) goto out;
    ret = _krb5_principalname2krb5_principal(context,
					     &t->client,
					     t->ticket.cname,
					     t->ticket.crealm);
    if (ret) goto out;

    ret = decrypt_authenticator(context,
				&t->ticket.key,
				&ap_req->authenticator,
				ac->authenticator,
				usage);
    if (ret)
	goto out;

    {
	krb5_principal p1, p2;
	krb5_boolean res;

	_krb5_principalname2krb5_principal(context,
					   &p1,
					   ac->authenticator->cname,
					   ac->authenticator->crealm);
	_krb5_principalname2krb5_principal(context,
					   &p2,
					   t->ticket.cname,
					   t->ticket.crealm);
	res = krb5_principal_compare(context, p1, p2);
	krb5_free_principal(context, p1);
	krb5_free_principal(context, p2);
	if (!res) {
	    ret = KRB5KRB_AP_ERR_BADMATCH;
	    krb5_clear_error_message(context);
	    goto out;
	}
    }

    /* check addresses */

    if (t->ticket.caddr
	&& ac->remote_address
	&& !krb5_address_search(context,
				ac->remote_address,
				t->ticket.caddr)) {
	ret = KRB5KRB_AP_ERR_BADADDR;
	krb5_clear_error_message(context);
	goto out;
    }

    /* check timestamp in authenticator */
    {
	krb5_timestamp now;

	krb5_timeofday(context, &now);

	if (krb5_time_abs(ac->authenticator->ctime, now) > context->max_skew) {
	    ret = KRB5KRB_AP_ERR_SKEW;
	    krb5_clear_error_message(context);
	    goto out;
	}
    }

    if (ac->authenticator->seq_number)
	krb5_auth_con_setremoteseqnumber(context, ac,
					 *ac->authenticator->seq_number);

    /* XXX - Xor sequence numbers */

    if (ac->authenticator->subkey) {
	ret = krb5_auth_con_setremotesubkey(context, ac,
					    ac->authenticator->subkey);
	if (ret)
	    goto out;
    }

    ret = find_etypelist(context, ac, &etypes);
    if (ret)
	goto out;

    ac->keytype = (krb5_keytype)ETYPE_NULL;

    if (etypes.val) {
	size_t i;

	for (i = 0; i < etypes.len; i++) {
	    if (krb5_enctype_valid(context, etypes.val[i]) == 0) {
		ac->keytype = etypes.val[i];
		break;
	    }
	}
    }

    /* save key */
    ret = krb5_copy_keyblock(context, &t->ticket.key, &ac->keyblock);
    if (ret) goto out;

    if (ap_req_options) {
	*ap_req_options = 0;
	if (ac->keytype != ETYPE_NULL)
	    *ap_req_options |= AP_OPTS_USE_SUBKEY;
	if (ap_req->ap_options.use_session_key)
	    *ap_req_options |= AP_OPTS_USE_SESSION_KEY;
	if (ap_req->ap_options.mutual_required)
	    *ap_req_options |= AP_OPTS_MUTUAL_REQUIRED;
    }

    if(ticket)
	*ticket = t;
    else
	krb5_free_ticket(context, t);
    if (auth_context) {
	if (*auth_context == NULL)
	    *auth_context = ac;
    } else
	krb5_auth_con_free(context, ac);
    free_EtypeList(&etypes);
    return 0;
 out:
    free_EtypeList(&etypes);
    if (t)
	krb5_free_ticket(context, t);
    if (auth_context == NULL || *auth_context == NULL)
	krb5_auth_con_free(context, ac);
    return ret;
}