/* $Id: auth.c,v 1.25 1998/06/12 18:40:58 iarce Exp $
 * Secure Syslog daemon
 * CORE SDI S.A. Buenos Aires, Argentina. 1998
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES
 * ARE DISCLAIMED. IN NO EVENT SHALL CORE SDI S.A. BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES RESULTING
 * FROM THE USE OR MISUSE OF THIS SOFTWARE.
 *
 * Authentication routines for Secure Syslog.
 *
 * Author: Emiliano Kargieman && Ariel Futoransky,  CORE SDI S.A.
 */

#include "syslogd.h"
#define MAXPATHNAME 128
#define BUFSZ	1024


#include <sys/stat.h>
#include <stdio.h>
#include "sha1.h"
#include "cryutils.h"
#include "randpool.h"

extern struct filed *Files;

static struct au_proto au_protos[3] =
{
	{"none", AUP_NONE, 0, "", (_au_method *) & none},
	{"peo", AUP_PEO, 0, "", (_au_method *) & peo},
	{NULL, 0, 0, "", NULL}};


int
au_getproto (char *prot, struct au_proto *p)
{
	int i;
	for (i = 0; au_protos[i].name != NULL; i++)
		if (!strcmp (au_protos[i].name, prot))
			{
				memcpy (p, &au_protos[i], sizeof (struct au_proto));
				break;
			}
	if (au_protos[i].name == NULL)
		return (-1);
	return (0);
}


char *
redo_line (struct filed *f, struct iovec *iov)
{
	static char buf[MAXLINE + 5];

	snprintf (buf, MAXLINE + 2, "%s%s%s%s%s", iov[0].iov_base, iov[1].iov_base, iov[2].iov_base, iov[3].iov_base, iov[4].iov_base);
	switch (f->f_type)
		{
		case F_TTY:
			strcat (buf, "\r");
			break;
		case F_FILE:
			break;
		default:
			snprintf (buf, MAXLINE + 3, "Unrecognized type %d for secure authentication", f->f_type);
			break;
		}
	strcat (buf, "\n");
	return (buf);
}

struct au_proto *
getauthproto (s, proto)
		 char *s;
		 char *proto;
{
	int i;
	struct filed *f;
	struct au_proto *p;
	char name[MAXPATHNAME + 1];
	static struct au_proto unused;

	if (!strcmp (proto, "UNUSED"))
		{
			unused.fd = -1;
			unused.proto = 0;
			return (&unused);
		}



	for (f = Files; f && (f->f_type != F_FILE || f->f_authproto == NULL ||
						 strncmp (f->f_un.f_fname, s, MAXPATHNAME - 1)); f = f->f_next);

	for (i = 0; au_protos[i].name != NULL; i++)
		if (!strcmp (au_protos[i].name, proto))
			break;
	if (au_protos[i].name == NULL)
		i = 0;

	if (f == NULL)
		{
			if ((p = (struct au_proto *) malloc (sizeof (struct au_proto))) == NULL)
				  return (NULL);

			memcpy (p, &au_protos[i], sizeof (struct au_proto));
			strcpy (name, AUTHPATH);
			SCAT (name, cv_name (s), MAXPATHNAME );
			name[MAXPATHNAME] = 0;	
			if (i == AUP_PEO)								/* peo */
				{
					if ((p->fd = open (name, O_RDWR | O_CREAT)) < 0)
						p->fd = -1;
					read (p->fd, p->buf, sizeof (p->buf));
				}
			return (p);
		}
	else
  {
		if (i != f->f_authproto->proto )
		{
			snprintf(name, MAXPATHNAME - 1, 
				"Warning logging to file %s with more than one protocol", s);
			errno = 0;
			logerror(name);
		}
		return (f->f_authproto);
  }
}

int
none (int action, struct filed *fi, char *buf, int *len)
{
	return (0);
}


int
peo (int action, struct filed *fi, char *buf, int *len)
{
	AU_PEO_LOG *log = (AU_PEO_LOG *) & fi->f_authproto->buf;
	SHA1_CTX sha1x;
	u_char digest[SHA1_DIGESTSIZE];
	char name[MAXPATHNAME];
	char chunk[SHA1_BLOCKSIZE];
	struct stat st;
	char *msg;
	int i, cnt;

	switch (action)
		{
		case AU_OPEN:
			break;
		case AU_UPDATE:
			msg = redo_line (fi, (struct iovec *) buf);
#ifdef NO_MEMCPY
			for (i=0;i<sizeof(digest);i++)
				((char *)&digest)[i]=((char *)&log->sha1digest)[i];
#else
			log=log;
			memcpy ((char *)&digest, (char *) &(log->sha1digest), sizeof (digest));
#endif /* NO_MEMCPY */
			memset (chunk, '\0', sizeof (chunk));
			cnt = strlen (msg);
			while (cnt > 0)
				{
					for (i = 0; i < SHA1_BLOCKSIZE && i < cnt; i++)
						chunk[i] = *(msg + i) ^ digest[i % SHA1_DIGESTSIZE];
					SHA1Init (&sha1x);
					SHA1Update (&sha1x, chunk, SHA1_BLOCKSIZE);
					HTONDIGEST (sha1x.state);
					memcpy ((char *) &digest, (char *) &sha1x.state, sizeof (digest));
					msg += i;
					cnt -= i;
				}
			NTOHDIGEST (sha1x.state);
			SHA1Final ((char *) &digest, &sha1x);
#ifdef NO_MEMCPY
			for (i=0;i<sizeof(digest);i++)
				((char *)&log->sha1digest)[i]=((char *)&digest)[i];
#else
			memcpy ((char *) &log->sha1digest, &digest, sizeof (log->sha1digest));
#endif /* NO_MEMCPY */
			lseek (fi->f_authproto->fd, 0, SEEK_SET);
			write (fi->f_authproto->fd, log, sizeof (AU_PEO_LOG));
			break;
			if (rand_need ())
				rand_add (msg, strlen (msg));
		case AU_CLOSE:
			close (fi->f_authproto->fd);
			break;
		}
	return (0);
}
