/*
 * 
 * POP3-Virusscan-Proxy
 *
 * (C) 2002 by Folke Ashberg <folke@ashberg.de>
 *
 * $Id: scanner_basic.c,v 1.14 2002/06/11 23:09:16 folke Exp $ 
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <errno.h>
#include <stdlib.h>
#include <pcre.h>

#include "pop3vscan.h"

struct configuration_t * config;

static int scan(struct proxycontext *p, char ** virname){
    int ret;
    char * command;
    int len;
    FILE * scanner;
    char  line[4096];
    pcre * rx;
    const char *pcre_error;
    int pcre_erroffset;
    int offsets[50];
#define VISIZE 1000
    char *vi=malloc(VISIZE);
    int vipos = 0;

    do_log(LOG_DEBUG, "Basic scanner says hello");

    if (config->virusregexp){
	rx = pcre_compile(config->virusregexp, PCRE_UNGREEDY /* | PCRE_CASELESS */ ,
		    &pcre_error, &pcre_erroffset, NULL);
	if (!rx) {
	    /* should not happemd, because init1 has already tested and set to NULL on error */
	    do_log(LOG_WARNING, "Ouch! Can't compile regular expression: %s (char %i)",
			pcre_error, pcre_erroffset);
	}
    } else {
	rx=NULL;
    }

    len=strlen(config->virusscanner) + strlen(p->scanthis) + 1 + strlen(" '' 2>&1"); 
    command=malloc(len+1);
    snprintf(command, len, "%s '%s' 2>&1", config->virusscanner, p->scanthis);
    do_log(LOG_DEBUG, "popen %s", command);

    if ((scanner=popen(command, "r"))==NULL){
	do_log(LOG_ALERT, "Can't start scanner '%s' !!!", command);
	return SCANNER_RET_ERR;
    }
    vi[0]='\0';
    *virname=vi;
    while ((fgets(line, 4095, scanner))!=NULL){
	line[strlen(line)-1]='\0';
	do_log(LOG_DEBUG, "ScannerLine: '%s'", line);
	if (rx){
	    ret = pcre_exec(rx, NULL, line, strlen(line), 0, 0, offsets, 50);
	    if (ret > config->virusregexpsub){
		len=pcre_copy_substring(line, offsets, ret, config->virusregexpsub, vi+vipos, VISIZE  - vipos -4 );
		if (len>0) vipos+=len;
		vi[vipos]=' '; vipos++;
		vi[vipos]='&'; vipos++;
		vi[vipos]=' '; vipos++;
	    }
	}
    }
    ret=pclose(scanner);
    free(command);
    if (vipos > 3) vi[vipos-3]='\0';
    do_log(LOG_DEBUG, "vi : '%s'", vi);
    if (rx) pcre_free(rx);


    if (!WIFEXITED(ret)){
	do_log(LOG_ALERT, "Scanner returned abnormal signal (%i)", ret);
	return SCANNER_RET_ERR;
    } else 
      do_log(LOG_DEBUG, "Scanner returned signal %i", WEXITSTATUS(ret));
    ret=WEXITSTATUS(ret);
    if (ret==config->viruscode)
      return SCANNER_RET_VIRUS; /* contains a virus */
    if (ret!=0){
	do_log(LOG_ALERT,
		    "WARNING: Your scanner returned neither 0 "
		    "nor viruscode (%i), but %i",
		    config->viruscode, ret);
	return SCANNER_RET_ERR;
    }
    do_log(LOG_DEBUG, "Basic scanner says goodbye");
    return SCANNER_RET_OK; /* all ok, no virus */
}

static int init1(void){
    pcre * rx;
    const char *pcre_error;
    int pcre_erroffset;
    if (strlen(NONULL(config->virusscanner))<1){
	do_log(LOG_CRIT, "no scanner was defined. scanning completely disabled");
	return -1;
    }
    if (strlen(NONULL(config->virusregexp))>0){
	rx = pcre_compile(config->virusregexp, PCRE_UNGREEDY /* | PCRE_CASELESS */ ,
		    &pcre_error, &pcre_erroffset, NULL);
	if (!rx) {
	    do_log(LOG_WARNING, "Can't compile regular expression: %s (char %i). Virusnames can't be extracted",
			pcre_error, pcre_erroffset);
	    config->virusregexp=NULL;
	} else {
	    do_log(LOG_DEBUG, "RX compiled succesfully");
	    pcre_free(rx);
	}
    } else {
	config->virusregexp=NULL;
	do_log(LOG_WARNING, "No Regular Expression given! Virusnames can't be extracted");
    }
    return 0;
}

scanner_t scanner_basic = {
    "basic",				    /* name */
    "Basic file invocation scanner",	    /* description */
    &init1,				    /* init1 (once, afer startup) */
    NULL,				    /* init2 (every connection before first mail) */
    &scan,				    /* scan */
    NULL,				    /* uninit2 */
    NULL,				    /* uninit1 */
    1					    /* dirscan */
};


syntax highlighted by Code2HTML, v. 0.9.1