#ifndef lint
static char rcsid[] = "$Id: preen.interp.c,v 1.14 1994/04/04 00:34:40 gkim Exp $";
#endif

/*
 * preen.interp.c
 *
 *	interpret the diffs between the database files
 *
 * Gene Kim
 * Purdue University
 */

#include "../include/config.h"
#include <stdio.h>
#ifdef STDLIBH
#include <stdlib.h>
#endif
#ifdef STRINGH
#include <string.h>
#else
#include <strings.h>
#endif
#include <sys/param.h>
#ifdef __STDC__
# include <sys/types.h>
# include <sys/stat.h>
#endif
#if (defined(SYSV) && (SYSV < 3))
# include <limits.h>
#endif	/* SVR2 */
#include "../include/list.h"
#include "../include/tripwire.h"

/* Rootkit configuration files */
#include "../../config.h"
#include "../../rootkittripwire.h"

					/* the diff lists */
struct list *diff_added_list = NULL,
	    *diff_deleted_list = NULL,
	    *diff_changed_list = NULL;

					/* how many in each list */
int diff_added_num = 0,
    diff_changed_num = 0,
    diff_deleted_num = 0,
    diff_unignored_num = 0;

/*
 * preen_interp(FILE *fpin)
 *
 *	do the actual interpreation of the diff output, generated by
 *	diffing the two database files.
 */

void
preen_interp (fpin)
    FILE *fpin;
{
    char s[1024];
    char key[MAXPATHLEN+256], value[512];
    struct list_elem *plist;

/* Read in list of files to have their reports blocked */
	file_block_list();

    if (!quietmode)
	fprintf(stderr, "### Phase 4:   Searching for inconsistencies\n");

    /* start reading in lines from the new database */
    while (fgets(s, sizeof(s), fpin) != NULL) {
	char *oldvalue;
	static int countlines = 1;

	countlines++;

	/* is it a comment? */
	if (s[0] == '#')
	    continue;
	if (s[0] == '@' && s[1] == '@')
	    continue;

	/*
	 * if it's in the list:
	 *	flag as SEEN
	 *	a) if it's the same, next;
	 *	b) if it's different, it's CHANGED;
	 * otherwise,
	 *	it's ADDED
	 *
	 * scan entire list, find all !SEEN
	 *	they're DELETED
	 */

	/* (this should never happen since it was already preprocessed!) */
	if (string_split_space(s, key, value) < 0) {
	    fprintf(stderr, 
	    	"%s: fatal parse error in preprocessed database file, line %d\n!",
		progname, countlines);
	    exit(1);
	}

	filename_escape_expand(key);

/* If file should be blocked mark as seen and continue */
	if(check_file(key)) {
		list_setflag(key, FLAG_SEEN, &olddbase_list);
		continue;
	}

	/* if file is in saved database */
	if ((oldvalue = list_lookup(key, &olddbase_list)) != NULL) {

	    list_setflag(key, FLAG_SEEN, &olddbase_list);

	    /* was it CHANGED? */
	    if (strcmp(value, oldvalue) != 0) {

SPDEBUG(6) printf("--(changed %s)------vvv\n", key);
SPDEBUG(6) printf(">%s>%s\n", oldvalue, value);

		list_set(key, value, 0, &diff_changed_list);
		diff_changed_num++;
	    }
	    /* else skip it */
	    else
		continue;

	}
	/* else it's been ADDED */
	else {
	    list_set(key, value, 0, &diff_added_list);
	    diff_added_num++;
	}
    }

    /* look for DELETED entries */
    if (list_open(&olddbase_list) < 0) {
	fprintf(stderr, "preen_interp: list_open() failed!\n");
	exit(1);
    }

    while ((plist = list_get(&olddbase_list)) != NULL) {

	/* skip entries that have already been seen */
	if (plist->flag & FLAG_SEEN)
	    continue;

	list_set(plist->varname, plist->varvalue, 0, &diff_deleted_list);
	diff_deleted_num++;
    }

    if (list_close(&olddbase_list) < 0) {
	fprintf(stderr, "preen_interp: list_open() failed!\n");
	exit(1);
    }

    return;
}
