/* Filter pre sendmail 8.12 ... ktory zavola externy program inflex a ten 
  zavola antivirovu kontrolu. 
  Tento filter si zapisuje mail co prichadza do suboru a potom spusti externy 
  program (b-inflex) ktory vrati ze bud je ok a poslem dalej, alebo
  ze je zavireny a vtedy mail sa v tichosti zahodi (b-inflex ma poslat oznam)
  alebo nedefinovany stav = mail bude odmietnuty.
  Mail generovany na localhost NEBUDE kontrolovany antivirom a PREJDE !!!
  Stacilo by aby pustal len virusmastra a Mailer-daemona ale .. loklane
  virus asi aj tak nik nespravi lebo od windows pc to uz nieje lokalne
*/
/* kompiluj: gcc -O2 -Wall -o fantivbbo fantivbbo.c /usr/lib/libmilter/libmilter.a /usr/lib/libmilter/libsm.a  -lldap -llber -lbind -pthread
  treba mat v deb woody baliky: libmilter-dev libldap2-dev bind-dev */
/* Instalacia:
 do *.mc pre sendmail 8.12 dat:
 F=R .. reject connection ak nefunguje filter 
   T .. temorary fail .. odmietne az neskor ak ozaj chce poslat postu
   NIC ak ma posielat aj bez oscanovania !
T=timeouty
        C . pre spojenie s filtrom def:5m
        S .pre poslanie do filtra def:10s
        R .. REPLY z FILTRA .. toto treba dat dost def:10s
        E .. final potvrdenie 5m
INPUT_MAIL_FILTER(`fantivbbo', `S=unix:/var/spool/inflex/fantiv.sock, F=T, T=S:10s;R:1m;E:5m')
Treba este pripadne mazat stare spravy z inputu ak som nejak podivne skoncil
*/
/* treba este spustaci init.d script a konfiguracny subor a tmp katalogy */

#include <libmilter/mfapi.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sysexits.h>
#include <unistd.h>
#include <syslog.h>
#include <signal.h>
#include <fcntl.h>
#include <wait.h>
#include <errno.h>
#include <sys/param.h>
#include <sys/time.h>
#include <dirent.h>
#include <ctype.h>
#include <pwd.h>
#include <grp.h>
#include <sys/resource.h>

/* sendmail ponuka strlcpy a strlcat .. v libsm.a */
#define strlcpy sm_strlcpy
#define strlcat sm_strlcat
extern size_t sm_strlcpy __P((char *, const char *, size_t));
extern size_t sm_strlcat __P((char *, const char *, size_t));


/*
** errno comes from errno.h and libc
*/
extern int errno;

/*
** these can be changed from the configure file
*/
static char *HLAVICKA=NULL;
static char *HOMEDIR=NULL;
static char *SAFEUSER=NULL;
static char *SAFEGROUP=NULL;
static char *SOCKETNAME=NULL;

/*
** these are the default values
*/
#define CONF_HLAVICKA	  "scanned by antivir, host xy"
#define CONF_HOMEDIR      "/usr/local/inflex"
#define CONF_SAFEUSER     "inflex"
#define CONF_SAFEGROUP    "inflex"
#define CONF_SOCKETNAME   "unix:/var/spool/inflex/fantiv.sock"

static char *configfile=NULL;
#define DEFAULTCONFIGFILE "/etc/mail/fantivbbo.conf"

struct mlfiPriv
{
  char *qid;		//queue ID
  char *datafile;	//meno soboru aj s cestou
  FILE *datafp;		//fd suboru
  int headers;		//mam nejake header , pocet
  int bodyblocks;	//kolko mam bodyblokov
  int hasvirus;		//mam virus
  int childpid;		//pid extern prg .. treba si pamatat pre cleanup zabitie
  int childstatus;
  int obalka;		// 0 = bol sender (existuje), 1=bol rcpt, -1=ukoncena
  struct timeval start;
};

// this is a handy shortcut
#define MLFIPRIV        ((struct mlfiPriv *) smfi_getpriv(ctx))

static int debug=0;

//moja fcia pre cistenie vsetkeho
void cleanup(SMFICTX *);

// POZOR obcas sa connect neazvola .. teda dva maily v jednom .. a vtedy
// takze aby ti nechybalo priv !!
sfsistat mlfi_connect(SMFICTX *ctx, char *hostname, _SOCK_ADDR *hostaddr)
{
  if (debug) {
	syslog(LOG_ERR,"mlfi_connect(0x%x, %s)",(int)ctx,hostname);
	}
/* Ak localhost tak bez dalsich kontrol ! */
  if (strcmp("localhost",hostname)== 0)
  	  return SMFIS_ACCEPT;
  return SMFIS_CONTINUE;
}

int testascii(char *x) /* retazec je od !-~ t.j znaky plus ascii bez space*/
{
 if (x==NULL) return 0;
 for (;*x!='\0';x++)
  if (*x<'!' || *x>'~') return 0;
 return 1;
}
int najdiip(char *relay,char *buf) /* najde v relay [IP] a vlozi do buf alebo vrati 0*/
{
        char buf1[50];
        char *b,*e;
        if (relay == NULL) return 0;
        strncpy(buf1,relay,sizeof(buf1));
        b=rindex(buf1,'[');
        e=rindex(buf1,']');
        if (b == NULL || e == NULL ) return 0;
        *++e=0;
        strcpy(buf,b);
        if (testascii(buf)) return 1;
	return 0;
}

sfsistat mlfi_envfrom(SMFICTX *ctx, char **argv)
{
  struct mlfiPriv *priv = MLFIPRIV;  
  char *qid;
  char buf[512];
  char *relay;

  if (debug) {
    syslog(LOG_ERR,"mlfi_envfrom(0x%x, %s)",(int)ctx,argv[0]);
//	blb=smfi_getsymval(ctx,"{mail_host}");
	}

  priv = malloc(sizeof *priv);
  if (priv == NULL)
    {
      syslog(LOG_CRIT,"malloc(): %s",strerror(errno));
      return SMFIS_TEMPFAIL;
    }
  memset(priv, '\0', sizeof *priv);
  smfi_setpriv(ctx, priv);

  qid=smfi_getsymval(ctx,"i");
  if (qid==NULL)
    {
      syslog(LOG_CRIT,"could not get $i from sendmail");
      return(SMFIS_TEMPFAIL);
    }

  priv->qid=strdup(qid);
  if ((priv->qid)==NULL)
    {
      syslog(LOG_CRIT,"strdup(): %s",strerror(errno));
      return(SMFIS_TEMPFAIL);
    }

  if (debug)
    syslog(LOG_ERR,"mlfi_envfrom(0x%x, %s) processing qid %s",
	   (int)ctx,argv[0],qid);

  if (((priv->headers)!=0) || ((priv->bodyblocks)!=0))
    {
      syslog(LOG_ERR,"mlfi_envfrom() found headers and bodyblocks > 0");
    }

  snprintf(buf,sizeof(buf),"%s/inputtmp/%s",HOMEDIR,qid);
  priv->datafile=strdup(buf);
  if ((priv->datafile)==NULL)
    {
      syslog(LOG_CRIT,"strdup(): %s",strerror(errno));
      return(SMFIS_TEMPFAIL);
    }

  priv->datafp=fopen(priv->datafile,"w");
  if ((priv->datafp)==NULL)
    {
      syslog(LOG_CRIT,"fopen(%s): %s",priv->datafile,strerror(errno));
      return(SMFIS_TEMPFAIL);
    }
/** RELAY adresa **/
 relay=smfi_getsymval(ctx, "_");
 if(najdiip(relay,buf)==0)	// do buf dal [IP]
	strcpy(buf,"[NULL]");
 if(testascii(argv[0]) == 0)  	      /** hlavicka  sender*/
	return(SMFIS_REJECT);		// zla adresa //
 if (fprintf(priv->datafp, "OBALKA: %s %s",buf,argv[0])<=0)
    return(SMFIS_TEMPFAIL);

  if (debug)
    syslog(LOG_ERR,"mlfi_envfrom(0x%x, %s) => SMFIS_CONTINUE",
	   (int)ctx,argv[0]);
  return(SMFIS_CONTINUE);
}

sfsistat mlfi_envrcpt(SMFICTX *ctx, char **argv)
{
  struct mlfiPriv *priv = MLFIPRIV;
//  char *rcptaddr = smfi_getsymval(ctx, "{rcpt_addr}");

 if(testascii(argv[0]) == 0)
        return(SMFIS_REJECT);           // ala adresa //
 if (fprintf(priv->datafp, " %s",argv[0])<=0)
    return(SMFIS_TEMPFAIL);
 priv->obalka=1;
  if (debug)
   syslog(LOG_ERR,"mlfi_envrcpt(0x%x, %s) => SMFIS_CONTINUE",(int)ctx,argv[0]);

  return SMFIS_CONTINUE;
}

void endobalky(struct mlfiPriv *priv)
{
  if(priv->obalka==1) {
	priv->obalka= -1;
	fprintf(priv->datafp, "\n");
  }
}
 

sfsistat mlfi_header(SMFICTX *ctx, char *headerf, char *headerv)
{
  struct mlfiPriv *priv = MLFIPRIV;
  endobalky(priv);
  if (debug)
    syslog(LOG_ERR,"smfi_header(0x%x, %s, <omitted>)",(int)ctx,headerf);

  if (fprintf(priv->datafp, "%s: %s\n", headerf, headerv)<=0)
    return(SMFIS_TEMPFAIL);

  (priv->headers)++;
  if (debug)
    syslog(LOG_ERR,"smfi_header(0x%x, %s, <omitted>) => SMFIS_CONTINUE",
	   (int)ctx,headerf);
  return SMFIS_CONTINUE;
}

sfsistat mlfi_eoh(SMFICTX *ctx)
{
  struct mlfiPriv *priv = MLFIPRIV;
  endobalky(priv);
  if (debug)
    syslog(LOG_ERR,"smfi_eoh(0x%x)",(int)ctx);

  if (fprintf(priv->datafp, "\n")<=0)
    {
      if (debug)
	syslog(LOG_ERR,"smfi_eoh(0x%x) => SMFIS_TEMPFAIL",(int)ctx);
      return(SMFIS_TEMPFAIL);
    }
  
  if (debug)
    syslog(LOG_ERR,"smfi_eoh(0x%x) => SMFIS_CONTINUE",(int)ctx);

  return SMFIS_CONTINUE;
}

sfsistat mlfi_body(SMFICTX *ctx, unsigned char *bodyp, size_t bodylen)
{
  int nwritten;
  struct mlfiPriv *priv = MLFIPRIV;
  endobalky(priv);
  if (debug)
    syslog(LOG_ERR,"smfi_body(0x%x, 0x%x, %d)",(int)ctx,(int)bodyp,bodylen);

  (priv->bodyblocks)++;
  if ((nwritten = fwrite(bodyp, bodylen, 1, priv->datafp)) != 1)
    {
      syslog(LOG_CRIT,"mlfi_body(): fwrite(): %s",strerror(errno));
      (void) cleanup(ctx);
      return SMFIS_TEMPFAIL;
    }
  
  if (debug)
    syslog(LOG_ERR,"smfi_body(0x%x, 0x%x, %d) => SMFIS_CONTINUE",
	   (int)ctx,(int)bodyp,bodylen);
  return SMFIS_CONTINUE;
}

// -1=error inak je to navratova hodnota
int externalcommand(SMFICTX *ctx, char *workdir,  char *p, char **av)
{
  struct mlfiPriv *priv = MLFIPRIV;
  char *ev[]={"PATH=/bin:/usr/bin",NULL};
  int i;
  int openmax=getdtablesize();

  if (debug)
    syslog(LOG_ERR,"externalcommand(0x%x, ..., %s, ...)",(int)ctx,p);

  if ((priv->childpid)!=0)
    {
      syslog(LOG_CRIT,"externalcommand() called and priv->childpid is %d",
	     priv->childpid);
    }

  priv->childstatus=0;
  priv->childpid=fork();
  switch(priv->childpid)
    {
    case -1: /* error */
      syslog(LOG_CRIT,"fork(): %s",strerror(errno));
      priv->childpid=0;
      return(-1);
      break;
    case 0: /* child */
      if (workdir!=NULL)
	{
	  if (chdir(workdir)!=0)
	    {
	      syslog(LOG_CRIT,"chdir(%s): %s",workdir,strerror(errno));
	    }
	}
	  close(0);
	  close(1);
	  close(2);
	  open("/dev/null",O_RDONLY);
	  open("/dev/null",O_WRONLY);
	  open("/dev/null",O_WRONLY);

      for (i=3;i<openmax;i++)
	close(i);

      execve(p, av, ev);
      syslog(LOG_CRIT,"externalcommand() failed to execve() %s",p);
      exit(1);
      break;
    default: /* parent */
      waitpid(priv->childpid,&(priv->childstatus),0);
      priv->childpid=0;
      if (WIFEXITED(priv->childstatus))
	{
	  if (debug)
	    syslog(LOG_ERR,"externalcommand(0x%x, ..., %s, ...) => %d",
		   (int)ctx,p,WEXITSTATUS(priv->childstatus));
	  return(WEXITSTATUS(priv->childstatus));
	}
      else
	{
	  if (debug)
	    syslog(LOG_ERR,"externalcommand(0x%x, ..., %s, ...) => -1",
		   (int)ctx,p);
	  return(-1);
	}
      break;
    }
  if (debug)
    syslog(LOG_ERR,"externalcommand(0x%x, ..., %s, ...) => -1",(int)ctx,p);
  return(-1);
}

/* Vratit ma SMFIS_REJECT=virus SMFIS_TEMPFAIL=nevedno SMFIS_CONTINUE=ok */
sfsistat virusscan(SMFICTX *ctx, char *prg, char *cestasubor)
{
  int retval;
  char *av[]={NULL, NULL, NULL};

  if (debug)
    syslog(LOG_ERR,"virusscan(0x%x, ...)",(int)ctx);
  
  av[0]=prg;
  av[1]=cestasubor;

  retval=externalcommand(ctx,HOMEDIR,prg,av);

  if (retval==20)	/* 20 =VIRUS */
    {
      return(SMFIS_REJECT);	
    }
  if (retval==10)	/* 10 = OK */
    {
      return(SMFIS_CONTINUE);
    }
		/* nezname teda chyby */
    syslog(LOG_CRIT,"externalcommand() returned less than zero");
    return(SMFIS_TEMPFAIL);
}

sfsistat mlfi_eom(SMFICTX *ctx)
{
  struct mlfiPriv *priv = MLFIPRIV;
//  char *message="VIRUS OR ILLEGAL FILETYPE FOUND, Virus alebo zakazane exe prilohy !!!";
  sfsistat vstat;
  struct timeval stop;
  struct timeval total;

  if (debug) {
    //char *rcptaddr = smfi_getsymval(ctx, "{rcpt_addr}");
    char *rcptaddr = smfi_getsymval(ctx, "u");
    syslog(LOG_ERR,"smfi_eom(0x%x)",(int)ctx);
    syslog(LOG_ERR,"BBBBBB(0x%x:%s)",(int)ctx,rcptaddr);
	}

  if (priv==NULL)
    {
      syslog(LOG_ERR,"mlfi_eom() priv is NULL in mlfi_eom?");
      return(SMFIS_TEMPFAIL);
    }
  if ((priv->datafp)!=NULL)	// zavri subor s postou
    {
      fclose(priv->datafp);
      (priv->datafp)=NULL;
    }
  else
    {
      syslog(LOG_ERR,"mlfi_eom() priv->datafp is NULL?");
      return(SMFIS_TEMPFAIL);
    }

// Ak nieco bolo teda nieje to prazdny mail
  if (((priv->headers)!=0) || ((priv->bodyblocks)!=0))
    {
      if ((priv->datafile)==NULL)
	  syslog(LOG_ERR,"mlfi_eom() priv->datafile is NULL");

	  if (gettimeofday(&(priv->start),NULL)!=0)
	    syslog(LOG_ERR,"gettimeofday(): %s",strerror(errno));
//unpack bola chyba .. lebo aj vtedy povedal ze ok
	{
	  vstat=virusscan(ctx,"/usr/local/inflex/inflex",priv->datafile);

	  if (gettimeofday(&stop,NULL)!=0)
	    syslog(LOG_ERR,"cleanup(0x%x): gettimeofday(): %s",
		   (int)ctx,strerror(errno));
	  
	  total.tv_sec=(stop.tv_sec-(priv->start).tv_sec);
	  if (stop.tv_usec > (priv->start.tv_usec))
	    {
	      total.tv_usec=stop.tv_usec-(priv->start).tv_usec;
	    }
	  else
	    {
	      total.tv_sec--;
	      total.tv_usec=(1000000 + stop.tv_usec) - (priv->start).tv_usec;
	    }
	  syslog(LOG_ERR,"timing virusscan %s: %d.%06d",
		 priv->qid,(int)total.tv_sec,(int)total.tv_usec);

	  switch(vstat)
	    {
	    case SMFIS_REJECT:
/* reject je pekne .. ale potom odosielatel dostane od svojha mailera virus
lebo ze toto nemohlo byt dorucene a ak maju antivir tak by sme si to mohli
zacat pohadzovat .. t.j. nebezpecie cyklusu preto len tiche zahodenie*/
	      priv->hasvirus=1;
// 	      smfi_setreply(ctx, "550", "5.7.1", message);
	      cleanup(ctx);
	      if (debug)
		syslog(LOG_ERR,"smfi_eom(0x%x) => SMFIS_DISCARD",(int)ctx);
	      return(SMFIS_DISCARD);
	      break;
	    case SMFIS_CONTINUE:
	      smfi_addheader(ctx,"X-scanner",HLAVICKA);
	      break;
	    case SMFIS_TEMPFAIL:
	    default:

	      cleanup(ctx);
	      if (debug)
		syslog(LOG_ERR,"smfi_eom(0x%x) => SMFIS_TEMPFAIL",(int)ctx);
	      return(SMFIS_TEMPFAIL);
	      break;
	    }
	  
	}
    }
  
  cleanup(ctx);
  if (debug)
    syslog(LOG_ERR,"smfi_eom(0x%x) => SMFIS_CONTINUE",(int)ctx);
  return(SMFIS_CONTINUE);
}

sfsistat mlfi_abort(SMFICTX *ctx)
{
  if (debug)
    syslog(LOG_ERR,"smfi_abort(0x%x)",(int)ctx);
  cleanup(ctx);
  if (debug)
    syslog(LOG_ERR,"smfi_abort(0x%x) => SMFIS_CONTINUE",(int)ctx);
  return(SMFIS_CONTINUE);
}

void cleanup(SMFICTX *ctx)
{
  struct mlfiPriv *priv = MLFIPRIV;

  if (debug)
    syslog(LOG_ERR,"cleanup(0x%x)",(int)ctx);

  if (priv != NULL)
    {
      if ((priv->childpid)>0)
	{
	  syslog(LOG_ERR,"cleanup() killing %d\n",priv->childpid);
	  kill(priv->childpid,SIGABRT);
	  waitpid(priv->childpid,NULL,0);
	  priv->childpid=0;
	}

      if ((priv->datafp)!=NULL)		// zavri subor
	{
	  fclose(priv->datafp);
	  priv->datafp=NULL;
	}
      
      (priv->headers)=0;
      (priv->bodyblocks)=0;
      
      if(priv->datafile)		// a tu ho aj zmazem
	{
	  if (unlink(priv->datafile)<0) {
	     if (errno!=ENOENT) {
	        syslog(LOG_ERR,"unlink err qid=(%s)",priv->qid);
	     }
	  }

	  free(priv->datafile);
	  priv->datafile=NULL;
	}
      if(priv->qid)
	{
	  free(priv->qid);
	  priv->qid=NULL;
	}
    }

  free(priv);
  smfi_setpriv(ctx, NULL);

  if (debug)
    syslog(LOG_ERR,"cleanup(0x%x) => (void)",(int)ctx);
}

sfsistat mlfi_close(SMFICTX *ctx)
{
  struct mlfiPriv *priv = MLFIPRIV;

  if (debug)
    syslog(LOG_ERR,"smfi_close(0x%x)",(int)ctx);

  if (priv!=NULL)
    {
      cleanup(ctx);
    }
  if (debug)
    syslog(LOG_ERR,"smfi_close(0x%x) => SMFIS_CONTINUE",(int)ctx);
  return SMFIS_CONTINUE;
}

struct smfiDesc smfilter =
{
    "fantivbbo",    /* filter name */
    SMFI_VERSION,   /* version code -- do not change */
    SMFIF_ADDHDRS,  /* flags  mozno buidem menit hlavicku pridam*/
    mlfi_connect,   /* connection info filter */
    NULL,           /* SMTP HELO command filter */
    mlfi_envfrom,   /* envelope sender filter */
    mlfi_envrcpt,   /* envelope recipient filter */
    mlfi_header,    /* header filter */
    mlfi_eoh,       /* end of header */
    mlfi_body,      /* body block filter */
    mlfi_eom,       /* end of message */
    mlfi_abort,     /* message aborted */
    mlfi_close,     /* connection cleanup */
};

static void
usage(void)
{
    fprintf(stderr,"Usage: prg [-cdh]\n");
    fprintf(stderr,"  -c: vypis configuracie\n");
    fprintf(stderr,"  -d: debug\n");
    fprintf(stderr,"  -h: help\n");
}

/*
** inspired by Thomas Lussnig <thomas@bewegungsmelder.de>
*/
int droproot(void)
{
  uid_t myuid;
  uid_t myeuid;
  struct passwd *pwent;
  struct group *grent;

  myuid=getuid();
  myeuid=geteuid();

  if ((myuid!=0) && (myeuid!=0)) return(1); 

  grent=getgrnam(SAFEGROUP);
  if (grent==NULL)
    {
      fprintf(stderr,"droproot(): getgrnam(%s): %s\n",
	      SAFEGROUP,strerror(errno));
      return(-1);
    }
  if (setregid(grent->gr_gid,grent->gr_gid)!=0)
    {
      fprintf(stderr,"droproot(): setregid(%d,%d): %s\n",
	      (int)grent->gr_gid,(int)grent->gr_gid,strerror(errno));
      return(-1);
    }
  if (initgroups(SAFEUSER,grent->gr_gid))
    {
      fprintf(stderr,"droproot(): initgroups(%s,%d): %s\n",
              SAFEUSER,(int)(grent->gr_gid),strerror(errno));
      return(-1);
    }

  pwent=getpwnam(SAFEUSER);
  if (pwent==NULL)
    {
      fprintf(stderr,"droproot(): getpwnam(%s): %s\n",
	      SAFEUSER,strerror(errno));
      return(-1);
    }
  if (setreuid(pwent->pw_uid,pwent->pw_uid)!=0)
    {
      fprintf(stderr,"droproot(): setreuid(%d,%d): %s\n",
	      (int)pwent->pw_uid,(int)pwent->pw_uid,strerror(errno));
      return(-1);
    }
  
  myuid=getuid();
  myeuid=geteuid();

  if ((myuid==0) || (myeuid==0))
    {
      fprintf(stderr,"droproot(): still root after setreuid()?\n");
      return(-1);
    }

  return(0);
}

static int readconfig(void)
{
  FILE *fp;
  char buf[512];
  char fmt[64];
  char token[64];
  char value[256];
  char *ptr;
  int scanned;
  int set=0;
  int line=0;

  fflush(stdout);

  if (configfile==NULL)
    {
      fp=fopen(DEFAULTCONFIGFILE,"r");
      if (fp==NULL)
	{
	  if (errno==ENOENT)
	    return(0);
	  snprintf(buf,sizeof(buf),"fopen(%s)",configfile);
	  perror(buf);
	  return(-1);
	}
    }
  else
    {
      fp=fopen(configfile,"r");
      if (fp==NULL)
	{
	  snprintf(buf,sizeof(buf),"fopen(%s)",configfile);
	  perror(buf);
	  return(-1);
	}
    }
      
  while (fgets(buf,sizeof(buf),fp)!=NULL)
    {
      line++;
      ptr=index(buf,'#');
      if (ptr)
	*ptr='\0';

      snprintf(fmt,sizeof(fmt),"%%%ds %%%d[!-~ ]",sizeof(token),sizeof(value));
      scanned=sscanf(buf,fmt,token,value);
      if (scanned==1)
	{
	  fprintf(stderr,"Error on line %d in configure file: %s\n",line,buf);
	  fclose(fp);
	  return(-1);
	}
      if (scanned==2)
	{
#define DOTOKEN(X,Y) if(strcasecmp(token,(X))==0){if((Y)!=NULL){fprintf(stderr,"readconfig(): %s already defined\n",(X));return(-1);}(Y)=strdup(value);if ((Y)==NULL){perror("malloc()");return(-1);}set++;continue;}
	  DOTOKEN("HOMEDIR",HOMEDIR);
	  DOTOKEN("SAFEUSER",SAFEUSER);
	  DOTOKEN("SAFEGROUP",SAFEGROUP);
	  DOTOKEN("SOCKETNAME",SOCKETNAME);
	  DOTOKEN("HLAVICKA",HLAVICKA);  
	  fprintf(stderr,"Line %d unrecognized: %s\n",line,buf);
	  fclose(fp);
	  return(-1);
	}
    }

  if (set==0)
    {
      fprintf(stderr,"Warning: %s contained no valid lines\n",configfile);
    }

  fclose(fp);
  return(0);
}

int initc(void)
{
  if (readconfig()<0)
    return(-1);

  if (HLAVICKA==NULL) HLAVICKA=CONF_HLAVICKA;
  if (HOMEDIR==NULL) HOMEDIR=CONF_HOMEDIR;
  if (SAFEUSER==NULL) SAFEUSER=CONF_SAFEUSER;
  if (SAFEGROUP==NULL) SAFEGROUP=CONF_SAFEGROUP;
  if (SOCKETNAME==NULL) SOCKETNAME=CONF_SOCKETNAME;

  return(0);
}

void dumpconfig(void)
{
  printf("HLAVICKA   %s\n",HLAVICKA);
  printf("HOMEDIR    %s\n",HOMEDIR);
  printf("SAFEUSER   %s\n",SAFEUSER);
  printf("SAFEGROUP  %s\n",SAFEGROUP);
  printf("SOCKETNAME %s\n",SOCKETNAME);
}

int main(int argc, char **argv)
{
  int retval;
  char c;
  const char *args = "chd";

  while ((c = getopt(argc, argv, args)) != (char)EOF)
    {
      switch (c)
        {
	case 'd':
	  debug++;
	  break;
	case 'c':
	  initc();
	  dumpconfig();
	  exit(0);
        case 'h':
        default:
	  usage();
	  exit(0);
	  break;
        }
    }
  if (initc()!=0)
    {
      fprintf(stderr,"init() failed\n");
      exit(EX_SOFTWARE);
    }
  if (droproot()!=0)
    {
      fprintf(stderr,"droproot() failed - zmena prav neuspesna\n");
      exit(EX_SOFTWARE);
    }
  
  openlog("fantivbbo",LOG_PID,LOG_MAIL);

  if (chdir(HOMEDIR)!=0)
    {
      syslog(LOG_CRIT,"chdir(%s): %s",HOMEDIR,strerror(errno));
      fprintf(stderr,"chdir(%s): %s",HOMEDIR,strerror(errno));
      exit(EX_SOFTWARE);
    }

  /*
  ** do the socket
  */
  if(smfi_setconn(SOCKETNAME) == MI_FAILURE)
    {
      fprintf(stderr,"smfi_setconn(%s) failed",SOCKETNAME);
      syslog(LOG_CRIT,"smfi_setconn(%s) failed",SOCKETNAME);
      exit(EX_SOFTWARE);
    }
  /*
  ** If we're using a local socket, make sure it doesn't
  ** already exist.
  **
  ** Why do they do this after the smfi_setconn() call?
  */
  if(strncmp(SOCKETNAME, "unix:", 5) == 0)
    {
      if (unlink(SOCKETNAME + 5)<0)
	{
	  if (errno!=ENOENT)
	    perror("unlink()");
	}
    }
  else if(strncmp(SOCKETNAME, "local:", 6) == 0)
    {
      if (unlink(SOCKETNAME + 6)<0)
	{
	  if (errno!=ENOENT)
	    perror("unlink()");
	}
    }

  if (smfi_register(smfilter) == MI_FAILURE)
    {
      fprintf(stderr, "smfi_register failed\n");
      exit(EX_UNAVAILABLE);
    }
  syslog(LOG_CRIT,"ready to answer queries");
  retval = smfi_main();
  if (retval != 0)
    {
      fprintf(stderr,"smfi_main() => %d\n",retval);
    }
  syslog(LOG_CRIT,"END,koniec");
  return(abs(retval));
}
// END

