/* $Id: au_proto.c,v 1.5 1998/06/12 18:40:54 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, CORE SDI S.A.
 */

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

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



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


char *
au_getprotoname (p)
		 int p;
{
	int i;

	for (i = 0; au_protos[i].name != NULL; i++)
		if (au_protos[i].proto == p)
			return (au_protos[i].name);
	return ("UNKNOWN");
}

char *
cv_name (char *name)
{
	static char buf[MAXPATHNAME];
	char *p;

	strncpy (buf, name, MAXPATHNAME - 1);
	buf[MAXPATHNAME - 1] = 0;
	while ((p = strchr (buf, '/')) != NULL)
		*p = '.';
	return (buf);
}


int
au_putcmd (fd, cmd)
		 int fd;
		 int cmd;
{
	cput_int32 (fd, cmd);
	cflushout (fd);
	cput_int32 (fd, cmd + 1);
	cflushout (fd);
}

int
au_getcmd (fd)
{
	int i;

	i = cget_int32 (fd);
	cflushin (fd);
	if (i + 1 != cget_int32 (fd))
		i = -1;
	cflushin (fd);

	return (i);
}

int
au_getfiled (fd, f)
		 int fd;
		 struct filed *f;
{
	struct au_proto *p;

	f->f_next = (struct filed *) cget_int32 (fd);
	f->f_type = cget_int32 (fd);
	f->f_file = cget_int32 (fd);
	f->f_time = cget_int32 (fd);
	cread (fd, (char *) &f->f_pmask, sizeof (f->f_pmask));
	cread (fd, (char *) &f->f_un, sizeof (f->f_un));
	cget_str (fd, (char *) &f->f_prevline, sizeof (f->f_prevline));
	cget_str (fd, (char *) &f->f_lasttime, sizeof (f->f_lasttime));
	cget_str (fd, (char *) &f->f_prevhost, sizeof (f->f_prevhost));
	f->f_prevpri = cget_int32 (fd);
	f->f_prevlen = cget_int32 (fd);
	f->f_prevcount = cget_int32 (fd);
	f->f_repeatcount = cget_int32 (fd);
	f->f_authtime = cget_int32 (fd);

	f->f_iamnew = cget_int32 (fd);
	/* struct auth_proto */
	if (cget_int32 (fd) != 0)
		{
			if ((p = (struct au_proto *) malloc (sizeof (struct au_proto))) == NULL)
				  return (-1);
			memset ((char *) p, 0, sizeof (p));

			p->name = (char *) cget_int32 (fd);
			p->proto = cget_int32 (fd);
			p->fd = cget_int32 (fd);
			cread (fd, p->buf, sizeof (p->buf));
			p->method = (_au_method *) cget_int32 (fd);

			f->f_authproto = p;
		}
	else
		f->f_authproto = NULL;

	cflushin (fd);
	return (0);
}

int
au_putfiled (fd, f)
		 int fd;
		 struct filed *f;
{
	cput_int32 (fd, (u_int32_t) f->f_next);
	cput_int32 (fd, (u_int32_t) f->f_type);
	cput_int32 (fd, (u_int32_t) f->f_file);
	cput_int32 (fd, (u_int32_t) f->f_time);
	cwrite (fd, (char *) &f->f_pmask, sizeof (f->f_pmask));
	cwrite (fd, (char *) &f->f_un, sizeof (f->f_un));
	cput_str (fd, (char *) &f->f_prevline);
	cput_str (fd, (char *) &f->f_lasttime);
	cput_str (fd, (char *) &f->f_prevhost);
	cput_int32 (fd, (u_int32_t) f->f_prevpri);
	cput_int32 (fd, (u_int32_t) f->f_prevlen);
	cput_int32 (fd, (u_int32_t) f->f_prevcount);
	cput_int32 (fd, (u_int32_t) f->f_repeatcount);
	cput_int32 (fd, (u_int32_t) f->f_authtime);

	cput_int32 (fd, (u_int32_t) f->f_iamnew);
	/* struct auth_proto */
	cput_int32 (fd, (u_int32_t) f->f_authproto);
	if (f->f_authproto)
		{
			cput_int32 (fd, (u_int32_t) f->f_authproto->name);
			cput_int32 (fd, (u_int32_t) f->f_authproto->proto);
			cput_int32 (fd, (u_int32_t) f->f_authproto->fd);
			cwrite (fd, f->f_authproto->buf, sizeof (f->f_authproto->buf));
			cput_int32 (fd, (u_int32_t) f->f_authproto->method);
		}
	cflushout (fd);
	return (0);
}

int
au_putfnum (fd, n)
		 int fd;
		 int n;
{
	cput_int32 (fd, n);
	cflushout (fd);
}

int
au_getfnum (fd)
{
	int i;

	i = cget_int32 (fd);
	cflushin (fd);
	return (i);
}

int
au_putauthbuf (fd, buf)
		 int fd;
		 char *buf;
{
	cwrite (fd, buf, MAXAUTHBUF);
	cflushout (fd);
	return (0);
}

int
au_getauthbuf (fd, buf)
		 int fd;
		 char *buf;
{
	cread (fd, buf, MAXAUTHBUF);
	cflushin (fd);
	return (0);
}

int
au_putfile (fd, f)
		 int fd, f;
{
	char buf[BUFSZ];
	int len, l, tot;

	tot = len = lseek (f, 0, SEEK_END);
	cput_int32 (fd, len);
	cflushout (fd);
	lseek (f, 0, SEEK_SET);

	while (len > 0)
		{
			l = (len > BUFSZ) ? BUFSZ : len;
			read (f, buf, l);
			cwrite (fd, buf, l);
			len -= l;
		}
	cflushout (fd);
	return (tot);
}

int
au_getfile (fd, f)
		 int fd, f;
{
	char buf[BUFSZ];
	int len, l, tot;

	tot = len = cget_int32 (fd);
	cflushin (fd);
	while (len > 0)
		{
			l = (len > BUFSZ) ? BUFSZ : len;
			cread (fd, buf, l);
			write (f, buf, l);
			len -= l;
		}
	cflushin (fd);
	return (tot);
}

int
au_getfilepeo (fd, f, k)
		 int fd, f;
		 u_char *k;

{
	char buf[BUFSZ + 1];
	int i, j, len, l, tot;
	char c;
	char chunk[SHA1_BLOCKSIZE];
	SHA1_CTX sha1x;

	tot = len = cget_int32 (fd);

	cflushin (fd);
	cread (fd, &c, 1);
	while (len > 0)
		{
			l = 0;
			while (c != '\n' && (len > 0) && (l < BUFSZ))
				{
					buf[l++] = c;
					len--;
					if (len > 0)
						cread (fd, &c, 1);
				}
			if (c == '\n')
				{
					buf[l++] = c;
					buf[l] = '\0';
					len--;
					if (len > 0)
						cread (fd, &c, 1);
				}
			write (f, buf, l);
			memset (chunk, 0, sizeof (chunk));
			memcpy ((char *) &sha1x.state, k, SHA1_DIGESTSIZE);

			j = 0;
			for (i = 0; i < l; i++)
				{
					chunk[(i % SHA1_BLOCKSIZE)] = buf[i] ^
						(((char *) &sha1x.state)[(i % SHA1_BLOCKSIZE) % SHA1_DIGESTSIZE]);

					if (i % SHA1_BLOCKSIZE == SHA1_BLOCKSIZE - 1)
						{
							SHA1Init (&sha1x);
							SHA1Update (&sha1x, chunk, SHA1_BLOCKSIZE);
							HTONDIGEST (sha1x.state);
						}
				}
			if (i % SHA1_BLOCKSIZE != 0)
				{
					SHA1Init (&sha1x);
					SHA1Update (&sha1x, chunk, SHA1_BLOCKSIZE);
				}
			else
				NTOHDIGEST (sha1x.state);

			SHA1Final (k, &sha1x);

		}
	cflushin (fd);
	return (tot);
}
