/* $Id: audutils.c,v 1.23 1998/06/12 18:40:57 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.
 *
 *  Auditing routines for server
 *
 *  Authors: Ariel Futoransky && Emiliano Kargieman, CORE SDI S.A.
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <fcntl.h>
#include <signal.h>
#include <netdb.h>
#include <time.h>
#include "audit.h"
#include "syslogd.h"
#include "randpool.h"
#include "au_proto.h"

#define SERVER_KEYFILE "/var/ssyslog/.key"
#define SERVER_RANDFILE "/var/ssyslog/.rand"
#define BUFSZ	128

extern struct filed *Files;
extern int Debug;

struct au_key audit_k;

int
audit_init ()
{
	int fd;

	rand_open (SERVER_RANDFILE);
	if ((fd = open (SERVER_KEYFILE, O_RDONLY)) < 0)
		return (-1);
	read (fd, &audit_k, sizeof (audit_k));
	audit_k.keylen = ntohl (audit_k.keylen);
	close (fd);

	return (0);
}

int
audit_auth (int fd, struct in_addr *s)
{
	struct hostent *he;

	time_t r[2];

	if ((he = gethostbyaddr ((char *) s, sizeof (struct in_addr), AF_INET)) == NULL)
		{
			logerror ("Hostname lookup error");
			return (0);
		}
/*
   if(strncmp(he->h_name, audit_k.host, 15))
   {
   logerror("Audit host mismatch");
   return(0);
   }
 */

	rand_get ((char *) &r, sizeof (r));
	if (authpeer (fd, (char *) &audit_k.key, audit_k.keylen, r) != 0)
		{
			logerror ("Cryptographic Auth failed");
			return (0);
		}


	return (1);
}

void
WAIT_CHILD (int s)
{
	int i;
	wait (&i);
}

int
doreopen (s)
		 struct au_proto *s;
{
	struct filed *f;


	for (f = Files; f; f = f->f_next)
		{
			if (f->f_authproto == s)
				{
					close (f->f_file);
					if ((f->f_file =
							 open (f->f_un.f_fname, O_WRONLY | O_APPEND | O_CREAT | O_TRUNC, 0)) < 0)
						{
							f->f_file = F_UNUSED;
							logerror (f->f_un.f_fname);
						}
					fchmod (f->f_file, S_IRUSR | S_IWUSR);

				}
		}


}

int
do_audit (int fd)
{
	char buf[AU_CMDSZ];
	int cmd;
	int c, n;
	char inibuf[MAXAUTHBUF];
	struct fqueue
		{
			char file[MAXPATHLEN];
			struct fqueue *next;
		}
	 *fqi = NULL;
	struct fqueue *fq, *fqu;
	int pid, todo = 0, done = 0;
	struct filed *f;
	time_t now;


	while (!done && ((cmd = au_getcmd (fd)) > 0))
		{
			switch (cmd)
				{
				case AU_GETLOGS:
					n = 0;
					for (f = Files; f; f = f->f_next)
						n++;
					f = Files;
					au_putfnum (fd, n);
					while (f)
						{
							au_putfiled (fd, f);
							f = f->f_next;
						}
					break;

				case AU_AUDIT:
					if ((fq = (struct fqueue *) malloc (sizeof (struct fqueue))) == NULL)
						  return -1;


					c = au_getfnum (fd);

					au_getauthbuf (fd, inibuf);
					f = Files;
					while (f && c--)
						f = f->f_next;

					if (!f || f->f_type != F_FILE)
						{
							au_putcmd (fd, AU_ERROR_NOFILE);
							break;
						}

					strncpy (fq->file, f->f_un.f_fname, MAXPATHLEN - 5);
					strcat (fq->file, ".old");
					fq->file[MAXPATHLEN - 1] = 0;
					if (rename (f->f_un.f_fname, fq->file) != 0)
						{
							free (fq);
							au_putcmd (fd, AU_ERROR_BACKUP);
							break;
						}
					doreopen (f->f_authproto);
					memcpy (f->f_authproto->buf, inibuf, MAXAUTHBUF);
					(void) time (&now);
					strncpy (f->f_lasttime, ctime (&now) + 4, 15);
					f->f_lasttime[15] = 0;
					strncpy (f->f_prevhost, audit_k.host, sizeof (f->f_prevhost));
					f->f_prevline[0] = 0;
					f->f_prevlen = 0;
					f->f_prevcount = f->f_repeatcount = 0;
#ifdef SYSKLOGD
					fprintlog (f, audit_k.host, 0, AUTH_INITMSG);
#else
					fprintlog (f, 0, AUTH_INITMSG);
#endif
					au_putcmd (fd, AU_OK);
					fq->next = fqi;
					fqi = fq;

					break;

				case AU_END:
					done = 1;
					break;
				}
		}

/* Actually send the files here in the child, to avoid 
 * using too much parent time on this issue
 */
	alarm (0);

	if ((pid = fork ()) < 0)
		{
			return (-1);
		}
	else if (pid == 0)
		{
			int f, g;
			long lo;
			char bf[BUFSZ];

			signal (SIGALRM, SIG_IGN);

			for (fq = fqi; fq; fq = fq->next)
				{
					if ((f = open (fq->file, O_RDONLY)) < 0)
						{
							logerror ("Secure Syslog: Couldn't open backup for auditing");
							f = -1;
						}

					au_putcmd (fd, AU_OK);
					au_putfile (fd, f);
					close (f);
				}
			for (fq = fqi; fq;)
				{
					fqu = fq->next;
					free (fq);
					fq = fqu;
				}
			close (fd);
			exit (0);
		}
	else
		{
			for (fq = fqi; fq;)
				{
					fqu = fq->next;
					free (fq);
					fq = fqu;
				}
		}
	return (0);
}
