Ejemplo n.º 1
0
static krb5_error_code
fast_armor_ap_request(krb5_context context,
                      struct krb5int_fast_request_state *state,
                      krb5_ccache ccache, krb5_principal target_principal)
{
    krb5_error_code retval = 0;
    krb5_creds creds, *out_creds = NULL;
    krb5_auth_context authcontext = NULL;
    krb5_data encoded_authenticator;
    krb5_fast_armor *armor = NULL;
    krb5_keyblock *subkey = NULL, *armor_key = NULL;

    encoded_authenticator.data = NULL;
    memset(&creds, 0, sizeof(creds));
    creds.server = target_principal;
    retval = krb5_cc_get_principal(context, ccache, &creds.client);
    if (retval == 0)
        retval = krb5_get_credentials(context, 0, ccache,  &creds, &out_creds);
    if (retval == 0) {
        TRACE_FAST_ARMOR_CCACHE_KEY(context, &out_creds->keyblock);
        retval = krb5_mk_req_extended(context, &authcontext,
                                      AP_OPTS_USE_SUBKEY, NULL /*data*/,
                                      out_creds, &encoded_authenticator);
    }
    if (retval == 0)
        retval = krb5_auth_con_getsendsubkey(context, authcontext, &subkey);
    if (retval == 0)
        retval = krb5_c_fx_cf2_simple(context, subkey, "subkeyarmor",
                                      &out_creds->keyblock, "ticketarmor",
                                      &armor_key);
    if (retval == 0) {
        TRACE_FAST_ARMOR_KEY(context, armor_key);
        armor = calloc(1, sizeof(krb5_fast_armor));
        if (armor == NULL)
            retval = ENOMEM;
    }
    if (retval == 0) {
        armor->armor_type = KRB5_FAST_ARMOR_AP_REQUEST;
        armor->armor_value = encoded_authenticator;
        encoded_authenticator.data = NULL;
        encoded_authenticator.length = 0;
        state->armor = armor;
        armor = NULL;
        state->armor_key = armor_key;
        armor_key = NULL;
    }
    krb5_free_keyblock(context, armor_key);
    krb5_free_keyblock(context, subkey);
    if (out_creds)
        krb5_free_creds(context, out_creds);
    /* target_principal is owned by caller. */
    creds.server = NULL;
    krb5_free_cred_contents(context, &creds);
    if (encoded_authenticator.data)
        krb5_free_data_contents(context, &encoded_authenticator);
    krb5_auth_con_free(context, authcontext);
    return retval;
}
Ejemplo n.º 2
0
krb5_error_code KRB5_CALLCONV
krb5_auth_con_getlocalsubkey(krb5_context context, krb5_auth_context auth_context, krb5_keyblock **keyblock)
{
    return krb5_auth_con_getsendsubkey(context, auth_context, keyblock);
}
Ejemplo n.º 3
0
Archivo: chpw.c Proyecto: aosm/Kerberos
krb5_error_code 
krb5int_rd_chpw_rep(krb5_context context, krb5_auth_context auth_context, krb5_data *packet, int *result_code, krb5_data *result_data)
{
    char *ptr;
    int plen, vno;
    krb5_data ap_rep;
    krb5_ap_rep_enc_part *ap_rep_enc;
    krb5_error_code ret;
    krb5_data cipherresult;
    krb5_data clearresult;
    krb5_error *krberror;
    krb5_replay_data replay;
    krb5_keyblock *tmp;

    if (packet->length < 4)
	/* either this, or the server is printing bad messages,
	   or the caller passed in garbage */
	return(KRB5KRB_AP_ERR_MODIFIED);

    ptr = packet->data;

    /* verify length */

    plen = (*ptr++ & 0xff);
    plen = (plen<<8) | (*ptr++ & 0xff);

    if (plen != packet->length) 
	{
		/*
		 * MS KDCs *may* send back a KRB_ERROR.  Although
		 * not 100% correct via RFC3244, it's something
		 * we can workaround here.
		 */
		if (krb5_is_krb_error(packet)) {

			if ((ret = krb5_rd_error(context, packet, &krberror)))
			return(ret);

			if (krberror->e_data.data  == NULL) {
				ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
				krb5_free_error(context, krberror);
				return (ret);
			}
		}
		else
		{
			return(KRB5KRB_AP_ERR_MODIFIED);
		}
	}
	

    /* verify version number */

    vno = (*ptr++ & 0xff);
    vno = (vno<<8) | (*ptr++ & 0xff);

    if (vno != 1)
	return(KRB5KDC_ERR_BAD_PVNO);

    /* read, check ap-rep length */

    ap_rep.length = (*ptr++ & 0xff);
    ap_rep.length = (ap_rep.length<<8) | (*ptr++ & 0xff);

    if (ptr + ap_rep.length >= packet->data + packet->length)
	return(KRB5KRB_AP_ERR_MODIFIED);

    if (ap_rep.length) {
	/* verify ap_rep */
	ap_rep.data = ptr;
	ptr += ap_rep.length;

	/*
	 * Save send_subkey to later smash recv_subkey.
	 */
	ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmp);
	if (ret)
	    return ret;

	ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
	if (ret) {
	    krb5_free_keyblock(context, tmp);
	    return(ret);
	}

	krb5_free_ap_rep_enc_part(context, ap_rep_enc);

	/* extract and decrypt the result */

	cipherresult.data = ptr;
	cipherresult.length = (packet->data + packet->length) - ptr;

	/*
	 * Smash recv_subkey to be send_subkey, per spec.
	 */
	ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmp);
	krb5_free_keyblock(context, tmp);
	if (ret)
	    return ret;

	ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
			   &replay);

	if (ret)
	    return(ret);
    } else {
	cipherresult.data = ptr;
	cipherresult.length = (packet->data + packet->length) - ptr;

	if ((ret = krb5_rd_error(context, &cipherresult, &krberror)))
	    return(ret);

	clearresult = krberror->e_data;
    }

    if (clearresult.length < 2) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    ptr = clearresult.data;

    *result_code = (*ptr++ & 0xff);
    *result_code = (*result_code<<8) | (*ptr++ & 0xff);

    if ((*result_code < KRB5_KPASSWD_SUCCESS) ||
	(*result_code > KRB5_KPASSWD_INITIAL_FLAG_NEEDED)) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    /* all success replies should be authenticated/encrypted */

    if ((ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS)) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    result_data->length = (clearresult.data + clearresult.length) - ptr;

    if (result_data->length) {
	result_data->data = (char *) malloc(result_data->length);
	if (result_data->data == NULL) {
	    ret = ENOMEM;
	    goto cleanup;
	}
	memcpy(result_data->data, ptr, result_data->length);
    } else {
	result_data->data = NULL;
    }

    ret = 0;

cleanup:
    if (ap_rep.length) {
	krb5_xfree(clearresult.data);
    } else {
	krb5_free_error(context, krberror);
    }

    return(ret);
}
Ejemplo n.º 4
0
static int
cifs_krb5_get_req(const char *host, const char *ccname,
		  DATA_BLOB * mechtoken, DATA_BLOB * sess_key)
{
	krb5_error_code ret;
	krb5_keyblock *tokb;
	krb5_context context;
	krb5_ccache ccache;
	krb5_creds in_creds, *out_creds;
	krb5_data apreq_pkt, in_data;
	krb5_auth_context auth_context = NULL;
#if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
	static const uint8_t gss_cksum[24] = { 0x10, 0x00, /* ... */};
#endif

	ret = krb5_init_context(&context);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to init krb5 context", __func__);
		return ret;
	}

	ret = krb5_cc_resolve(context, ccname, &ccache);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to resolve %s to ccache\n",
		       __func__, ccname);
		goto out_free_context;
	}

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

	ret = krb5_cc_get_principal(context, ccache, &in_creds.client);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to get client principal name",
		       __func__);
		goto out_free_ccache;
	}

	ret = krb5_sname_to_principal(context, host, "cifs", KRB5_NT_UNKNOWN,
					&in_creds.server);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to convert sname to princ (%s).",
		       __func__, host);
		goto out_free_principal;
	}

	ret = krb5_get_credentials(context, 0, ccache, &in_creds, &out_creds);
	krb5_free_principal(context, in_creds.server);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to get credentials for %s",
		       __func__, host);
		goto out_free_principal;
	}

	in_data.length = 0;
	in_data.data = NULL;

	ret = krb5_auth_con_init(context, &auth_context);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to create auth_context: %d",
		       __func__, ret);
		goto out_free_creds;
	}

#if defined(HAVE_KRB5_AUTH_CON_SETADDRS) && defined(HAVE_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE)
	/* Ensure we will get an addressless ticket. */
	ret = krb5_auth_con_setaddrs(context, auth_context, NULL, NULL);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to set NULL addrs: %d",
		       __func__, ret);
		goto out_free_auth;
	}

	/*
	 * Create a GSSAPI checksum (0x8003), see RFC 4121.
	 *
	 * The current layout is
	 *
	 * 0x10, 0x00, 0x00, 0x00 - length = 16
	 * 0x00, 0x00, 0x00, 0x00 - channel binding info - 16 zero bytes
	 * 0x00, 0x00, 0x00, 0x00
	 * 0x00, 0x00, 0x00, 0x00
	 * 0x00, 0x00, 0x00, 0x00
	 * 0x00, 0x00, 0x00, 0x00 - flags
	 *
	 * GSS_C_NO_CHANNEL_BINDINGS means 16 zero bytes,
	 * this is needed to work against some closed source
	 * SMB servers.
	 *
	 * See https://bugzilla.samba.org/show_bug.cgi?id=7890
	 */
	in_data.data = discard_const_p(char, gss_cksum);
	in_data.length = 24;

	/* MIT krb5 < 1.7 is missing the prototype, but still has the symbol */
#if !HAVE_DECL_KRB5_AUTH_CON_SET_REQ_CKSUMTYPE
	krb5_error_code krb5_auth_con_set_req_cksumtype(
		krb5_context      context,
		krb5_auth_context auth_context,
		krb5_cksumtype    cksumtype);
#endif
	ret = krb5_auth_con_set_req_cksumtype(context, auth_context, 0x8003);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to set 0x8003 checksum",
		       __func__);
		goto out_free_auth;
	}
#endif

	apreq_pkt.length = 0;
	apreq_pkt.data = NULL;
	ret = krb5_mk_req_extended(context, &auth_context, AP_OPTS_USE_SUBKEY,
				   &in_data, out_creds, &apreq_pkt);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to make AP-REQ for %s",
		       __func__, host);
		goto out_free_auth;
	}

	ret = krb5_auth_con_getsendsubkey(context, auth_context, &tokb);
	if (ret) {
		syslog(LOG_DEBUG, "%s: unable to get session key for %s",
		       __func__, host);
		goto out_free_auth;
	}

	*mechtoken = data_blob(apreq_pkt.data, apreq_pkt.length);
	*sess_key = data_blob(KRB5_KEY_DATA(tokb), KRB5_KEY_LENGTH(tokb));

	krb5_free_keyblock(context, tokb);
out_free_auth:
	krb5_auth_con_free(context, auth_context);
out_free_creds:
	krb5_free_creds(context, out_creds);
out_free_principal:
	krb5_free_principal(context, in_creds.client);
out_free_ccache:
#if defined(KRB5_TC_OPENCLOSE)
	krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
#endif
	krb5_cc_close(context, ccache);
out_free_context:
	krb5_free_context(context);
	return ret;
}
Ejemplo n.º 5
0
Archivo: chpw.c Proyecto: aosm/Kerberos
krb5_error_code 
krb5int_rd_setpw_rep( krb5_context context, krb5_auth_context auth_context, krb5_data *packet,
     int *result_code, krb5_data *result_data )
{
    char *ptr;
    unsigned int message_length, version_number;
    krb5_data ap_rep;
    krb5_ap_rep_enc_part *ap_rep_enc;
    krb5_error_code ret;
    krb5_data cipherresult;
    krb5_data clearresult;
    krb5_keyblock *tmpkey;
/*
** validate the packet length -
*/
    if (packet->length < 4)
	return(KRB5KRB_AP_ERR_MODIFIED);

    ptr = packet->data;

/*
** see if it is an error
*/
    if (krb5_is_krb_error(packet)) {
	krb5_error *krberror;
	if ((ret = krb5_rd_error(context, packet, &krberror)))
	    return(ret);
	if (krberror->e_data.data  == NULL) {
	    ret = ERROR_TABLE_BASE_krb5 + (krb5_error_code) krberror->error;
	    krb5_free_error(context, krberror);
	    return (ret);
	}
	clearresult = krberror->e_data;
	krberror->e_data.data  = NULL; /*So we can free it later*/
	krberror->e_data.length = 0;
	krb5_free_error(context, krberror);
		
    } else { /* Not an error*/

/*
** validate the message length -
** length is big endian 
*/
	message_length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
	ptr += 2;
/*
** make sure the message length and packet length agree -
*/
	if (message_length != packet->length)
	    return(KRB5KRB_AP_ERR_MODIFIED);
/*
** get the version number -
*/
	version_number = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
	ptr += 2;
/*
** make sure we support the version returned -
*/
/*
** set password version is 0xff80, change password version is 1
*/
	if (version_number != 1 && version_number != 0xff80)
	    return(KRB5KDC_ERR_BAD_PVNO);
/*
** now fill in ap_rep with the reply -
*/
/*
** get the reply length -
*/
	ap_rep.length = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
	ptr += 2;
/*
** validate ap_rep length agrees with the packet length -
*/
	if (ptr + ap_rep.length >= packet->data + packet->length)
	    return(KRB5KRB_AP_ERR_MODIFIED);
/*
** if data was returned, set the ap_rep ptr -
*/
	if( ap_rep.length ) {
	    ap_rep.data = ptr;
	    ptr += ap_rep.length;

	    /*
	     * Save send_subkey to later smash recv_subkey.
	     */
	    ret = krb5_auth_con_getsendsubkey(context, auth_context, &tmpkey);
	    if (ret)
		return ret;

	    ret = krb5_rd_rep(context, auth_context, &ap_rep, &ap_rep_enc);
	    if (ret) {
		krb5_free_keyblock(context, tmpkey);
		return(ret);
	    }

	    krb5_free_ap_rep_enc_part(context, ap_rep_enc);
/*
** now decrypt the result -
*/
	    cipherresult.data = ptr;
	    cipherresult.length = (packet->data + packet->length) - ptr;

	    /*
	     * Smash recv_subkey to be send_subkey, per spec.
	     */
	    ret = krb5_auth_con_setrecvsubkey(context, auth_context, tmpkey);
	    krb5_free_keyblock(context, tmpkey);
	    if (ret)
		return ret;

	    ret = krb5_rd_priv(context, auth_context, &cipherresult, &clearresult,
			       NULL);
	    if (ret)
		return(ret);
	} /*We got an ap_rep*/
	else
	    return (KRB5KRB_AP_ERR_MODIFIED);
    } /*Response instead of error*/

/*
** validate the cleartext length 
*/
    if (clearresult.length < 2) {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }
/*
** now decode the result -
*/
    ptr = clearresult.data;

    *result_code = (((ptr[0] << 8)&0xff) | (ptr[1]&0xff));
    ptr += 2;

/*
** result code 5 is access denied
*/
    if ((*result_code < KRB5_KPASSWD_SUCCESS) || (*result_code > 5))
    {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }
/*
** all success replies should be authenticated/encrypted
*/
    if( (ap_rep.length == 0) && (*result_code == KRB5_KPASSWD_SUCCESS) )
    {
	ret = KRB5KRB_AP_ERR_MODIFIED;
	goto cleanup;
    }

    if (result_data) {
	result_data->length = (clearresult.data + clearresult.length) - ptr;

	if (result_data->length)
	{
	    result_data->data = (char *) malloc(result_data->length);
	    if (result_data->data)
		memcpy(result_data->data, ptr, result_data->length);
	}
	else
	    result_data->data = NULL;
    }
    ret = 0;

 cleanup:
    krb5_free_data_contents(context, &clearresult);
    return(ret);
}