예제 #1
0
krb5_error_code KRB5_CALLCONV
krb5_auth_con_free(krb5_context context, krb5_auth_context auth_context)
{
    if (auth_context == NULL)
        return 0;
    if (auth_context->local_addr)
        krb5_free_address(context, auth_context->local_addr);
    if (auth_context->remote_addr)
        krb5_free_address(context, auth_context->remote_addr);
    if (auth_context->local_port)
        krb5_free_address(context, auth_context->local_port);
    if (auth_context->remote_port)
        krb5_free_address(context, auth_context->remote_port);
    if (auth_context->authentp)
        krb5_free_authenticator(context, auth_context->authentp);
    if (auth_context->key)
        krb5_k_free_key(context, auth_context->key);
    if (auth_context->send_subkey)
        krb5_k_free_key(context, auth_context->send_subkey);
    if (auth_context->recv_subkey)
        krb5_k_free_key(context, auth_context->recv_subkey);
    if (auth_context->rcache)
        krb5_rc_close(context, auth_context->rcache);
    if (auth_context->permitted_etypes)
        free(auth_context->permitted_etypes);
    if (auth_context->ad_context)
        krb5_authdata_context_free(context, auth_context->ad_context);
    free(auth_context);
    return 0;
}
예제 #2
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_verify_authenticator_checksum(krb5_context context,
				   krb5_auth_context ac,
				   void *data,
				   size_t len)
{
    krb5_error_code ret;
    krb5_keyblock *key = NULL;
    krb5_authenticator authenticator;
    krb5_crypto crypto;

    ret = krb5_auth_con_getauthenticator(context, ac, &authenticator);
    if (ret)
	return ret;
    if (authenticator->cksum == NULL) {
	ret = -17;
        goto out;
    }
    ret = krb5_auth_con_getkey(context, ac, &key);
    if (ret)
        goto out;
    ret = krb5_crypto_init(context, key, 0, &crypto);
    if (ret)
	goto out;
    ret = krb5_verify_checksum(context, crypto,
                               KRB5_KU_AP_REQ_AUTH_CKSUM,
                               data, len, authenticator->cksum);
    krb5_crypto_destroy(context, crypto);
out:
    krb5_free_authenticator(context, &authenticator);
    krb5_free_keyblock(context, key);
    return ret;
}
예제 #3
0
파일: kfree.c 프로젝트: kennymacdonald/krb5
void KRB5_CALLCONV
krb5_free_tkt_authent(krb5_context context, krb5_tkt_authent *val)
{
    if (val == NULL)
        return;
    krb5_free_ticket(context, val->ticket);
    krb5_free_authenticator(context, val->authenticator);
    free(val);
}
예제 #4
0
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL
krb5_auth_con_free(krb5_context context,
		   krb5_auth_context auth_context)
{
    if (auth_context != NULL) {
	krb5_free_authenticator(context, &auth_context->authenticator);
	if(auth_context->local_address){
	    free_HostAddress(auth_context->local_address);
	    free(auth_context->local_address);
	}
	if(auth_context->remote_address){
	    free_HostAddress(auth_context->remote_address);
	    free(auth_context->remote_address);
	}
	krb5_free_keyblock(context, auth_context->keyblock);
	krb5_free_keyblock(context, auth_context->remote_subkey);
	krb5_free_keyblock(context, auth_context->local_subkey);
	free (auth_context);
    }
    return 0;
}
예제 #5
0
static krb5_error_code
tgs_parse_request(krb5_context context, 
		  krb5_kdc_configuration *config,
		  KDC_REQ_BODY *b,
		  const PA_DATA *tgs_req,
		  hdb_entry_ex **krbtgt,
		  krb5_enctype *krbtgt_etype,
		  krb5_ticket **ticket,
		  const char **e_text,
		  const char *from,
		  const struct sockaddr *from_addr,
		  time_t **csec,
		  int **cusec,
		  AuthorizationData **auth_data)
{
    krb5_ap_req ap_req;
    krb5_error_code ret;
    krb5_principal princ;
    krb5_auth_context ac = NULL;
    krb5_flags ap_req_options;
    krb5_flags verify_ap_req_flags;
    krb5_crypto crypto;
    Key *tkey;

    *auth_data = NULL;
    *csec  = NULL;
    *cusec = NULL;

    memset(&ap_req, 0, sizeof(ap_req));
    ret = krb5_decode_ap_req(context, &tgs_req->padata_value, &ap_req);
    if(ret){
	kdc_log(context, config, 0, "Failed to decode AP-REQ: %s", 
		krb5_get_err_text(context, ret));
	goto out;
    }

    if(!get_krbtgt_realm(&ap_req.ticket.sname)){
	/* XXX check for ticket.sname == req.sname */
	kdc_log(context, config, 0, "PA-DATA is not a ticket-granting ticket");
	ret = KRB5KDC_ERR_POLICY; /* ? */
	goto out;
    }
    
    _krb5_principalname2krb5_principal(context,
				       &princ,
				       ap_req.ticket.sname,
				       ap_req.ticket.realm);
    
    ret = _kdc_db_fetch(context, config, princ, HDB_F_GET_KRBTGT, NULL, krbtgt);

    if(ret) {
	char *p;
	ret = krb5_unparse_name(context, princ, &p);
	if (ret != 0)
	    p = "<unparse_name failed>";
	krb5_free_principal(context, princ);
	kdc_log(context, config, 0,
		"Ticket-granting ticket not found in database: %s: %s",
		p, krb5_get_err_text(context, ret));
	if (ret == 0)
	    free(p);
	ret = KRB5KRB_AP_ERR_NOT_US;
	goto out;
    }
    
    if(ap_req.ticket.enc_part.kvno && 
       *ap_req.ticket.enc_part.kvno != (*krbtgt)->entry.kvno){
	char *p;

	ret = krb5_unparse_name (context, princ, &p);
	krb5_free_principal(context, princ);
	if (ret != 0)
	    p = "<unparse_name failed>";
	kdc_log(context, config, 0,
		"Ticket kvno = %d, DB kvno = %d (%s)", 
		*ap_req.ticket.enc_part.kvno,
		(*krbtgt)->entry.kvno,
		p);
	if (ret == 0)
	    free (p);
	ret = KRB5KRB_AP_ERR_BADKEYVER;
	goto out;
    }

    *krbtgt_etype = ap_req.ticket.enc_part.etype;

    ret = hdb_enctype2key(context, &(*krbtgt)->entry, 
			  ap_req.ticket.enc_part.etype, &tkey);
    if(ret){
	char *str, *p;
	krb5_enctype_to_string(context, ap_req.ticket.enc_part.etype, &str);
	krb5_unparse_name(context, princ, &p);
	kdc_log(context, config, 0,
		"No server key with enctype %s found for %s", str, p);
	free(str);
	free(p);
	ret = KRB5KRB_AP_ERR_BADKEYVER;
	goto out;
    }
    
    if (b->kdc_options.validate)
	verify_ap_req_flags = KRB5_VERIFY_AP_REQ_IGNORE_INVALID;
    else
	verify_ap_req_flags = 0;

    ret = krb5_verify_ap_req2(context,
			      &ac,
			      &ap_req,
			      princ,
			      &tkey->key,
			      verify_ap_req_flags,
			      &ap_req_options,
			      ticket,
			      KRB5_KU_TGS_REQ_AUTH);
			     
    krb5_free_principal(context, princ);
    if(ret) {
	kdc_log(context, config, 0, "Failed to verify AP-REQ: %s", 
		krb5_get_err_text(context, ret));
	goto out;
    }

    {
	krb5_authenticator auth;

	ret = krb5_auth_con_getauthenticator(context, ac, &auth);
	if (ret == 0) {
	    *csec   = malloc(sizeof(**csec));
	    if (*csec == NULL) {
		krb5_free_authenticator(context, &auth);
		kdc_log(context, config, 0, "malloc failed");
		goto out;
	    }
	    **csec  = auth->ctime;
	    *cusec  = malloc(sizeof(**cusec));
	    if (*cusec == NULL) {
		krb5_free_authenticator(context, &auth);
		kdc_log(context, config, 0, "malloc failed");
		goto out;
	    }
	    **cusec  = auth->cusec;
	    krb5_free_authenticator(context, &auth);
	}
    }

    ret = tgs_check_authenticator(context, config, 
				  ac, b, e_text, &(*ticket)->ticket.key);
    if (ret) {
	krb5_auth_con_free(context, ac);
	goto out;
    }

    if (b->enc_authorization_data) {
	krb5_keyblock *subkey;
	krb5_data ad;
	ret = krb5_auth_con_getremotesubkey(context,
					    ac,
					    &subkey);
	if(ret){
	    krb5_auth_con_free(context, ac);
	    kdc_log(context, config, 0, "Failed to get remote subkey: %s", 
		    krb5_get_err_text(context, ret));
	    goto out;
	}
	if(subkey == NULL){
	    ret = krb5_auth_con_getkey(context, ac, &subkey);
	    if(ret) {
		krb5_auth_con_free(context, ac);
		kdc_log(context, config, 0, "Failed to get session key: %s", 
			krb5_get_err_text(context, ret));
		goto out;
	    }
	}
	if(subkey == NULL){
	    krb5_auth_con_free(context, ac);
	    kdc_log(context, config, 0,
		    "Failed to get key for enc-authorization-data");
	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
	    goto out;
	}
	ret = krb5_crypto_init(context, subkey, 0, &crypto);
	if (ret) {
	    krb5_auth_con_free(context, ac);
	    kdc_log(context, config, 0, "krb5_crypto_init failed: %s",
		    krb5_get_err_text(context, ret));
	    goto out;
	}
	ret = krb5_decrypt_EncryptedData (context,
					  crypto,
					  KRB5_KU_TGS_REQ_AUTH_DAT_SUBKEY,
					  b->enc_authorization_data,
					  &ad);
	krb5_crypto_destroy(context, crypto);
	if(ret){
	    krb5_auth_con_free(context, ac);
	    kdc_log(context, config, 0, 
		    "Failed to decrypt enc-authorization-data");
	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
	    goto out;
	}
	krb5_free_keyblock(context, subkey);
	ALLOC(*auth_data);
	if (*auth_data == NULL) {
	    krb5_auth_con_free(context, ac);
	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
	    goto out;
	}
	ret = decode_AuthorizationData(ad.data, ad.length, *auth_data, NULL);
	if(ret){
	    krb5_auth_con_free(context, ac);
	    free(*auth_data);
	    *auth_data = NULL;
	    kdc_log(context, config, 0, "Failed to decode authorization data");
	    ret = KRB5KRB_AP_ERR_BAD_INTEGRITY; /* ? */
	    goto out;
	}
    }

    krb5_auth_con_free(context, ac);
    
out:
    free_AP_REQ(&ap_req);
    
    return ret;
}
예제 #6
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;
}
예제 #7
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;
}
예제 #8
0
파일: kerberos5.c 프로젝트: aunali1/exopc
void
kerberos5_is(Authenticator *ap, unsigned char *data, int cnt)
{
    krb5_error_code ret;
    krb5_data outbuf;
    krb5_keyblock *key_block;
    char *name;
    krb5_principal server;
    krb5_authenticator authenticator;
    int zero = 0;

    if (cnt-- < 1)
	return;
    switch (*data++) {
    case KRB_AUTH:
	auth.data = (char *)data;
	auth.length = cnt;

	auth_context = NULL;

	ret = krb5_auth_con_init (context, &auth_context);
	if (ret) {
	    Data(ap, KRB_REJECT, "krb5_auth_con_init failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("Kerberos V5: krb5_auth_con_init failed (%s)\r\n",
		       krb5_get_err_text(context, ret));
	    return;
	}

	ret = krb5_auth_con_setaddrs_from_fd (context,
					      auth_context,
					      &zero);
	if (ret) {
	    Data(ap, KRB_REJECT, "krb5_auth_con_setaddrs_from_fd failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("Kerberos V5: "
		       "krb5_auth_con_setaddrs_from_fd failed (%s)\r\n",
		       krb5_get_err_text(context, ret));
	    return;
	}

	ret = krb5_sock_to_principal (context,
				      0,
				      "host",
				      KRB5_NT_SRV_HST,
				      &server);
	if (ret) {
	    Data(ap, KRB_REJECT, "krb5_sock_to_principal failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("Kerberos V5: "
		       "krb5_sock_to_principal failed (%s)\r\n",
		       krb5_get_err_text(context, ret));
	    return;
	}

	ret = krb5_rd_req(context,
			  &auth_context,
			  &auth, 
			  server,
			  NULL,
			  NULL,
			  &ticket);
	krb5_free_principal (context, server);

	if (ret) {
	    char *errbuf;

	    asprintf(&errbuf,
		     "Read req failed: %s",
		     krb5_get_err_text(context, ret));
	    Data(ap, KRB_REJECT, errbuf, -1);
	    if (auth_debug_mode)
		printf("%s\r\n", errbuf);
	    free (errbuf);
	    return;
	}

	ret = krb5_auth_con_getkey(context, auth_context, &key_block);
	if (ret) {
	    Data(ap, KRB_REJECT, "krb5_auth_con_getkey failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("Kerberos V5: "
		       "krb5_auth_con_getkey failed (%s)\r\n",
		       krb5_get_err_text(context, ret));
	    return;
	}
	
	ret = krb5_auth_getauthenticator (context,
					  auth_context,
					  &authenticator);
	if (ret) {
	    Data(ap, KRB_REJECT, "krb5_auth_getauthenticator failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("Kerberos V5: "
		       "krb5_auth_getauthenticator failed (%s)\r\n",
		       krb5_get_err_text(context, ret));
	    return;
	}

	if (authenticator->cksum) {
	    char foo[2];

	    foo[0] = ap->type;
	    foo[1] = ap->way;

	    ret = krb5_verify_checksum (context,
					foo,
					sizeof(foo),
					key_block,
					authenticator->cksum);
	    if (ret) {
		Data(ap, KRB_REJECT, "No checksum", -1);
		if (auth_debug_mode)
		    printf ("No checksum\r\n");
		krb5_free_authenticator (context,
					 &authenticator);
		
		return;
	    }
	}
	krb5_free_authenticator (context,
				 &authenticator);

	ret = krb5_auth_con_getremotesubkey (context,
					     auth_context,
					     &key_block);

	if (ret) {
	    Data(ap, KRB_REJECT, "krb5_auth_con_getremotesubkey failed", -1);
	    auth_finished(ap, AUTH_REJECT);
	    if (auth_debug_mode)
		printf("Kerberos V5: "
		       "krb5_auth_con_getremotesubkey failed (%s)\r\n",
		       krb5_get_err_text(context, ret));
	    return;
	}

	if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL) {
	    ret = krb5_mk_rep(context, &auth_context, &outbuf);
	    if (ret) {
		Data(ap, KRB_REJECT,
		     "krb5_mk_rep failed", -1);
		auth_finished(ap, AUTH_REJECT);
		if (auth_debug_mode)
		    printf("Kerberos V5: "
			   "krb5_mk_rep failed (%s)\r\n",
			   krb5_get_err_text(context, ret));
		return;
	    }
	    Data(ap, KRB_RESPONSE, outbuf.data, outbuf.length);
	}
	if (krb5_unparse_name(context, ticket->client, &name))
	    name = 0;

	if(UserNameRequested && krb5_kuserok(context,
					     ticket->client,
					     UserNameRequested)) {
	    Data(ap, KRB_ACCEPT, name, name ? -1 : 0);
	    if (auth_debug_mode) {
		printf("Kerberos5 identifies him as ``%s''\r\n",
		       name ? name : "");
	    }

	    if(key_block->keytype == KEYTYPE_DES) {
		Session_Key skey;

		skey.type = SK_DES;
		skey.length = 8;
		skey.data = key_block->keyvalue.data;
		encrypt_session_key(&skey, 0);
	    }

	} else {
	    char *msg;

	    asprintf (&msg, "user `%s' is not authorized to "
		      "login as `%s'", 
		      name ? name : "<unknown>",
		      UserNameRequested ? UserNameRequested : "<nobody>");
	    if (msg == NULL)
		Data(ap, KRB_REJECT, NULL, 0);
	    else {
		Data(ap, KRB_REJECT, (void *)msg, -1);
		free(msg);
	    }
	}
	auth_finished(ap, AUTH_USER);

	krb5_free_keyblock_contents(context, key_block);
	
	break;
#ifdef	FORWARD
    case KRB_FORWARD: {
	struct passwd *pwd;
	char ccname[1024];	/* XXX */
	krb5_data inbuf;
	krb5_ccache ccache;
	inbuf.data = (char *)data;
	inbuf.length = cnt;

	pwd = getpwnam (UserNameRequested);
	if (pwd == NULL)
	    break;

	snprintf (ccname, sizeof(ccname),
		  "FILE:/tmp/krb5cc_%u", pwd->pw_uid);

	ret = krb5_cc_resolve (context, ccname, &ccache);
	if (ret) {
	    if (auth_debug_mode)
		printf ("Kerberos V5: could not get ccache: %s\r\n",
			krb5_get_err_text(context, ret));
	    break;
	}

	ret = krb5_cc_initialize (context,
				  ccache,
				  ticket->client);
	if (ret) {
	    if (auth_debug_mode)
		printf ("Kerberos V5: could not init ccache: %s\r\n",
			krb5_get_err_text(context, ret));
	    break;
	}

	ret = krb5_rd_cred (context,
			    auth_context,
			    ccache,
			    &inbuf);
	if(ret) {
	    char *errbuf;

	    asprintf (&errbuf,
		      "Read forwarded creds failed: %s",
		      krb5_get_err_text (context, ret));
	    if(errbuf == NULL)
		Data(ap, KRB_FORWARD_REJECT, NULL, 0);
	    else
		Data(ap, KRB_FORWARD_REJECT, errbuf, -1);
	    if (auth_debug_mode)
		printf("Could not read forwarded credentials: %s\r\n",
		       errbuf);
	    free (errbuf);
	} else
	    Data(ap, KRB_FORWARD_ACCEPT, 0, 0);
	chown (ccname + 5, pwd->pw_uid, -1);
	if (auth_debug_mode)
	    printf("Forwarded credentials obtained\r\n");
	break;
    }
#endif	/* FORWARD */
    default:
	if (auth_debug_mode)
	    printf("Unknown Kerberos option %d\r\n", data[-1]);
	Data(ap, KRB_REJECT, 0, 0);
	break;
    }
}
예제 #9
0
/*
 * krb5_authenticator_internalize()	- Internalize the krb5_authenticator.
 */
static krb5_error_code
krb5_authenticator_internalize(krb5_context kcontext, krb5_pointer *argp, krb5_octet **buffer, size_t *lenremain)
{
    krb5_error_code	kret;
    krb5_authenticator	*authenticator;
    krb5_int32		ibuf;
    krb5_octet		*bp;
    size_t		remain;
    int			i;
    krb5_int32		nadata;
    size_t		len;

    bp = *buffer;
    remain = *lenremain;
    kret = EINVAL;
    /* Read our magic number */
    if (krb5_ser_unpack_int32(&ibuf, &bp, &remain))
	ibuf = 0;
    if (ibuf == KV5M_AUTHENTICATOR) {
	kret = ENOMEM;

	/* Get memory for the authenticator */
	if ((remain >= (3*sizeof(krb5_int32))) &&
	    (authenticator = (krb5_authenticator *) 
	     calloc(1, sizeof(krb5_authenticator)))) {

	    /* Get ctime */
	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
	    authenticator->ctime = (krb5_timestamp) ibuf;

	    /* Get cusec */
	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
	    authenticator->cusec = ibuf;

	    /* Get seq_number */
	    (void) krb5_ser_unpack_int32(&ibuf, &bp, &remain);
	    authenticator->seq_number = ibuf;
	    
	    kret = 0;

	    /* Attempt to read in the client */
	    kret = krb5_internalize_opaque(kcontext,
					   KV5M_PRINCIPAL,
					   (krb5_pointer *)
					   &authenticator->client,
					   &bp,
					   &remain);
	    if (kret == EINVAL)
		kret = 0;

	    /* Attempt to read in the checksum */
	    if (!kret) {
		kret = krb5_internalize_opaque(kcontext,
					       KV5M_CHECKSUM,
					       (krb5_pointer *)
					       &authenticator->checksum,
					       &bp,
					       &remain);
		if (kret == EINVAL)
		    kret = 0;
	    }

	    /* Attempt to read in the subkey */
	    if (!kret) {
		kret = krb5_internalize_opaque(kcontext,
					       KV5M_KEYBLOCK,
					       (krb5_pointer *)
					       &authenticator->subkey,
					       &bp,
					       &remain);
		if (kret == EINVAL)
		    kret = 0;
	    }

	    /* Attempt to read in the authorization data count */
	    if (!(kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain))) {
		nadata = ibuf;
		len = (size_t) (nadata + 1);

		/* Get memory for the authorization data pointers */
		if ((authenticator->authorization_data = (krb5_authdata **)
		     calloc(len, sizeof(krb5_authdata *)))) {
		    for (i=0; !kret && (i<nadata); i++) {
			kret = krb5_internalize_opaque(kcontext,
						       KV5M_AUTHDATA,
						       (krb5_pointer *)
						       &authenticator->
						       authorization_data[i],
						       &bp,
						       &remain);
		    }

		    /* Finally, find the trailer */
		    if (!kret) {
			kret = krb5_ser_unpack_int32(&ibuf, &bp, &remain);
			if (!kret && (ibuf == KV5M_AUTHENTICATOR))
			    authenticator->magic = KV5M_AUTHENTICATOR;
			else
			    kret = EINVAL;
		    }
		}
	    }
	    if (!kret) {
		*buffer = bp;
		*lenremain = remain;
		*argp = (krb5_pointer) authenticator;
	    }
	    else
		krb5_free_authenticator(kcontext, authenticator);
	}
    }
    return(kret);
}
예제 #10
0
static krb5_error_code
recvauth(int f,
	krb5_context krb_context,
	unsigned int *valid_checksum,
	krb5_ticket **ticket,
	int *auth_type,
	krb5_principal *client,
	int encr_flag,
	krb5_keytab keytab)
{
	krb5_error_code status = 0;
	krb5_auth_context auth_context = NULL;
	krb5_rcache rcache;
	krb5_authenticator *authenticator;
	krb5_data inbuf;
	krb5_data auth_version;

	*valid_checksum = 0;

	if ((status = krb5_auth_con_init(krb_context, &auth_context)))
		return (status);

	/* Only need remote address for rd_cred() to verify client */
	if ((status = krb5_auth_con_genaddrs(krb_context, auth_context, f,
			KRB5_AUTH_CONTEXT_GENERATE_REMOTE_FULL_ADDR)))
		return (status);

	status = krb5_auth_con_getrcache(krb_context, auth_context, &rcache);
	if (status)
		return (status);

	if (!rcache) {
		krb5_principal server;

		status = krb5_sname_to_principal(krb_context, 0, 0,
						KRB5_NT_SRV_HST, &server);
		if (status)
			return (status);

		status = krb5_get_server_rcache(krb_context,
				krb5_princ_component(krb_context, server, 0),
				&rcache);
		krb5_free_principal(krb_context, server);
		if (status)
			return (status);

		status = krb5_auth_con_setrcache(krb_context, auth_context,
						rcache);
		if (status)
			return (status);
	}
	if ((status = krb5_compat_recvauth(krb_context,
					&auth_context,
					&f,
					NULL,	/* Specify daemon principal */
					0,	/* no flags */
					keytab,	/* NULL to use v5srvtab */
					ticket,	/* return ticket */
					auth_type, /* authentication system */
					&auth_version))) {
		if (*auth_type == KRB5_RECVAUTH_V5) {
			/*
			 * clean up before exiting
			 */
			getstr(f, rusername, sizeof (rusername), "remuser");
			getstr(f, lusername, sizeof (lusername), "locuser");
			getstr(f, term, sizeof (term), "Terminal type");
		}
		return (status);
	}

	getstr(f, lusername, sizeof (lusername), "locuser");
	getstr(f, term, sizeof (term), "Terminal type");

	kcmd_protocol = KCMD_UNKNOWN_PROTOCOL;
	if (auth_version.length != 9 || auth_version.data == NULL) {
		syslog(LOG_ERR, "Bad application protocol version length in "
		    "KRB5 exchange, exiting");
		fatal(f, "Bad application version length, exiting.");
	}
	/*
	 * Determine which Kerberos CMD protocol was used.
	 */
	if (strncmp(auth_version.data, "KCMDV0.1", 9) == 0) {
		kcmd_protocol = KCMD_OLD_PROTOCOL;
	} else if (strncmp(auth_version.data, "KCMDV0.2", 9) == 0) {
		kcmd_protocol = KCMD_NEW_PROTOCOL;
	} else {
		syslog(LOG_ERR, "Unrecognized KCMD protocol (%s), exiting",
			(char *)auth_version.data);
		fatal(f, "Unrecognized KCMD protocol, exiting");
	}

	if ((*auth_type == KRB5_RECVAUTH_V5) && chksum_flag &&
		kcmd_protocol == KCMD_OLD_PROTOCOL) {
		if ((status = krb5_auth_con_getauthenticator(krb_context,
							    auth_context,
							    &authenticator)))
			return (status);
		if (authenticator->checksum) {
			struct sockaddr_storage adr;
			int adr_length = sizeof (adr);
			int buflen;
			krb5_data input;
			krb5_keyblock key;
			char *chksumbuf;

			/*
			 * Define the lenght of the chksum buffer.
			 * chksum string = "[portnum]:termstr:username"
			 * The extra 32 is to hold a integer string for
			 * the portnumber.
			 */
			buflen = strlen(term) + strlen(lusername) + 32;
			chksumbuf = (char *)malloc(buflen);
			if (chksumbuf == 0) {
				krb5_free_authenticator(krb_context,
							authenticator);
				fatal(f, "Out of memory error");
			}

			if (getsockname(f, (struct sockaddr *)&adr,
							&adr_length) != 0) {
				krb5_free_authenticator(krb_context,
							authenticator);
				fatal(f, "getsockname error");
			}

			(void) snprintf(chksumbuf, buflen,
					"%u:%s%s",
					ntohs(SOCK_PORT(adr)),
					term, lusername);

			input.data = chksumbuf;
			input.length = strlen(chksumbuf);
			key.contents = (*ticket)->enc_part2->session->contents;
			key.length = (*ticket)->enc_part2->session->length;
			status = krb5_c_verify_checksum(krb_context,
						&key, 0,
						&input,
						authenticator->checksum,
						valid_checksum);

			if (status == 0 && *valid_checksum == 0)
				status = KRB5KRB_AP_ERR_BAD_INTEGRITY;

			if (chksumbuf)
				krb5_xfree(chksumbuf);
			if (status) {
				krb5_free_authenticator(krb_context,
							authenticator);
				return (status);
			}
		}
		krb5_free_authenticator(krb_context, authenticator);
	}

	if ((status = krb5_copy_principal(krb_context,
					(*ticket)->enc_part2->client,
					client)))
		return (status);

	/* Get the Unix username of the remote user */
	getstr(f, rusername, sizeof (rusername), "remuser");

	/* Get the Kerberos principal name string of the remote user */
	if ((status = krb5_unparse_name(krb_context, *client, &krusername)))
		return (status);

#ifdef DEBUG
	syslog(LOG_DEBUG | LOG_AUTH, "rlogind: got krb5 credentials for %s",
	    (krusername != NULL ? krusername : "******"));
#endif

	if (encr_flag) {
		status = krb5_auth_con_getremotesubkey(krb_context,
						    auth_context,
						    &session_key);
		if (status) {
			syslog(LOG_ERR, "Error getting KRB5 session "
			    "subkey, exiting");
			fatal(f, "Error getting KRB5 session subkey, exiting");
		}
		/*
		 * The "new" protocol requires that a subkey be sent.
		 */
		if (session_key == NULL &&
		    kcmd_protocol == KCMD_NEW_PROTOCOL) {
			syslog(LOG_ERR, "No KRB5 session subkey sent, exiting");
			fatal(f, "No KRB5 session subkey sent, exiting");
		}
		/*
		 * The "old" protocol does not permit an authenticator subkey.
		 * The key is taken from the ticket instead (see below).
		 */
		if (session_key != NULL &&
		    kcmd_protocol == KCMD_OLD_PROTOCOL) {
			syslog(LOG_ERR, "KRB5 session subkey not permitted "
			    "with old KCMD protocol, exiting");

			fatal(f, "KRB5 session subkey not permitted "
			    "with old KCMD protocol, exiting");
		}
		/*
		 * If no key at this point, use the session key from
		 * the ticket.
		 */
		if (session_key == NULL) {
			/*
			 * Save the session key so we can configure the crypto
			 * module later.
			 */
			status = krb5_copy_keyblock(krb_context,
					    (*ticket)->enc_part2->session,
					    &session_key);
			if (status) {
				syslog(LOG_ERR, "krb5_copy_keyblock failed");
				fatal(f, "krb5_copy_keyblock failed");
			}
		}
		/*
		 * If session key still cannot be found, we must
		 * exit because encryption is required here
		 * when encr_flag (-x) is set.
		 */
		if (session_key == NULL) {
			syslog(LOG_ERR, "Could not find an encryption key,"
				    "exiting");
			fatal(f, "Encryption required but key not found, "
			    "exiting");
		}
	}
	/*
	 * Use krb5_read_message to read the principal stuff.
	 */
	if ((status = krb5_read_message(krb_context, (krb5_pointer)&f,
					&inbuf)))
		fatal(f, "Error reading krb5 message");

	if (inbuf.length) { /* Forwarding being done, read creds */
		krb5_creds **creds = NULL;

		if (status = krb5_rd_cred(krb_context, auth_context, &inbuf,
					    &creds, NULL)) {
			if (rcache)
				(void) krb5_rc_close(krb_context, rcache);
			krb5_free_creds(krb_context, *creds);
			fatal(f, "Can't get forwarded credentials");
		}

		/* Store the forwarded creds in the ccache */
		if (status = store_forw_creds(krb_context,
					    creds, *ticket, lusername,
					    &ccache)) {
			if (rcache)
				(void) krb5_rc_close(krb_context, rcache);
			krb5_free_creds(krb_context, *creds);
			fatal(f, "Can't store forwarded credentials");
		}
		krb5_free_creds(krb_context, *creds);
	}

	if (rcache)
		(void) krb5_rc_close(krb_context, rcache);

	return (status);
}
예제 #11
0
파일: kstuff.c 프로젝트: davidben/zephyr
Code_t
ZCheckSrvAuthentication(ZNotice_t *notice,
			struct sockaddr_in *from,
			char *realm)
{
#ifdef HAVE_KRB5
    unsigned char *authbuf;
    krb5_principal princ;
    krb5_data packet;
    krb5_ticket *tkt;
    char *name;
    krb5_error_code result;
    krb5_principal server;
    krb5_keytab keytabid = 0;
    krb5_auth_context authctx;
    krb5_keyblock *keyblock;
    krb5_enctype enctype;
    krb5_cksumtype cksumtype;
    krb5_data cksumbuf;
    int valid;
    char *cksum0_base, *cksum1_base = NULL, *cksum2_base;
    char *x;
    unsigned char *asn1_data, *key_data, *cksum_data;
    int asn1_len, key_len, cksum0_len = 0, cksum1_len = 0, cksum2_len = 0;
    KRB5_AUTH_CON_FLAGS_TYPE acflags;
#ifdef KRB5_AUTH_CON_GETAUTHENTICATOR_TAKES_DOUBLE_POINTER
    krb5_authenticator *authenticator;
#define KRB5AUTHENT authenticator
#else
    krb5_authenticator authenticator;
#define KRB5AUTHENT &authenticator
#endif
    int len;
    char *sender;
    char rlmprincipal[MAX_PRINCIPAL_SIZE];

    if (!notice->z_auth)
        return ZAUTH_NO;

    /* Check for bogus authentication data length. */
    if (notice->z_authent_len <= 0) {
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: bogus authenticator length");
        return ZAUTH_FAILED;
    }

#ifdef HAVE_KRB4
    if (notice->z_ascii_authent[0] != 'Z' && realm == NULL)
      return ZCheckAuthentication4(notice, from);
#endif

    len = strlen(notice->z_ascii_authent)+1;
    authbuf = malloc(len);

    /* Read in the authentication data. */
    if (ZReadZcode((unsigned char *)notice->z_ascii_authent,
                   authbuf,
                   len, &len) == ZERR_BADFIELD) {
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: ZReadZcode: Improperly formatted field");
        return ZAUTH_FAILED;
    }

    if (realm == NULL) {
	sender = notice->z_sender;
    } else {
	(void) snprintf(rlmprincipal, MAX_PRINCIPAL_SIZE, "%s/%s@%s", SERVER_SERVICE,
			SERVER_INSTANCE, realm);
	sender = rlmprincipal;
    }

    packet.length = len;
    packet.data = (char *)authbuf;

    result = krb5_kt_resolve(Z_krb5_ctx,
                        keytab_file, &keytabid);
    if (result) {
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_kt_resolve: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, keytabid */
    /* Create the auth context */
    result = krb5_auth_con_init(Z_krb5_ctx, &authctx);
    if (result) {
        krb5_kt_close(Z_krb5_ctx, keytabid);
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_init: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, keytabid, authctx */
    result = krb5_auth_con_getflags(Z_krb5_ctx, authctx, &acflags);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_kt_close(Z_krb5_ctx, keytabid);
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_getflags: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    acflags &= ~KRB5_AUTH_CONTEXT_DO_TIME;

    result = krb5_auth_con_setflags(Z_krb5_ctx, authctx, acflags);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_kt_close(Z_krb5_ctx, keytabid);
        free(authbuf);
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: krb5_auth_con_setflags: %s", error_message(result));
        return ZAUTH_FAILED;
    }

    result = krb5_build_principal(Z_krb5_ctx, &server, strlen(__Zephyr_realm),
				  __Zephyr_realm, SERVER_SERVICE,
				  SERVER_INSTANCE, NULL);
    if (!result) {
        result = krb5_rd_req(Z_krb5_ctx, &authctx, &packet, server,
                             keytabid, NULL, &tkt);
	krb5_free_principal(Z_krb5_ctx, server);
    }
    krb5_kt_close(Z_krb5_ctx, keytabid);

    /* HOLDING: authbuf, authctx */
    if (result) {
        if (result == KRB5KRB_AP_ERR_REPEAT)
            syslog(LOG_DEBUG, "ZCheckSrvAuthentication: k5 auth failed: %s",
                   error_message(result));
        else
            syslog(LOG_WARNING,"ZCheckSrvAuthentication: k5 auth failed: %s",
                   error_message(result));
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, authctx, tkt */

    if (tkt == 0 || !Z_tktprincp(tkt)) {
        if (tkt)
            krb5_free_ticket(Z_krb5_ctx, tkt);
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: No Ticket");
        return ZAUTH_FAILED;
    }

    princ = Z_tktprinc(tkt);

    if (princ == 0) {
        krb5_free_ticket(Z_krb5_ctx, tkt);
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: No... Ticket?");
        return ZAUTH_FAILED;
    }

    /* HOLDING: authbuf, authctx, tkt */
    result = krb5_unparse_name(Z_krb5_ctx, princ, &name);
    if (result) {
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_unparse_name failed: %s",
               error_message(result));
        free(authbuf);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_ticket(Z_krb5_ctx, tkt);
        return ZAUTH_FAILED;
    }

    krb5_free_ticket(Z_krb5_ctx, tkt);

    /* HOLDING: authbuf, authctx, name */
    if (strcmp(name, sender)) {
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: name mismatch: '%s' vs '%s'",
               name, sender);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
        krb5_free_unparsed_name(Z_krb5_ctx, name);
#else
        free(name);
#endif
        free(authbuf);
        return ZAUTH_FAILED;
    }
#ifdef HAVE_KRB5_FREE_UNPARSED_NAME
    krb5_free_unparsed_name(Z_krb5_ctx, name);
#else
    free(name);
#endif
    free(authbuf);

    /* HOLDING: authctx */
    /* Get an authenticator so we can get the keyblock */
    result = krb5_auth_con_getauthenticator (Z_krb5_ctx, authctx,
    					     &authenticator);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getauthenticator failed: %s",
               error_message(result));
        return ZAUTH_FAILED;
    }

    /* HOLDING: authctx, authenticator */
    result = krb5_auth_con_getkey(Z_krb5_ctx, authctx, &keyblock);
    if (result) {
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: krb5_auth_con_getkey failed: %s",
               error_message(result));
        return (ZAUTH_FAILED);
    }

    /* HOLDING: authctx, authenticator, keyblock */
    /* Figure out what checksum type to use */
    key_data = Z_keydata(keyblock);
    key_len = Z_keylen(keyblock);
    result = Z_ExtractEncCksum(keyblock, &enctype, &cksumtype);
    if (result) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: Z_ExtractEncCksum failed: %s",
               error_message(result));
        return (ZAUTH_FAILED);
    }
    /* HOLDING: authctx, authenticator, keyblock */

    if (realm == NULL)
	ZSetSession(keyblock);

    /* Assemble the things to be checksummed */
    /* first part is from start of packet through z_default_format:
     * - z_version
     * - z_num_other_fields
     * - z_kind
     * - z_uid
     * - z_port
     * - z_auth
     * - z_authent_len
     * - z_ascii_authent
     * - z_class
     * - z_class_inst
     * - z_opcode
     * - z_sender
     * - z_recipient
     * - z_default_format
     */
    cksum0_base = notice->z_packet;
    x           = notice->z_default_format;
    cksum0_len  = x + strlen(x) + 1 - cksum0_base;
    /* second part is from z_multinotice through other fields:
     * - z_multinotice
     * - z_multiuid
     * - z_sender_(sock)addr
     * - z_charset
     * - z_other_fields[]
     */
    if (notice->z_num_hdr_fields > 15 ) {
	cksum1_base = notice->z_multinotice;
	if (notice->z_num_other_fields)
	    x = notice->z_other_fields[notice->z_num_other_fields - 1];
	else {
	    /* see also ZCheckRealmAuthentication
	       and lib/ZCkZaut.c:ZCheckZcodeAuthentication  */
	    /* XXXXXXXXXXXXXXXXXXXXXXX */
	    if (notice->z_num_hdr_fields > 16)
		x = cksum1_base + strlen(cksum1_base) + 1; /* multinotice */
	    if (notice->z_num_hdr_fields > 17)
		x = x + strlen(x) + 1; /* multiuid */
	    if (notice->z_num_hdr_fields > 18)
		x = x + strlen(x) + 1; /* sender */
	}
	cksum1_len  = x + strlen(x) + 1 - cksum1_base; /* charset / extra field */
    }

    /* last part is the message body */
    cksum2_base = notice->z_message;
    cksum2_len  = notice->z_message_len;

    /*XXX we may wish to ditch this code someday?*/
    if ((!notice->z_ascii_checksum || *notice->z_ascii_checksum != 'Z') &&
        key_len == 8 &&
        (enctype == (krb5_enctype)ENCTYPE_DES_CBC_CRC ||
         enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD4 ||
         enctype == (krb5_enctype)ENCTYPE_DES_CBC_MD5)) {
      /* try old-format checksum (covers cksum0 only) */

      ZChecksum_t our_checksum;

      if (realm == NULL)
	  our_checksum = compute_checksum(notice, key_data);
      else
	  our_checksum = compute_rlm_checksum(notice, key_data);

      krb5_free_keyblock(Z_krb5_ctx, keyblock);
      krb5_auth_con_free(Z_krb5_ctx, authctx);
      krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);

      if (our_checksum == notice->z_checksum) {
          return ZAUTH_YES;
      } else {
          syslog(LOG_DEBUG, "ZCheckSrvAuthentication: des quad checksum mismatch");
          return ZAUTH_FAILED;
      }
    }

    /* HOLDING: authctx, authenticator */

    cksumbuf.length = cksum0_len + cksum1_len + cksum2_len;
    cksumbuf.data = malloc(cksumbuf.length);
    if (!cksumbuf.data) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(cksumbuf.data): %m");
        return ZAUTH_FAILED;
    }
    /* HOLDING: authctx, authenticator, cksumbuf.data */

    cksum_data = (unsigned char *)cksumbuf.data;
    memcpy(cksum_data, cksum0_base, cksum0_len);
    if (cksum1_len)
	memcpy(cksum_data + cksum0_len, cksum1_base, cksum1_len);
    memcpy(cksum_data + cksum0_len + cksum1_len,
           cksum2_base, cksum2_len);

    /* decode zcoded checksum */
    /* The encoded form is always longer than the original */
    asn1_len = strlen(notice->z_ascii_checksum) + 1;
    asn1_data = malloc(asn1_len);
    if (!asn1_data) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        free(cksumbuf.data);
        syslog(LOG_ERR, "ZCheckSrvAuthentication: malloc(asn1_data): %m");
        return ZAUTH_FAILED;
    }
    /* HOLDING: authctx, authenticator, cksumbuf.data, asn1_data */
    result = ZReadZcode((unsigned char *)notice->z_ascii_checksum,
                        asn1_data, asn1_len, &asn1_len);
    if (result != ZERR_NONE) {
        krb5_free_keyblock(Z_krb5_ctx, keyblock);
        krb5_auth_con_free(Z_krb5_ctx, authctx);
        krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
        free(asn1_data);
        free(cksumbuf.data);
        syslog(LOG_WARNING, "ZCheckSrvAuthentication: ZReadZcode: %s",
               error_message(result));
        return ZAUTH_FAILED;
    }
    /* HOLDING: asn1_data, cksumbuf.data, authctx, authenticator */

    valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype,
				Z_KEYUSAGE_CLT_CKSUM,
				asn1_data, asn1_len);

    /* XXX compatibility with unreleased interrealm krb5; drop in 3.1 */
    if (!valid && realm)
	valid = Z_krb5_verify_cksum(keyblock, &cksumbuf, cksumtype,
				    Z_KEYUSAGE_SRV_CKSUM,
				    asn1_data, asn1_len);

    free(asn1_data);
    krb5_auth_con_free(Z_krb5_ctx, authctx);
    krb5_free_authenticator(Z_krb5_ctx, KRB5AUTHENT);
    krb5_free_keyblock(Z_krb5_ctx, keyblock);
    free(cksumbuf.data);

    if (valid) {
        return ZAUTH_YES;
    } else {
        syslog(LOG_DEBUG, "ZCheckSrvAuthentication: Z_krb5_verify_cksum: failed");
        return ZAUTH_FAILED;
    }
#else
    return (notice->z_auth) ? ZAUTH_YES : ZAUTH_NO;
#endif
}
예제 #12
0
int
kerberos5_is_auth (TN_Authenticator * ap, unsigned char *data, int cnt,
		   char *errbuf, int errbuflen)
{
  int r = 0;
  krb5_keytab keytabid = 0;
  krb5_authenticator *authenticator;
  char *name;
  krb5_data outbuf;
  krb5_keyblock *newkey = NULL;
  krb5_principal server;

# ifdef ENCRYPTION
  Session_Key skey;
# endif

  auth.data = (char *) data;
  auth.length = cnt;

  if (!r && !auth_context)
    r = krb5_auth_con_init (telnet_context, &auth_context);
  if (!r)
    {
      krb5_rcache rcache;

      r = krb5_auth_con_getrcache (telnet_context, auth_context, &rcache);
      if (!r && !rcache)
	{
	  r = krb5_sname_to_principal (telnet_context, 0, 0,
				       KRB5_NT_SRV_HST, &server);
	  if (!r)
	    {
	      r = krb5_get_server_rcache (telnet_context,
					  krb5_princ_component
					  (telnet_context, server, 0),
					  &rcache);
	      krb5_free_principal (telnet_context, server);
	    }
	}
      if (!r)
	r = krb5_auth_con_setrcache (telnet_context, auth_context, rcache);
    }

  if (!r && telnet_srvtab)
    r = krb5_kt_resolve (telnet_context, telnet_srvtab, &keytabid);
  if (!r)
    r = krb5_rd_req (telnet_context, &auth_context, &auth,
		     NULL, keytabid, NULL, &ticket);
  if (r)
    {
      snprintf (errbuf, errbuflen, "krb5_rd_req failed: %s",
		error_message (r));
      return r;
    }

  /* 256 bytes should be much larger than any reasonable
     first component of a service name especially since
     the default is of length 4. */
  if (krb5_princ_component (telnet_context, ticket->server, 0)->length < 256)
    {
      char princ[256];
      strncpy (princ,
	       krb5_princ_component (telnet_context, ticket->server, 0)->data,
	       krb5_princ_component (telnet_context, ticket->server,
				     0)->length);
      princ[krb5_princ_component (telnet_context, ticket->server, 0)->
	    length] = '\0';
      if (strcmp ("host", princ))
	{
	  snprintf (errbuf, errbuflen,
		    "incorrect service name: \"%s\" != \"host\"", princ);
	  return 1;
	}
    }
  else
    {
      strncpy (errbuf, "service name too long", errbuflen);
      return 1;
    }

  r = krb5_auth_con_getauthenticator (telnet_context,
				      auth_context, &authenticator);
  if (r)
    {
      snprintf (errbuf, errbuflen,
		"krb5_auth_con_getauthenticator failed: %s",
		error_message (r));
      return 1;
    }

# ifdef AUTH_ENCRYPT_MASK
  if ((ap->way & AUTH_ENCRYPT_MASK) == AUTH_ENCRYPT_ON
      && !authenticator->checksum)
    {
      snprintf (errbuf, errbuflen,
		"authenticator is missing required checksum");
      return 1;
    }
# endif

  if (authenticator->checksum)
    {
      char type_check[2];
      krb5_checksum *cksum = authenticator->checksum;
      krb5_keyblock *key;

      type_check[0] = ap->type;
      type_check[1] = ap->way;

      r = krb5_auth_con_getkey (telnet_context, auth_context, &key);
      if (r)
	{
	  snprintf (errbuf, errbuflen,
		    "krb5_auth_con_getkey failed: %s", error_message (r));
	  return 1;
	}

      r = krb5_verify_checksum (telnet_context,
				cksum->checksum_type, cksum,
				&type_check, 2, key->contents, key->length);

      if (r)
	{
	  snprintf (errbuf, errbuflen,
		    "checksum verification failed: %s", error_message (r));
	  return 1;
	}
      krb5_free_keyblock (telnet_context, key);
    }

  krb5_free_authenticator (telnet_context, authenticator);
  if ((ap->way & AUTH_HOW_MASK) == AUTH_HOW_MUTUAL)
    {
      if ((r = krb5_mk_rep (telnet_context, auth_context, &outbuf)))
	{
	  snprintf (errbuf, errbuflen, "Make reply failed: %s",
		    error_message (r));
	  return 1;
	}

      Data (ap, KRB_RESPONSE, outbuf.data, outbuf.length);
    }

  if (krb5_unparse_name (telnet_context, ticket->enc_part2->client, &name))
    name = 0;

  Data (ap, KRB_ACCEPT, name, name ? -1 : 0);
  DEBUG (("telnetd: Kerberos5 identifies him as ``%s''\r\n",
	  name ? name : ""));
  auth_finished (ap, AUTH_USER);

  free (name);
  krb5_auth_con_getremotesubkey (telnet_context, auth_context, &newkey);

  if (session_key)
    {
      krb5_free_keyblock (telnet_context, session_key);
      session_key = 0;
    }

  if (newkey)
    {
      krb5_copy_keyblock (telnet_context, newkey, &session_key);
      krb5_free_keyblock (telnet_context, newkey);
    }
  else
    {
      krb5_copy_keyblock (telnet_context, ticket->enc_part2->session,
			  &session_key);
    }
  telnet_encrypt_key (&skey);
  return 0;
}