/*
 * SNK support functions
 *
 * Part of the SNK extension to logdaemon
 *
 * Written by William LeFebvre, Argonne National Laboratory
 */

#include <stdio.h>
#include <string.h>

#include "snk.h"

/*
 * int oatoi(char *s)
 *	Convert a string of octal characters into a number.
 *	This function scans the entire string and does no error checking.
 *	STATIC INTERNAL FUNCTION.
 */

static int oatoi(s)

char *s;

{
    register int val = 0;
    register int ch;

    while ((ch = *s++) != '\0')
    {
	val <<= 3;
	val |= (ch - '0');
    }
    return(val);
}

/*
 * We need to remember the challenge string so that we can verify
 * the response.  The following static area is used to save the challenge
 * string.
 */

static char challbuf[32];	/* challenge string */
static int challenged;		/* flag indicating challenge was offered */

/*
 * char *snk_challenge()
 *	return a string suitable for use as an SNK challenge
 */

char *snk_challenge()

{
    challenged = 1;
    sprintf(challbuf, "%6.6lu", randomnumber(3) % 1000000);
    return(challbuf);
}

/*
 * int snk_verify(struct snkent *snk, char *response)
 *	Verify that "response" is valid for previously issued challenge
 *	using card described by "snk".  Value returned is either zero
 *	(accept) or non-zero (reject).
 */

int snk_verify(snk, response)

struct snkent *snk;
char *response;

{
    unsigned char key[8];
    unsigned char data[8];
    char buf[64];
    register int i;
    register char *p;

    /* convert text key (ascii) in to binary */
    p = strtok(snk->key, " ");
    for (i = 0; i < 8; i++)
    {
	/* bad keys always fail */
	if (p == 0)
	    return(0);
	key[i] = (unsigned char)oatoi(p);
	p = strtok((char *) 0, " ");
    }
    /* bad keys always fail */
    if (p != 0)
	return(0);

    /* copy over challenge string */
    if (!challenged)
    {
	/* challenge never issued - we can't proceed */
	return(0);
    }
    strncpy((char *)data, challbuf, 6);
    data[6] = data[7] = '\0';

    /* encrypt the challenge */
    snk_encrypt(data, key);

    /* convert result into a hex string */
    sprintf(buf, "%02x%02x%02x%02x", data[0], data[1], data[2], data[3]);

    /* check result against the response we were given */
    if(strcasecmp(response, buf) == 0)
    {
	/* perfect match! */
	return(1);
    }

    /* it didn't match: it may be that the result was given in
       decimal only mode, so "massage" our result into decimal
       and try again */
    for(i=0; buf[i]; i++)
    {
	if(buf[i] == 'a' || buf[i] == 'b' || buf[i] == 'c')
	{
	    buf[i] = '2';
	}
	else
	{
	    if(buf[i] == 'd' || buf[i] == 'e' || buf[i] == 'f')
	    {
		buf[i] = '3';
	    }
	}
    }

    /* return true or false accordingly */
    return(strcmp(response, buf) == 0);
}
