/*$Id: audit.c,v 1.30 1998/06/12 18:40:55 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.
 *
 */
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdio.h>
#include <netdb.h>
#include "audit.h"
#include "syslogd.h"
#include <fcntl.h>
#include "syslog.h"
#include <time.h>
#include "cryutils.h"
#include "au_proto.h"
#include "randpool.h"
#include "sha1.h"

#define LPATH	"/audit/"
#define MAXPATHNAME	256

extern char *optarg;
extern int optind;

int DownLoadAll = 0;
int YesToAll = 0;
int verbose = 1;
int sock;

struct filed *FIL;
int FILN = 0;

char destpath[MAXPATHNAME + 1];

struct fqueue
	{
		int fd;
		AU_PEO_LOG k0;
		struct fqueue *next;
	}
 *fq = NULL;

char *dedecode (int, CODE *);


void
usage (void)
{
	printf ("Usage: audit [-a] [-q] [-c host[:logfile]] | -r data_file |-n host | ]\n\n");
	printf ("\taudlog -r data_file			reads the specified data_file\n");
	printf ("\taudlog -c host[:logfile]] 		Check logfile@host or host config\n");
	printf ("\taudlog -n host [-y]             	Add host\n");
	printf ("\taudlog -v				Adds verbosity\n");
	printf ("\taudlog -a 				All Files, even without auth\n");
	printf ("\taudlog -q 				quiet (minimal output)\n");
	exit (-1);
}

/* returns the path for host in buf. Assumes buf is MAXPATHNAME bytes long
 */
char *
hostpath (host, buf)
		 char *host, *buf;
{
	struct hostent *h;

	if ((h = gethostbyname (host)) == NULL)
		{
			perror (host);
			return (NULL);
		}
	snprintf(buf,MAXPATHNAME - 1, "%s%s", LPATH, h->h_name);
}

static struct au_proto *
newproto (s)
		 struct au_proto *s;
{
	struct filed *f;
	struct au_proto *p;
	char name[MAXPATHNAME];

	for (f = FIL; f && (f->f_type != F_FILE ||
											f->f_authproto->fd != s->fd); f = f->f_next);

	if (f == NULL)
		{
			return s;
		}
	else
		{
			free (s);
			return (f->f_authproto);
		}
}



int
generate_key (host)
		 char *host;
{
	struct au_key s;
	char buf[MAXPATHNAME], path[MAXPATHNAME];
	int fd;

	if (gethostname (buf, MAXPATHNAME - 1) < 0)
		{
			printf ("Cannot get hostname \n");
			return (-1);
		}
	strncpy ((char *) &s.host, buf, AUD_HOSTLEN - 1);
	s.host[AUD_HOSTLEN] = '\0';
	if (hostpath (host, path) == NULL)
		return (-1);

	getrandomkey ((char *) &s.key, &s.keylen, MAXKEY);
	s.keylen = htonl (s.keylen);
	snprintf (buf, MAXPATHNAME - 1, "%s/.key", path);
	if ((fd = open (buf, O_CREAT | O_WRONLY)) < 0)
		{
			perror (buf);
			return (-1);
		}
	fchmod (fd, S_IRUSR | S_IRGRP);
	write (fd, (char *) &s, sizeof (struct au_key));
	close (fd);

	return (0);
}

/*
   int generate_keypair(host)
   char *host;
   {

   pubring_entry pub;
   privring_entry priv;
   char buf[MAXPATHNAME],path[MAXPATHNAME];
   int fd;

   gethostname(buf,MAXPATHNAME-1);
   strncpy((char *)&pub.host,buf,AUD_HOSTLEN-1);pub.host[AUD_HOSTLEN]='\0'; 
   strncpy((char *)&priv.host,host,AUD_HOSTLEN-1);priv.host[AUD_HOSTLEN]='\0'; 
   if(hostpath(host,path)==NULL) return(-1);
   snprintf(buf,MAXPATHNAME-1,"%s/.priv_ring",path);
   if((fd=open(buf, O_CREAT | O_WRONLY))<0) {
   perror(buf);
   return(-1);
   }
   fchmod(fd, S_IRUSR | S_IRGRP);
   write(fd, (char *)&priv, sizeof(privring_entry)); 
   close(fd);
   snprintf(buf,MAXPATHNAME-1,"%s/audit_pubring",LPATH);
   if((fd=open(buf, O_CREAT | O_WRONLY | O_APPEND))<0) {
   perror(buf);
   return(-1);
   }
   write(fd, (char *)&pub, sizeof(pubring_entry)); 
   close(fd); 
   return(0);
   }
 */

int
new_host (char *host)
{
	char buf[MAXPATHNAME];
	struct stat s;

	if (verbose > 0)
		fprintf (stderr, "creating host %s:", host);

	if (hostpath (host, buf) == NULL)
		return (-1);
	if (verbose > 1)
		fprintf (stderr, "making_dirs ");
	if (!stat (buf, &s))
		{
			fprintf (stderr, "File exists: %s\n", buf);
			return (-1);
		}
	if (mkdir (buf, S_IRUSR | S_IWUSR | S_IXUSR |
						 S_IRGRP | S_IWGRP | S_IXGRP))
		{
			fprintf (stderr, "Couldn't create %s\n", buf);
			return (-1);
		}
	if (verbose > 0)
		fprintf (stderr, "generating_key ");

	generate_key (host);
	if (verbose > 0)
		fprintf (stderr, "done.\n");

	return (0);
}

int
au_secureconnect (host, port)
		 int port;
		 char *host;
{
	int fd;
	int desc;
	int len;
	struct sockaddr_in saddr;
	struct hostent *hostaddr;

	u_int32_t r[2];
	struct au_key k;
	char buf[MAXPATHNAME];


	if ((hostaddr = gethostbyname (host)) == NULL)
		{
			perror ("host lookup");
			return -1;
		}

	if (verbose > 0)
		printf ("contacting host %s\n", hostaddr->h_name);
	if ((desc = socket (AF_INET, SOCK_STREAM, 0)) < 0)
		{
			perror ("socket");
			return -1;
		}

	memset ((char *) &saddr, 0, sizeof (saddr));
	saddr.sin_port = htons (port);
	saddr.sin_family = AF_INET;
	memcpy (&saddr.sin_addr, hostaddr->h_addr, hostaddr->h_length);

	if (connect (desc, (struct sockaddr *) &saddr, sizeof (saddr)) == -1)
		{
			perror ("connect");
			return -1;
		}


	snprintf (buf, MAXPATHNAME - 1, "%s%s/.key", LPATH, hostaddr->h_name);
	snprintf (destpath, MAXPATHNAME - 1, "%s", hostaddr->h_name);
	if ((fd = open (buf, O_RDONLY)) < 0)
		{

			perror ("opening keyfile");
			return (-1);
		}
	if (read (fd, &k, sizeof (k)) != sizeof (k))
		{
			perror ("reading keyfile");
			close (fd);
			return (-1);
		}
	close (fd);

	rand_get ((char *) &r, sizeof (r));

	if (authpeer (desc, (char *) &k.key, ntohl (k.keylen), r) != 0)
		{
			close (desc);
			printf ("Auth failed!\n");
			return -1;
		}

	return desc;

}

/* deparse_line     de-parses a filed structure and prints the result in a
 *                  readable way (i.e. like a syslog.conf line)
 *
 */


char *
newgetprio (p)
		 unsigned char p;
{
	static char buf[LINE_MAX + 1];
	int i, j;

	buf[0] = '\0';

	if (p == 0xff)
		return ("*");
	if (p == 0)
		return ("none");

	j = 0;
	for (i = 0; i < 8; i++)
		if (!((1 << i) & p))
			break;

	if (i > 0)
		{
			SCAT(buf, dedecode(i, prioritynames), LINE_MAX);
			j = 1;
		}

	for (; i < 8; i++)
		{
			if ((1 << i) & p)
				{
					if (j)
						SCAT (buf, ",", LINE_MAX);
					else
						j = 1;
					SCAT (buf, "=", LINE_MAX);
					SCAT (buf, dedecode (i, prioritynames), LINE_MAX);
				}
		}
	return (buf);
}

#define FACNUM(x) (facilitynames[(x)].c_val >> 3)

char *
newdeparse_line (fil)
		 struct filed *fil;

{
	static char buf[LINE_MAX + 100];
	unsigned char p, pp;
	int i, j, k;

	p = 0xff;
	buf[0] = '\0';

	for (i = 0; facilitynames[i].c_val != -1; i++)
		if ((fil->f_pmask[FACNUM (i)]) && (FACNUM (i) < LOG_NFACILITIES))
			p &= fil->f_pmask[FACNUM (i)];

	for (i = k = 0; facilitynames[i].c_val != -1; i++)
		{
			if (FACNUM (i) < LOG_NFACILITIES)

				if (fil->f_pmask[FACNUM (i)] == p)
					k++;
				else
					k--;
		}

	if (k <= 0)
		p = 0;


	if (p)
		{
			SCAT (buf, "*.", LINE_MAX);
			SCAT (buf, newgetprio (p), LINE_MAX ); 
		}

	j = p;

	for (i = 0; facilitynames[i].c_val != -1; i++)
		{
			k = FACNUM (i);
			if ((p != fil->f_pmask[k]) && (k < LOG_NFACILITIES))
				{
					if (j)
						SCAT (buf, ";", LINE_MAX );
					else
						j = 1;
					SCAT (buf, facilitynames[i].c_name, LINE_MAX);
					SCAT (buf, ".", LINE_MAX);
					if (fil->f_pmask[k] & p != p)
						{
							SCAT (buf, "none,", LINE_MAX);
							SCAT (buf, newgetprio (fil->f_pmask[k]), LINE_MAX);
						}
					else
						{
							if (strlen (newgetprio (fil->f_pmask[k])) <
									strlen (newgetprio (fil->f_pmask[k] & ~p)))
								SCAT (buf, newgetprio (fil->f_pmask[k]), LINE_MAX);
							else
								SCAT (buf, newgetprio (fil->f_pmask[k] & ~p), LINE_MAX);

						}
				}
		}
	return (buf);
}

char *
dedecode (num, codetab)
		 int num;
		 CODE *codetab;
{
	CODE *c;
	for (c = codetab; c->c_name; c++)
		if (c->c_val == num)
			return (c->c_name);

	return ("UNUSED");
}

char *
olddeparse_line (fil)
		 struct filed *fil;
{
	static char line[LINE_MAX + 1];
	int i, j, wildpri;

	memset (line, '\0', LINE_MAX - 1);
	/* hack for predicting a facility wildcard */
	if (fil->f_type == F_UNUSED)
		return ("UNUSED\n");

	wildpri = (fil->f_pmask[15]);
	if ((wildpri != 0) && (wildpri != INTERNAL_NOPRI) && (wildpri != 0xff))
		{
			SCAT (line, "*.", LINE_MAX);
			SCAT (line, dedecode (wildpri, prioritynames), LINE_MAX);
			SCAT (line, ";", LINE_MAX);
		}
	/* end of hack */
	for (i = 0; i < LOG_NFACILITIES; i++)
		if (fil->f_pmask[i] != wildpri)
			{
				SCAT (line, dedecode (i << 3, facilitynames), LINE_MAX );
				SCAT (line, ".", LINE_MAX );
				if (fil->f_pmask[i] != LOG_PRIMASK + 1)
					SCAT (line, dedecode (fil->f_pmask[i], prioritynames), LINE_MAX);
				else
					SCAT (line, "*", LINE_MAX );
				SCAT (line, ";", LINE_MAX );
			}
	line[LINE_MAX ] = '\0';
	return (line);
}

char *
deparse_line (fil)
		 struct filed *fil;
{
	int j;
	static	char buf [ LINE_MAX + 1 ];

	if (!fil) return ("");

	if (fil->f_authproto)
		{
			if (fil->f_iamnew == 0)
				snprintf(buf, LINE_MAX,"%-40s [%-4s] ", 
					olddeparse_line(fil), 
					au_getprotoname(fil->f_authproto->proto)); 
			else
				snprintf(buf, LINE_MAX,"%-40s [%-4s] ", 
					newdeparse_line(fil),
					au_getprotoname(fil->f_authproto->proto)); 
		} else
	if (fil->f_iamnew == 0)
		snprintf(buf, LINE_MAX,"%-40s [%-4s] ", olddeparse_line(fil), "none"); 
	else
		snprintf(buf, LINE_MAX,"%-40s [%-4s] ", newdeparse_line(fil), "none");

	switch (fil->f_type)
		{
		case F_FILE:
		case F_TTY:
		case F_CONSOLE:
			SCAT (buf, fil->f_un.f_fname, LINE_MAX);
			break;
		case F_USERS:
			for (j = 0; *fil->f_un.f_uname[j] && j < MAXUNAMES; j++)
				{
					if (j > 0)
						SCAT (buf, ", ", LINE_MAX);
					SCAT (buf, fil->f_un.f_uname[j], LINE_MAX);
				}
				break;
		case F_FORW:
			SCAT (buf, "@", LINE_MAX );
			SCAT (buf, fil->f_un.f_forw.f_hname, LINE_MAX );
				break;
		}
	SCAT (buf, "\n", LINE_MAX );
  return(buf);
}

int
writefilp (fd, f)
		 int fd;
		 struct filed *f;
{
	if (write (fd, f, sizeof (*f)) < 0)
		return (-1);
	if (write (fd, f->f_authproto, sizeof (*f->f_authproto)) < 0)
		return (-1);
	return (0);
}

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

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

	if ((read (fd, f, sizeof (*f)) != sizeof (*f)) ||
			(read (fd, p, sizeof (*p)) != sizeof (*p)))
		{
			free (f);
			free (p);
			return (NULL);
		}
	f->f_authproto = p;
	f->f_file = 1;

	return (f);
}

/* dump_config  dumps configuration data to disk. 
 *              renames last configuration to *.old
 */
int
dump_config (host, fil)
		 char *host;
		 struct filed *fil;
{
	struct filed *filp;
	char buf[MAXPATHNAME + 1], bup[MAXPATHNAME + 1];
	int d;
	struct stat st;
	int new = 1;

	if (hostpath (host, buf) == NULL)
		return (-1);
	SCAT (buf, "/syslog-config.data", MAXPATHNAME);
	buf[MAXPATHNAME] = '\0';
	strncpy (bup, buf, MAXPATHNAME-1 );
	SCAT (bup, ".old", MAXPATHNAME );
	bup[MAXPATHNAME] = '\0';
	if (!stat (buf, &st))
		{
			if (rename (buf, bup) < 0)
				{
					perror (bup);
					return (-1);
				}
			new = 0;
		}
	if ((d = open (buf, O_WRONLY | O_CREAT)) < 0)
		{
			perror (buf);
			return -1;
		}
	fchmod (d, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
	filp = fil;
	while (filp)
		{
			if (writefilp (d, filp) < 0)
				{
					perror ("writing config\n");
					return (-1);
				}
			if (new && verbose)
				printf (deparse_line (filp));
			filp = filp->f_next;
		}
	close (d);
}



/* compare_configs  compare the last configuration with the actual 
 *                  config and report any changes.
 *                  (compares f_un, f_type, f_pmask, f_authproto->proto)
 */
int
compare_configs (host, fil)
		 char *host;
		 struct filed *fil;
{
	struct filed *old_fil = NULL, *filp, *old_filp = NULL;
	int oldcount = 0;
	int d, match, deltas = 0, count = 0;
	char buf[MAXPATHNAME];
	struct stat st;

	if (hostpath (host, buf) == NULL)
		return (-1);
	SCAT (buf, "/syslog-config.data", MAXPATHNAME);
	buf[MAXPATHNAME - 1] = '\0';
	if (stat (buf, &st))
		{
			printf ("Previous config data wasn't found, is this a new host?\n");
			return (1);
		}
	if ((d = open (buf, O_RDONLY)) < 0)
		{
			perror (buf);
			return (-1);
		}
	while (filp = readfilp (d))
		{
			filp->f_next = old_filp;
			old_filp = filp;
			oldcount++;
		}
	close (d);

	/* got old one, start comparing and stuff */
	for (fil = FIL; fil; fil = fil->f_next)
		{
			match = 0;
			for (filp = old_filp; filp; filp = filp->f_next)
				if ((filp->f_type == fil->f_type) &&
						(!memcmp ((char *) &(filp->f_un), (char *) &(fil->f_un)
											,sizeof (fil->f_un))) &&
						(!memcmp (filp->f_pmask, fil->f_pmask, sizeof (fil->f_pmask))) &&
						(filp->f_authproto->proto == fil->f_authproto->proto) &&
						(filp->f_file != 0))
					{
						match = 1;
						filp->f_file = 0;
						break;
					}
			if (!match || verbose)
				printf (deparse_line (fil));
			fflush (stdout);
			if (!match)
				{
					fprintf (stdout, "           ^\n");
					fprintf (stdout, "           |____ THIS LINE IS NEW OR CHANGED (%d)!\n\n", count);
					deltas++;
				}
			count++;
		}
	if (count != oldcount || deltas > 0)
/*      if(count-deltas < oldcount)  stochastic extrapiration */
		{
			if (verbose)
				fprintf (stderr, "\n\nWARNING WARNING WARNING WARNING WARNING\n");
			fprintf (stderr, "WARNING %.2d lines were unmatched WARNING\n", deltas);
			if (verbose)
				fprintf (stderr, "WARNING WARNING WARNING WARNING WARNING\n");
			return (1);
		}
	for (fil = old_fil; fil; filp = fil)
		{
			fil = fil->f_next;
			free (filp->f_authproto);
			free (filp);

		}
	return (0);
}

int
list_config (host, i)
	char *host;
	int i;
{
	char buf[MAXPATHNAME + 1];

	if (i)
		printf ("[%s] (old)\n", host); else
		printf ("[%s]\n", host);
	
	if (hostpath (host, buf) == NULL)
		return (-1);
	if (i)
		SCAT (buf, "/syslog-config.data.old", MAXPATHNAME); else
		SCAT (buf, "/syslog-config.data", MAXPATHNAME);
	buf[MAXPATHNAME] = '\0';
	return (parse_d_file (buf));
}


int
parse_d_file (file)
		 char *file;
{
	struct filed *fil;
	int d;

	if ((d = open (file, O_RDONLY)) < 0)
		{
			perror (file);
			return 1;
		}
	while (fil = readfilp (d))
		{
			printf ("%s",deparse_line (fil));
			free(fil);
		}
	close (d);
	return (0);
}


int
au_sync (host)
		 char *host;
{
	int n;
	struct filed *filp;

	if ((sock = au_secureconnect (host, AUDIT_PORT)) < 0)
		{
			fprintf (stderr, "can't connect\n");
			return -1;
		}

	au_putcmd (sock, AU_GETLOGS);
	FILN = au_getfnum (sock);
	FIL = NULL;

	n = FILN;
	while (n > 0)
		{
			if ((filp = (struct filed *) malloc (sizeof (struct filed))) == NULL)
				{
					perror ("malloc");
					return (-1);
				}
			memset (filp, '\0', sizeof (struct filed));
			au_getfiled (sock, filp);
			filp->f_next = FIL;
			FIL = filp;
			n--;
		}

	return (compare_configs (host, FIL) * dump_config (host, FIL));
}

struct filed *
get_filenum (i)
		 int i;
{
	struct filed *f;



	for (f = FIL; f && i < FILN - 1; f = f->f_next)
		i++;
	return (f);
}

int
get_fileno (s)
		 char *s;
{
	struct filed *f;
	int i;

	i = FILN - 1;
	for (f = FIL;
		f && strncmp ((char *) &f->f_un.f_fname, s, MAXPATHNAME); f = f->f_next)
		{
			i--;
		}

	return (i);
}

int
do_selectfile (i)
		 int i;
{
	struct filed *filp;
	struct fqueue *f;
	char inibuf[MAXAUTHBUF];
	int res;


	if ((filp = get_filenum (i)) == 0)
		{
			printf ("exiting\n");
			return (-1);
		}
	au_putcmd (sock, AU_AUDIT);
	au_putfnum (sock, i);
	rand_get (inibuf, sizeof (AU_PEO_LOG));
	au_putauthbuf (sock, inibuf);
	if ((res = au_getcmd (sock)) != AU_OK)
		{
			printf ("Received AU_ERROR: %s\n", (res == AU_ERROR_NOFILE) ? "Not a valid file" : "Can not create backup");
			return (-1);
		}
	if ((f = (struct fqueue *) malloc (sizeof (struct fqueue))) == NULL)
		  return (-1);
	f->fd = i;
	f->next = fq;
	memcpy (&f->k0, inibuf, sizeof (f->k0));
	fq = f;

	return (0);
}

char *
get_keypath (f)
		 struct filed *f;
{
	static char buf[MAXPATHNAME + 1];

	strncpy (buf, LPATH, MAXPATHNAME);
	SCAT (buf, destpath, MAXPATHNAME) ;
	SCAT (buf, "/", MAXPATHNAME );
	SCAT (buf, cv_name (f->f_un.f_fname), MAXPATHNAME);
	SCAT (buf, ".k0", MAXPATHNAME);
	return (buf);
}

char *
get_logpath (f)
		 struct filed *f;
{
	static char buf [ MAXPATHNAME + 1 ];

	strncpy (buf, LPATH, MAXPATHNAME);
	SCAT (buf, destpath, MAXPATHNAME );
	SCAT (buf, "/", MAXPATHNAME );
	SCAT (buf, cv_name (f->f_un.f_fname), MAXPATHNAME);
	return (buf);
}

char *
get_time()
{
  static char buf [ MAXPATHNAME + 1 ]; 
	time_t t;

	time (&t);
	snprintf(buf, MAXPATHNAME, "%s", ctime(&t)+4);
	if (buf[0])
    buf [ strlen(buf) - 1 ] = '\0';

	return(buf);
}


int
do_download ()
{
	int fd, fk, new;
	struct fqueue *q;
	AU_PEO_LOG k;
	u_char d[SHA1_DIGESTSIZE];
	struct filed *f;
	char buf[MAXPATHNAME + 1];
	int res;

	printf("\ndownloading files\n");
	au_putcmd (sock, AU_END);

	for (q = fq; q; q = q->next)
		{
			if ((res = au_getcmd (sock)) != AU_OK)
				printf ("(recv!=AU_OK)");

			f = get_filenum (q->fd);
			printf ("%s:%-30s ", destpath, f->f_un.f_fname);
			fflush (stdout);
			if ((fd = open (get_logpath (f), O_APPEND | O_WRONLY)) < 0)
				{
					if (errno == ENOENT)
					{ 
						fd = open (get_logpath (f), O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR);
						if (fd < 0)
							fprintf (stderr, "cannot save logs. please download \".old\" backup\n");
					}
				}
			switch (f->f_authproto->proto)
				{
				case AUP_NONE:
					printf ("(%5d) [none]\n", au_getfile (sock, fd));
					fflush (stdout);
					snprintf(buf, MAXPATHNAME, 
						"%s ========== Download: no auth used   ==================\n",
						get_time());
	 					write(fd, buf, strlen(buf));
					break;

				case AUP_PEO:
					new = 0;
					if ((fk = open (get_keypath (f), O_RDWR)) < 0)
					{
						if (errno == ENOENT)
						{			
							new = 1;
							if ((fk = open (get_keypath (f), O_CREAT | O_RDWR, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP)) < 0)
								printf ("warning: cannot create keyfile\n");
						} else
						{
							printf ("warning: cannot open keyfile\n");
							snprintf(buf, MAXPATHNAME, 
								"%s ========== Cannot open keyfile ===================\n",
								get_time());
							write(fd, buf, strlen(buf));
						}
					}
					if (!new) read (fk, &k, sizeof (k));
					memcpy ((char *) &d, (char *) &k.sha1digest, sizeof (d));
					printf ("(%5d) ", au_getfilepeo (sock, fd, &d));
					fflush (stdout);
					lseek (fk, 0, SEEK_SET);
					write (fk, &q->k0, sizeof (q->k0));
					close (fk);
					memcpy ((char *) &k, (char *) f->f_authproto->buf, sizeof (k));

					if (new)
					{
							snprintf(buf, MAXPATHNAME, 
								"%s ========== Download: [PEO] new file ===================\n",
								get_time());
							write(fd, buf, strlen(buf));
						printf("[PEO] new file\n");
					}
					else
					{
						if (!memcmp ((char *) &d, (char *) k.sha1digest, sizeof (d)))
						{
							snprintf(buf, MAXPATHNAME, 
								"%s ========== Download: [PEO] Ok =========================\n",
								get_time());
							write(fd, buf, strlen(buf));
							printf ("[PEO] Ok\n");
						}
						else
						{
							snprintf(buf, MAXPATHNAME, 
								"%s ========== Download: [PEO] WARNING AUTH FAILED ========\n",
								get_time());
							write(fd, buf, strlen(buf));
							printf ("[PEO] WARNING AUTH FAILED\n");
						}	
					}
					fflush (stdout);
					break;
				}
			close (fd);

		}
	return (0);
}

int
do_select_all ()
{
	struct filed *f, *j;

	for (f = FIL; f; f = f->f_next)
		{
			if (f->f_type == F_FILE && f->f_un.f_fname[0] == '/')
				{
					for (j = FIL; j != f; j = j->f_next)
						if ((!strncmp (f->f_un.f_fname, j->f_un.f_fname, MAXPATHNAME)) &&
								(j->f_type == F_FILE))
							break;
					if (j == f && 
								(DownLoadAll || 
								(f->f_authproto && (f->f_authproto->proto == AUP_PEO))))
						{
							if (do_selectfile (get_fileno (f->f_un.f_fname)) < 0)
								printf ("%s:%s Remote Auth failed\n", destpath, f->f_un.f_fname);
						}
				}
		}
}

int
main (int argc, char **argv)
{
	int c;
	char *aux, *host;
	struct filed *filp, *filu;

	printf ("\nSecure Syslog Auditor v1.2             CORE-SDI S.A.\n\n");
  rand_open (AUDIT_RANDFILE);

	if (argc < 2)
		{
			usage ();
		}
	else
		{
			while ((c = getopt (argc, argv, "aqvR:r:c:n:h")) != -1)
				switch (c)
					{
					case 'v':
						verbose++;
						break;
					case 'q':
						verbose = 0;
						break;
					case 'R':
						list_config (optarg,1);
						break;
					case 'r':
						list_config (optarg,0);
						break;
					case 'c':
						if (au_sync ((host = strtok (optarg, ":"))) < 0)
							return (-1);
						if ((aux = strtok (NULL, ":")) != NULL)
							{
								if (*aux == '*')	/* all files */
									do_select_all ();
								else
									do_selectfile (get_fileno (aux));
							}
						else
							do_select_all ();
						if (fq)
							do_download ();
						filp = FIL;
						while (filp)
							{
								filu = filp->f_next;
								free (filp);
								filp = filu;
							}
						close (sock);
						break;

					case 'a':
						DownLoadAll++;
						break;
					case 'n':
						new_host (optarg);
						break;
					case '?':
					default:
						usage ();
					}

			rand_close ();
		}


	return (0);
}
