Example #1
0
OM_uint32
_gsskrb5_error_token(OM_uint32 *minor_status,
		     gss_OID mech,
		     krb5_context context,
		     krb5_error_code error_code,
		     krb5_data *e_data,
		     krb5_principal server,
		     gss_buffer_t output_token)
{
    krb5_error_code ret;
    krb5_data outbuf;

    ret = krb5_mk_error(context, error_code, NULL, e_data, NULL,
			server, NULL, NULL, &outbuf);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    ret = _gsskrb5_encapsulate(minor_status,
			       &outbuf,
			       output_token,
			       "\x03\x00",
			       mech);
    krb5_data_free (&outbuf);
    if (ret)
	return ret;

    *minor_status = 0;
    return GSS_S_COMPLETE;
}
Example #2
0
static OM_uint32
send_error_token(OM_uint32 *minor_status,
		 krb5_context context,
		 krb5_error_code kret,
		 krb5_principal server,
		 krb5_data *indata,
		 gss_buffer_t output_token)
{
    krb5_principal ap_req_server = NULL;
    krb5_error_code ret;
    krb5_data outbuf;
    /* this e_data value encodes KERB_AP_ERR_TYPE_SKEW_RECOVERY which
       tells windows to try again with the corrected timestamp. See
       [MS-KILE] 2.2.1 KERB-ERROR-DATA */
    krb5_data e_data = { 7, rk_UNCONST("\x30\x05\xa1\x03\x02\x01\x02") };

    /* build server from request if the acceptor had not selected one */
    if (server == NULL) {
	AP_REQ ap_req;

	ret = krb5_decode_ap_req(context, indata, &ap_req);
	if (ret) {
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	ret = _krb5_principalname2krb5_principal(context,
						  &ap_req_server,
						  ap_req.ticket.sname,
						  ap_req.ticket.realm);
	free_AP_REQ(&ap_req);
	if (ret) {
	    *minor_status = ret;
	    return GSS_S_FAILURE;
	}
	server = ap_req_server;
    }

    ret = krb5_mk_error(context, kret, NULL, &e_data, NULL,
			server, NULL, NULL, &outbuf);
    if (ap_req_server)
	krb5_free_principal(context, ap_req_server);
    if (ret) {
	*minor_status = ret;
	return GSS_S_FAILURE;
    }

    ret = _gsskrb5_encapsulate(minor_status,
			       &outbuf,
			       output_token,
			       "\x03\x00",
			       GSS_KRB5_MECHANISM);
    krb5_data_free (&outbuf);
    if (ret)
	return ret;

    *minor_status = 0;
    return GSS_S_CONTINUE_NEEDED;
}
Example #3
0
static OM_uint32
gsskrb5_acceptor_start(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)
{
    krb5_error_code kret;
    OM_uint32 ret = GSS_S_COMPLETE;
    krb5_data indata;
    krb5_flags ap_options;
    krb5_keytab keytab = NULL;
    int is_cfx = 0;
    const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;

    /*
     * We may, or may not, have an escapsulation.
     */
    ret = _gsskrb5_decapsulate (minor_status,
				input_token_buffer,
				&indata,
				"\x01\x00",
				GSS_KRB5_MECHANISM);

    if (ret) {
	/* Assume that there is no OID wrapping. */
	indata.length	= input_token_buffer->length;
	indata.data	= input_token_buffer->value;
    }

    /*
     * We need to get our keytab
     */
    if (acceptor_cred == NULL) {
	if (_gsskrb5_keytab != NULL)
	    keytab = _gsskrb5_keytab;
    } else if (acceptor_cred->keytab != NULL) {
	keytab = acceptor_cred->keytab;
    }

    /*
     * We need to check the ticket and create the AP-REP packet
     */

    {
	krb5_rd_req_in_ctx in = NULL;
	krb5_rd_req_out_ctx out = NULL;
	krb5_principal server = NULL;

	if (acceptor_cred)
	    server = acceptor_cred->principal;

	kret = krb5_rd_req_in_ctx_alloc(context, &in);
	if (kret == 0)
	    kret = krb5_rd_req_in_set_keytab(context, in, keytab);
	if (kret) {
	    if (in)
		krb5_rd_req_in_ctx_free(context, in);
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_rd_req_ctx(context,
			       &ctx->auth_context,
			       &indata,
			       server,
			       in, &out);
	krb5_rd_req_in_ctx_free(context, in);
	if (kret == KRB5KRB_AP_ERR_SKEW || kret == KRB5KRB_AP_ERR_TKT_NYV) {
	    /*
	     * No reply in non-MUTUAL mode, but we don't know that its
	     * non-MUTUAL mode yet, thats inside the 8003 checksum, so
	     * lets only send the error token on clock skew, that
	     * limit when send error token for non-MUTUAL.
	     */
	    return send_error_token(minor_status, context, kret,
				    server, &indata, output_token);
	} else if (kret) {
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	/*
	 * we need to remember some data on the context_handle.
	 */
	kret = krb5_rd_req_out_get_ap_req_options(context, out,
						  &ap_options);
	if (kret == 0)
	    kret = krb5_rd_req_out_get_ticket(context, out,
					      &ctx->ticket);
	if (kret == 0)
	    kret = krb5_rd_req_out_get_keyblock(context, out,
						&ctx->service_keyblock);
	ctx->lifetime = ctx->ticket->ticket.endtime;

	krb5_rd_req_out_ctx_free(context, out);
	if (kret) {
	    ret = GSS_S_FAILURE;
	    *minor_status = kret;
	    return ret;
	}
    }


    /*
     * We need to copy the principal names to the context and the
     * calling layer.
     */
    kret = krb5_copy_principal(context,
			       ctx->ticket->client,
			       &ctx->source);
    if (kret) {
	ret = GSS_S_FAILURE;
	*minor_status = kret;
    }

    kret = krb5_copy_principal(context,
			       ctx->ticket->server,
			       &ctx->target);
    if (kret) {
	ret = GSS_S_FAILURE;
	*minor_status = kret;
	return ret;
    }

    /*
     * We need to setup some compat stuff, this assumes that
     * context_handle->target is already set.
     */
    ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
    if (ret)
	return ret;

    if (src_name != NULL) {
	kret = krb5_copy_principal (context,
				    ctx->ticket->client,
				    (gsskrb5_name*)src_name);
	if (kret) {
	    ret = GSS_S_FAILURE;
	    *minor_status = kret;
	    return ret;
	}
    }

    /*
     * We need to get the flags out of the 8003 checksum.
     */

    {
	krb5_authenticator authenticator;

	kret = krb5_auth_con_getauthenticator(context,
					      ctx->auth_context,
					      &authenticator);
	if(kret) {
	    ret = GSS_S_FAILURE;
	    *minor_status = kret;
	    return ret;
	}

	if (authenticator->cksum == NULL) {
	    krb5_free_authenticator(context, &authenticator);
	    *minor_status = 0;
	    return GSS_S_BAD_BINDINGS;
	}

        if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
            ret = _gsskrb5_verify_8003_checksum(minor_status,
						input_chan_bindings,
						authenticator->cksum,
						&ctx->flags,
						&ctx->fwd_data);

	    krb5_free_authenticator(context, &authenticator);
	    if (ret) {
		return ret;
	    }
        } else {
	    krb5_crypto crypto;

	    kret = krb5_crypto_init(context,
				    ctx->auth_context->keyblock,
				    0, &crypto);
	    if(kret) {
		krb5_free_authenticator(context, &authenticator);

		ret = GSS_S_FAILURE;
		*minor_status = kret;
		return ret;
	    }

	    /*
	     * Windows accepts Samba3's use of a kerberos, rather than
	     * GSSAPI checksum here
	     */

	    kret = krb5_verify_checksum(context,
					crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
					authenticator->cksum);
	    krb5_free_authenticator(context, &authenticator);
	    krb5_crypto_destroy(context, crypto);

	    if(kret) {
		ret = GSS_S_BAD_SIG;
		*minor_status = kret;
		return ret;
	    }

	    /*
	     * Samba style get some flags (but not DCE-STYLE), use
	     * ap_options to guess the mutual flag.
	     */
 	    ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
	    if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
		ctx->flags |= GSS_C_MUTUAL_FLAG;
        }
    }

    if(ctx->flags & GSS_C_MUTUAL_FLAG) {
	krb5_data outbuf;
	int use_subkey = 0;

	_gsskrb5i_is_cfx(context, ctx, 1);
	is_cfx = (ctx->more_flags & IS_CFX);

	if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
	    use_subkey = 1;
	} else {
	    krb5_keyblock *rkey;

	    /*
	     * If there is a initiator subkey, copy that to acceptor
	     * subkey to match Windows behavior
	     */
	    kret = krb5_auth_con_getremotesubkey(context,
						 ctx->auth_context,
						 &rkey);
	    if (kret == 0) {
		kret = krb5_auth_con_setlocalsubkey(context,
						    ctx->auth_context,
						    rkey);
		if (kret == 0)
		    use_subkey = 1;
		krb5_free_keyblock(context, rkey);
	    }
	}
	if (use_subkey) {
	    ctx->more_flags |= ACCEPTOR_SUBKEY;
	    krb5_auth_con_addflags(context, ctx->auth_context,
				   KRB5_AUTH_CONTEXT_USE_SUBKEY,
				   NULL);
	}

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

	if (IS_DCE_STYLE(ctx)) {
	    output_token->length = outbuf.length;
	    output_token->value = outbuf.data;
	} else {
	    ret = _gsskrb5_encapsulate(minor_status,
				       &outbuf,
				       output_token,
				       "\x02\x00",
				       GSS_KRB5_MECHANISM);
	    krb5_data_free (&outbuf);
	    if (ret)
		return ret;
	}
    }

    ctx->flags |= GSS_C_TRANS_FLAG;

    /* Remember the flags */

    ctx->lifetime = ctx->ticket->ticket.endtime;
    ctx->more_flags |= OPEN;

    if (mech_type)
	*mech_type = GSS_KRB5_MECHANISM;

    if (time_rec) {
	ret = _gsskrb5_lifetime_left(minor_status,
				     context,
				     ctx->lifetime,
				     time_rec);
	if (ret) {
	    return ret;
	}
    }

    /*
     * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
     * the client.
     */
    if (IS_DCE_STYLE(ctx)) {
	/*
	 * Return flags to caller, but we haven't processed
	 * delgations yet
	 */
	if (ret_flags)
	    *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);

	ctx->state = ACCEPTOR_WAIT_FOR_DCESTYLE;
	return GSS_S_CONTINUE_NEEDED;
    }

    ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
				 delegated_cred_handle);

    if (ret_flags)
	*ret_flags = ctx->flags;

    return ret;
}
static OM_uint32
init_auth
(OM_uint32 * minor_status,
 gsskrb5_cred initiator_cred_handle,
 gsskrb5_ctx ctx,
 krb5_const_principal name,
 const gss_OID mech_type,
 OM_uint32 req_flags,
 OM_uint32 time_req,
 const gss_channel_bindings_t input_chan_bindings,
 const gss_buffer_t input_token,
 gss_OID * actual_mech_type,
 gss_buffer_t output_token,
 OM_uint32 * ret_flags,
 OM_uint32 * time_rec
    )
{
    OM_uint32 ret = GSS_S_FAILURE;
    krb5_error_code kret;
    krb5_flags ap_options;
    krb5_creds *cred = NULL;
    krb5_data outbuf;
    krb5_ccache ccache = NULL;
    uint32_t flags;
    krb5_data authenticator;
    Checksum cksum;
    krb5_enctype enctype;
    krb5_data fwd_data;
    OM_uint32 lifetime_rec;

    krb5_data_zero(&outbuf);
    krb5_data_zero(&fwd_data);

    *minor_status = 0;

    if (actual_mech_type)
	*actual_mech_type = GSS_KRB5_MECHANISM;

    if (initiator_cred_handle == NULL) {
	kret = krb5_cc_default (_gsskrb5_context, &ccache);
	if (kret) {
	    _gsskrb5_set_error_string ();
	    *minor_status = kret;
	    ret = GSS_S_FAILURE;
	    goto failure;
	}
    } else
	ccache = initiator_cred_handle->ccache;

    kret = krb5_cc_get_principal (_gsskrb5_context, ccache, &ctx->source);
    if (kret) {
	_gsskrb5_set_error_string ();
	*minor_status = kret;
	ret = GSS_S_FAILURE;
	goto failure;
    }

    kret = krb5_copy_principal (_gsskrb5_context, name, &ctx->target);
    if (kret) {
	_gsskrb5_set_error_string ();
	*minor_status = kret;
	ret = GSS_S_FAILURE;
	goto failure;
    }

    ret = _gss_DES3_get_mic_compat(minor_status, ctx);
    if (ret)
	goto failure;


    ret = gsskrb5_get_creds(minor_status,
			    ccache,
			    ctx,
			    ctx->target,
			    time_req,
			    time_rec,
			    &cred);
    if (ret)
	goto failure;

    ctx->lifetime = cred->times.endtime;

    ret = _gsskrb5_lifetime_left(minor_status,
			       ctx->lifetime,
			       &lifetime_rec);
    if (ret) {
	goto failure;
    }

    if (lifetime_rec == 0) {
	*minor_status = 0;
	ret = GSS_S_CONTEXT_EXPIRED;
	goto failure;
    }

    krb5_auth_con_setkey(_gsskrb5_context, 
			 ctx->auth_context, 
			 &cred->session);

    kret = krb5_auth_con_generatelocalsubkey(_gsskrb5_context, 
					     ctx->auth_context,
					     &cred->session);
    if(kret) {
	_gsskrb5_set_error_string ();
	*minor_status = kret;
	ret = GSS_S_FAILURE;
	goto failure;
    }
    
    /* 
     * If the credential doesn't have ok-as-delegate, check what local
     * policy say about ok-as-delegate, default is FALSE that makes
     * code ignore the KDC setting and follow what the application
     * requested. If its TRUE, strip of the GSS_C_DELEG_FLAG if the
     * KDC doesn't set ok-as-delegate.
     */
    if (!cred->flags.b.ok_as_delegate) {
	krb5_boolean delegate;
    
	krb5_appdefault_boolean(_gsskrb5_context,
				"gssapi", name->realm,
				"ok-as-delegate", FALSE, &delegate);
	if (delegate)
	    req_flags &= ~GSS_C_DELEG_FLAG;
    }

    flags = 0;
    ap_options = 0;
    if (req_flags & GSS_C_DELEG_FLAG)
	do_delegation (ctx->auth_context,
		       ccache, cred, name, &fwd_data, &flags);
    
    if (req_flags & GSS_C_MUTUAL_FLAG) {
	flags |= GSS_C_MUTUAL_FLAG;
	ap_options |= AP_OPTS_MUTUAL_REQUIRED;
    }
    
    if (req_flags & GSS_C_REPLAY_FLAG)
	flags |= GSS_C_REPLAY_FLAG;
    if (req_flags & GSS_C_SEQUENCE_FLAG)
	flags |= GSS_C_SEQUENCE_FLAG;
    if (req_flags & GSS_C_ANON_FLAG)
	;                               /* XXX */
    if (req_flags & GSS_C_DCE_STYLE) {
	/* GSS_C_DCE_STYLE implies GSS_C_MUTUAL_FLAG */
	flags |= GSS_C_DCE_STYLE | GSS_C_MUTUAL_FLAG;
	ap_options |= AP_OPTS_MUTUAL_REQUIRED;
    }
    if (req_flags & GSS_C_IDENTIFY_FLAG)
	flags |= GSS_C_IDENTIFY_FLAG;
    if (req_flags & GSS_C_EXTENDED_ERROR_FLAG)
	flags |= GSS_C_EXTENDED_ERROR_FLAG;

    flags |= GSS_C_CONF_FLAG;
    flags |= GSS_C_INTEG_FLAG;
    flags |= GSS_C_TRANS_FLAG;
    
    if (ret_flags)
	*ret_flags = flags;
    ctx->flags = flags;
    ctx->more_flags |= LOCAL;
    
    ret = _gsskrb5_create_8003_checksum (minor_status,
					 input_chan_bindings,
					 flags,
					 &fwd_data,
					 &cksum);
    krb5_data_free (&fwd_data);
    if (ret)
	goto failure;

    enctype = ctx->auth_context->keyblock->keytype;

    kret = krb5_build_authenticator (_gsskrb5_context,
				     ctx->auth_context,
				     enctype,
				     cred,
				     &cksum,
				     NULL,
				     &authenticator,
				     KRB5_KU_AP_REQ_AUTH);

    if (kret) {
	_gsskrb5_set_error_string ();
	*minor_status = kret;
	ret = GSS_S_FAILURE;
	goto failure;
    }

    kret = krb5_build_ap_req (_gsskrb5_context,
			      enctype,
			      cred,
			      ap_options,
			      authenticator,
			      &outbuf);

    if (kret) {
	_gsskrb5_set_error_string ();
	*minor_status = kret;
	ret = GSS_S_FAILURE;
	goto failure;
    }

    ret = _gsskrb5_encapsulate (minor_status, &outbuf, output_token,
				   (u_char *)"\x01\x00", GSS_KRB5_MECHANISM);
    if (ret)
	goto failure;

    krb5_data_free (&outbuf);
    krb5_free_creds(_gsskrb5_context, cred);
    free_Checksum(&cksum);
    if (initiator_cred_handle == NULL)
	krb5_cc_close(_gsskrb5_context, ccache);

    if (flags & GSS_C_MUTUAL_FLAG) {
	ctx->state = INITIATOR_WAIT_FOR_MUTAL;
	return GSS_S_CONTINUE_NEEDED;
    }

    return gsskrb5_initiator_ready(minor_status, ctx);
failure:
    if(cred)
	krb5_free_creds(_gsskrb5_context, cred);
    if (ccache && initiator_cred_handle == NULL)
	krb5_cc_close(_gsskrb5_context, ccache);

    return ret;

}
Example #5
0
static OM_uint32
gsskrb5_acceptor_start(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)
{
    krb5_error_code kret;
    OM_uint32 ret = GSS_S_COMPLETE;
    krb5_data indata;
    krb5_flags ap_options;
    krb5_keytab keytab = NULL;
    int is_cfx = 0;
    const gsskrb5_cred acceptor_cred = (gsskrb5_cred)acceptor_cred_handle;
    krb5_boolean is_hostbased_service = FALSE;

    /*
     * We may, or may not, have an escapsulation.
     */
    ret = _gsskrb5_decapsulate (minor_status,
				input_token_buffer,
				&indata,
				"\x01\x00",
				ctx->mech);

    if (ret) {
	/* Assume that there is no OID wrapping. */
	indata.length	= input_token_buffer->length;
	indata.data	= input_token_buffer->value;
    }

    /*
     * We need to get our keytab
     */
    if (acceptor_cred == NULL) {
	if (_gsskrb5_keytab != NULL)
	    keytab = _gsskrb5_keytab;
    } else if (acceptor_cred->keytab != NULL) {
	keytab = acceptor_cred->keytab;
    }

    is_hostbased_service = 
	(acceptor_cred &&
	 acceptor_cred->principal &&
	 krb5_principal_is_gss_hostbased_service(context, acceptor_cred->principal));

    /*
     * We need to check the ticket and create the AP-REP packet
     */

    {
	krb5_rd_req_in_ctx in = NULL;
	krb5_rd_req_out_ctx out = NULL;
	krb5_principal server = NULL;

	if (acceptor_cred && !is_hostbased_service)
	    server = acceptor_cred->principal;

	kret = krb5_rd_req_in_ctx_alloc(context, &in);
	if (kret == 0)
	    kret = krb5_rd_req_in_set_keytab(context, in, keytab);
	if (kret) {
	    if (in)
		krb5_rd_req_in_ctx_free(context, in);
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	kret = krb5_rd_req_ctx(context,
			       &ctx->auth_context,
			       &indata,
			       server,
			       in, &out);
	krb5_rd_req_in_ctx_free(context, in);
	if (ret && _gss_mg_log_level(5)) {
	    const char *e = krb5_get_error_message(context, ret);
	    char *s = NULL;
	    if (server)
		(void)krb5_unparse_name(context, server, &s);
	    _gss_mg_log(5, "gss-asc: rd_req (server: %s) failed with: %d: %s",
			s ? s : "<not specified>",
			ret, e);
	    krb5_free_error_message(context, e);
	    if (s)
		krb5_xfree(s);
	}


	switch (kret) {
	case 0:
	    break;
	case KRB5KRB_AP_ERR_SKEW:
	case KRB5KRB_AP_ERR_TKT_NYV:
	    /*
	     * No reply in non-MUTUAL mode, but we don't know that its
	     * non-MUTUAL mode yet, thats inside the 8003 checksum, so
	     * lets only send the error token on clock skew, that
	     * limit when send error token for non-MUTUAL.
	     */
	    return send_error_token(minor_status, context, kret,
				    server, &indata, ctx->mech, output_token);
	case KRB5KRB_AP_ERR_MODIFIED:
	case KRB5_KT_NOTFOUND:
	case KRB5_KT_END:
	    /*
	     * If the error is on the keytab entry missing or bad
	     * decryption, lets assume that the keytab version was
	     * wrong and tell the client that.
	     */
	    return send_error_token(minor_status, context, KRB5KRB_AP_ERR_MODIFIED,
				    server, NULL, ctx->mech, output_token);
	default:
	    *minor_status = kret;
	    return GSS_S_FAILURE;
	}

	/*
	 * we need to remember some data on the context_handle.
	 */
	kret = krb5_rd_req_out_get_ap_req_options(context, out,
						  &ap_options);
	if (kret == 0)
	    kret = krb5_rd_req_out_get_ticket(context, out,
					      &ctx->ticket);
	if (kret == 0)
	    kret = krb5_rd_req_out_get_keyblock(context, out,
						&ctx->service_keyblock);
	if (kret == 0) {
	    int flags;
	    flags = krb5_rd_req_out_get_flags(context, out);
	    if (flags & KRB5_RD_REQ_OUT_PAC_VALID)
		ctx->more_flags |= PAC_VALID;
	}
	if (kret == 0 && is_hostbased_service) {
	    krb5_principal sp = ctx->ticket->server;

	    if (sp->name.name_string.len < 1 ||
		strcmp(sp->name.name_string.val[0], acceptor_cred->principal->name.name_string.val[0]) != 0)
	    {
		kret = KRB5KRB_AP_WRONG_PRINC;
		krb5_set_error_message(context, ret, "Expecting service %s but got %s",
				       acceptor_cred->principal->name.name_string.val[0],
				       sp->name.name_string.val[0]);
	    }
	}

	ctx->endtime = ctx->ticket->ticket.endtime;

	krb5_rd_req_out_ctx_free(context, out);
	if (kret) {
	    ret = GSS_S_FAILURE;
	    *minor_status = kret;
	    return ret;
	}
    }


    /*
     * We need to copy the principal names to the context and the
     * calling layer.
     */
    kret = krb5_copy_principal(context,
			       ctx->ticket->client,
			       &ctx->source);
    if (kret) {
	*minor_status = kret;
	return GSS_S_FAILURE;
    }

    kret = krb5_copy_principal(context,
			       ctx->ticket->server,
			       &ctx->target);
    if (kret) {
	ret = GSS_S_FAILURE;
	*minor_status = kret;
	return ret;
    }

    /*
     * We need to setup some compat stuff, this assumes that
     * context_handle->target is already set.
     */
    ret = _gss_DES3_get_mic_compat(minor_status, ctx, context);
    if (ret)
	return ret;

    if (src_name != NULL) {
	kret = krb5_copy_principal (context,
				    ctx->ticket->client,
				    (gsskrb5_name*)src_name);
	if (kret) {
	    ret = GSS_S_FAILURE;
	    *minor_status = kret;
	    return ret;
	}
    }

    /*
     * We need to get the flags out of the 8003 checksum.
     */

    {
	krb5_authenticator authenticator;

	kret = krb5_auth_con_getauthenticator(context,
					      ctx->auth_context,
					      &authenticator);
	if(kret) {
	    ret = GSS_S_FAILURE;
	    *minor_status = kret;
	    return ret;
	}

	if (authenticator->cksum == NULL) {
	    krb5_free_authenticator(context, &authenticator);
	    *minor_status = 0;
	    return GSS_S_BAD_BINDINGS;
	}

        if (authenticator->cksum->cksumtype == CKSUMTYPE_GSSAPI) {
	    krb5_data finished_data;
	    krb5_crypto crypto = NULL;

	    if (ctx->auth_context->remote_subkey) {
		kret = krb5_crypto_init(context,
					ctx->auth_context->remote_subkey,
					0, &crypto);
		if (kret) {
		    *minor_status = kret;
		    return GSS_S_FAILURE;
		}
	    }

	    krb5_data_zero(&finished_data);

            ret = _gsskrb5_verify_8003_checksum(minor_status,
						context,
						crypto,
						input_chan_bindings,
						authenticator->cksum,
						&ctx->flags,
						&ctx->fwd_data,
						&finished_data);

	    krb5_free_authenticator(context, &authenticator);
	    if (ret) {
		krb5_crypto_destroy(context, crypto);
		return ret;
	    }

	    if (finished_data.length) {
		GSS_KRB5_FINISHED finished;
		krb5_data pkt;

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

		if (ctx->messages == NULL) {
		    krb5_crypto_destroy(context, crypto);
		    krb5_data_free(&finished_data);
		    *minor_status = 0;
		    return GSS_S_BAD_SIG;
		}

		kret = krb5_storage_to_data(ctx->messages, &pkt);
		if (kret) {
		    krb5_crypto_destroy(context, crypto);
		    krb5_data_free(&finished_data);
		    *minor_status = kret;
		    return GSS_S_FAILURE;
		}

		if (ctx->auth_context->remote_subkey == NULL) {
		    krb5_crypto_destroy(context, crypto);
		    krb5_data_free(&finished_data);
		    krb5_data_free(&pkt);
		    *minor_status = 0;
		    return GSS_S_BAD_SIG;
		}

		kret = decode_GSS_KRB5_FINISHED(finished_data.data,
						finished_data.length,
						&finished, NULL);
		krb5_data_free(&finished_data);
		if (kret) {
		    krb5_crypto_destroy(context, crypto);
		    krb5_data_free(&pkt);
		    *minor_status = kret;
		    return GSS_S_FAILURE;
		}

		kret = krb5_verify_checksum(context, crypto,
					    KRB5_KU_FINISHED,
					    pkt.data, pkt.length,
					    &finished.gss_mic);
		free_GSS_KRB5_FINISHED(&finished);
		krb5_data_free(&pkt);
		if (kret) {
		    krb5_crypto_destroy(context, crypto);
		    *minor_status = kret;
		    return GSS_S_FAILURE;
		}
	    }
	    krb5_crypto_destroy(context, crypto);

        } else {
	    krb5_crypto crypto;

	    kret = krb5_crypto_init(context,
				    ctx->auth_context->keyblock,
				    0, &crypto);
	    if(kret) {
		krb5_free_authenticator(context, &authenticator);

		ret = GSS_S_FAILURE;
		*minor_status = kret;
		return ret;
	    }

	    /*
	     * Windows accepts Samba3's use of a kerberos, rather than
	     * GSSAPI checksum here
	     */

	    kret = krb5_verify_checksum(context,
					crypto, KRB5_KU_AP_REQ_AUTH_CKSUM, NULL, 0,
					authenticator->cksum);
	    krb5_free_authenticator(context, &authenticator);
	    krb5_crypto_destroy(context, crypto);

	    if(kret) {
		ret = GSS_S_BAD_SIG;
		*minor_status = kret;
		return ret;
	    }

	    /*
	     * Samba style get some flags (but not DCE-STYLE), use
	     * ap_options to guess the mutual flag.
	     */
 	    ctx->flags = GSS_C_REPLAY_FLAG | GSS_C_SEQUENCE_FLAG;
	    if (ap_options & AP_OPTS_MUTUAL_REQUIRED)
		ctx->flags |= GSS_C_MUTUAL_FLAG;
        }
    }

    if(ctx->flags & GSS_C_MUTUAL_FLAG) {
	krb5_data outbuf;
	int use_subkey = 0;

	_gsskrb5i_is_cfx(context, ctx, 1);
	is_cfx = (ctx->more_flags & IS_CFX);

	if (is_cfx || (ap_options & AP_OPTS_USE_SUBKEY)) {
	    use_subkey = 1;
	} else {
	    krb5_keyblock *rkey;

	    /*
	     * If there is a initiator subkey, copy that to acceptor
	     * subkey to match Windows behavior
	     */
	    kret = krb5_auth_con_getremotesubkey(context,
						 ctx->auth_context,
						 &rkey);
	    if (kret == 0) {
		kret = krb5_auth_con_setlocalsubkey(context,
						    ctx->auth_context,
						    rkey);
		if (kret == 0)
		    use_subkey = 1;
		krb5_free_keyblock(context, rkey);
	    }
	}
	if (use_subkey) {
	    ctx->gk5c.flags |= GK5C_ACCEPTOR_SUBKEY;
	    krb5_auth_con_addflags(context, ctx->auth_context,
				   KRB5_AUTH_CONTEXT_USE_SUBKEY,
				   NULL);
	}

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

	if (IS_DCE_STYLE(ctx)) {
	    output_token->length = outbuf.length;
	    output_token->value = outbuf.data;
	} else {
	    ret = _gsskrb5_encapsulate(minor_status,
				       &outbuf,
				       output_token,
				       "\x02\x00",
				       ctx->mech);
	    krb5_data_free (&outbuf);
	    if (ret)
		return ret;
	}
    }

    ctx->flags |= GSS_C_TRANS_FLAG;

    /* Remember the flags */

    ctx->endtime = ctx->ticket->ticket.endtime;
    ctx->more_flags |= OPEN;

    if (mech_type)
	*mech_type = ctx->mech;

    if (time_rec) {
	ret = _gsskrb5_lifetime_left(minor_status,
				     context,
				     ctx->endtime,
				     time_rec);
	if (ret) {
	    return ret;
	}
    }

    /*
     * When GSS_C_DCE_STYLE is in use, we need ask for a AP-REP from
     * the client.
     */
    if (IS_DCE_STYLE(ctx)) {
	/*
	 * Return flags to caller, but we haven't processed
	 * delgations yet
	 */
	if (ret_flags)
	    *ret_flags = (ctx->flags & ~GSS_C_DELEG_FLAG);

	ctx->acceptor_state = acceptor_wait_for_dcestyle;
	return GSS_S_CONTINUE_NEEDED;
    }

    ret = gsskrb5_acceptor_ready(minor_status, ctx, context,
				 delegated_cred_handle);

    if (ret_flags)
	*ret_flags = ctx->flags;

    return ret;
}
Example #6
0
static OM_uint32
pku2u_acceptor_start(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)
{
    krb5_data indata, outdata;
    krb5_error_code kret;
    heim_ipc ictx;
    OM_uint32 ret;
    
    if (ctx->messages == NULL) {
	ctx->messages = krb5_storage_emem();
	if (ctx->messages == NULL) {
	    *minor_status = ENOMEM;
	    return GSS_S_FAILURE;
	}
    }
    
    ret = _gsskrb5_decapsulate (minor_status,
				input_token_buffer,
				&indata,
				"\x05\x01",
				ctx->mech);
    if (ret == GSS_S_DEFECTIVE_TOKEN) {
	ctx->acceptor_state = gsskrb5_acceptor_start;
	return GSS_S_COMPLETE;
    } else if (ret != GSS_S_COMPLETE)
	return ret;
    
    krb5_storage_write(ctx->messages,
		       input_token_buffer->value,
		       input_token_buffer->length);
    
    kret = heim_ipc_init_context("ANY:org.h5l.kdc", &ictx);
    if (kret) {
	*minor_status = kret;
	return GSS_S_FAILURE;
    }
    
    
    ret = _gsskrb5_encapsulate(minor_status,
			       &outdata,
			       output_token,
			       "\x06\x00",
			       ctx->mech);
    heim_ipc_free_data(&outdata);
    if (ret != GSS_S_COMPLETE)
	return ret;
    
    krb5_storage_write(ctx->messages,
		       output_token->value,
		       output_token->length);
    
    
    *minor_status = 0;
    return GSS_S_FAILURE;
}