/*
 * Copyright 1985, 1986, 1987, 1988, 1990, 1991 by the Massachusetts
 * Institute of Technology.
 *
 * For copying and distribution information, please see the file
 * <mit-copyright.h>.
 */

/*
 * This includes code taken from:
 * Kerberos: rd_req.c,v 4.16 89/03/22 14:52:06 jtkohl Exp
 * Kerberos: prot.h,v 4.13 89/01/24 14:27:22 jtkohl Exp
 * Kerberos: krb_conf.h,v 4.0 89/01/23 09:59:27 jtkohl Exp
 */

#include <zephyr/mit-copyright.h>
#include "zserver.h"

RCSID("$Id: kopt.c,v 1.7 2000/05/19 11:21:27 lha Exp $");

#ifdef HAVE_KRB4

#include <prot.h>

/*
 * Cache of key schedules
 */

#define HASH_SIZE_1	255	/* not a power of 2 */
#define HASH_SIZE_2	3
static unsigned long last_use;
typedef struct {
    unsigned long last_time_used;
    des_cblock key;
    Sched schedule;
} KeySchedRec;
static KeySchedRec scheds[HASH_SIZE_1][HASH_SIZE_2];

Sched *
check_key_sched_cache(des_cblock key)
{
    unsigned int hash_value = key[0] + key[1] * 256;
    KeySchedRec *rec = scheds[hash_value % HASH_SIZE_1];
    int i;

    for (i = HASH_SIZE_2 - 1; i >= 0; i--) {
	if (rec[i].last_time_used && key[0] == rec[i].key[0]
	    && !memcmp(key, rec[i].key, sizeof(des_cblock))) {
	    rec[i].last_time_used = last_use++;
	    return &rec[i].schedule;
	}
    }
    return 0;
}

void
add_to_key_sched_cache(des_cblock key, Sched *sched)
{
    unsigned int hash_value = key[0] + key[1] * 256;
    KeySchedRec *rec = scheds[hash_value % HASH_SIZE_1];
    int i, oldest = HASH_SIZE_2 - 1;

    for (i = HASH_SIZE_2 - 1; i >= 0; i--) {
	if (rec[i].last_time_used == 0) {
	    oldest = i;
	    break;
	}
	if (rec[i].last_time_used < rec[oldest].last_time_used)
	    oldest = i;
    }
    memcpy (rec[oldest].key, key, sizeof(des_cblock));
    rec[oldest].schedule = *sched;
    rec[oldest].last_time_used = last_use++;
}

int
krb_find_ticket(KTEXT authent, KTEXT ticket)
{
    char *ptr;		/* For stepping through */

    /* Check for bogus length. */
    if (authent->length <= 0)
	return RD_AP_MODIFIED;

    ptr = (char *) authent->dat;

    /* check version */
    if (KRB_PROT_VERSION != (unsigned int) *ptr++)
        return RD_AP_VERSION;

    /* Make sure msg type is ok. */
    switch (*ptr++ & ~1) {
    case AUTH_MSG_APPL_REQUEST:
    case AUTH_MSG_APPL_REQUEST_MUTUAL:
        break;
    default:
        return RD_AP_MSG_TYPE;
    }

    ptr++;			/* skip server key version */
    ptr += strlen(ptr) + 1;     /* skip the realm "hint" */

    /* Get ticket from authenticator */
    ticket->length = (int) *ptr++;
    if ((ticket->length + (ptr + 1 - (char *) authent->dat)) > authent->length)
	return RD_AP_MODIFIED;
    memcpy((char *)(ticket->dat),ptr+1,ticket->length);

    return RD_AP_OK;
}

#endif /* HAVE_KRB4 */
