/* Nessus
 * Copyright (C) 1998 Renaud Deraison
 *
 * 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */           
 
#include <includes.h>
#ifdef NESSUSNT
#include "wstuff.h"
#else
#include <pwd.h>
#endif
#include "utils.h"
#include "rules.h"

extern int nessus_fnmatch(char *, char*, int);

static char * rules_get_fname(struct arglist *);
/*
 * Returns the name of the rules file
 */
static char *
rules_get_fname(preferences)
  struct arglist * preferences;
{
  char * t;
  if((t=arg_get_value(preferences, "rules")))return(t);
  else return(NESSUSD_RULES);
}

/*
 * Initializes the rules : read the file and place it in
 * memory
 */
void rules_init(rules, preferences)
     struct nessus_rules ** rules;
     struct arglist * preferences;
{
  FILE * fd;
  char * fn = rules_get_fname(preferences);
  struct nessus_rules * p ;
  
  
  p = *rules = emalloc(sizeof(struct nessus_rules));
  check_symlink(fn);
  fd = fopen(fn, "r"); 
  if(!fd)
    {
      char * buf = emalloc(200);
#ifndef NESSUSNT
      int fdesc = open(fn, O_CREAT | O_RDWR | O_EXCL,  0600);
      FILE * f = fdopen(fdesc, "w");
#else
      FILE * f = fopen(fn, "w");
#endif
      if(!f)
      {
       fprintf(stderr, "nessusd does not have the right to read %s\n", fn);
       DO_EXIT(0);
      }
      fprintf(f, 
	      "#Nessusd rules\n#read doc/sample.rules for details\nN:localhost.*\n");
      fclose(f);
      efree(&buf);
      p->name = emalloc(12);
      sprintf(p->name, "localhost.*");
      p->category = p_DONT_TEST;
      p->next = NULL;
    }
  else
    {
      char * buf = emalloc(255);
      
      bzero(buf, 255);
      while(fgets(buf, 255, fd) && !feof(fd))
	{
	  if(buf[0]!='#' && strlen(buf)>2)
	    {
	      switch(buf[0])
		{
		case 'n':
		  p->category = p_DONT_TEST;
		  break;
		case 'y':
		  p->category = p_DO_TEST;
		  break;
		case 'N' :
		  p->category = p_DO_NOT_TEST;
		  break;
		default : 
		  p->category = -1;
		  print_error("Parse error in %s : \"%s\"\n",fn,  buf);
		}
	      if(p->category != -1)
		{
		  buf+=2;
		  if(buf[strlen(buf)-1]=='\n')buf[strlen(buf)-1]=0;
		  p->name = emalloc(strlen(buf) + 1);
		  p->server = 1;
		  strncpy(p->name, buf, strlen(buf));
		  p->next = emalloc(sizeof(struct nessus_rules));
		  bzero(p->next, sizeof(struct nessus_rules));
		  p = p->next;
		  buf-=2;
		}
	    }
	  bzero(buf, 255);
	}
      efree(&buf);
      fclose(fd);
    } 
}

/*
 * Add some rules to the global rules
 */
void rules_add(rules, rules_str, level)
     struct nessus_rules * rules;
     char * rules_str;
     int level;
{
  int flag = 0;
  struct nessus_rules * p = rules;
  while(p && p->next)p=p->next;
  
  while(!flag)
    {
      char * t = strchr(rules_str, '\n');
      if(t)t[0]=0;
      while(rules_str[0] && rules_str[0]==' ')rules_str+=sizeof(char);
      if(rules_str[0]!='#' && strlen(rules_str)>2)
	{
	  switch(rules_str[0])
	    {
	    case 'n':
	      p->category = p_DONT_TEST;
	      break;
	    case 'y':
	      p->category = p_DO_TEST;
	      break;
	    case 'N' :
	      p->category = p_DO_NOT_TEST;
	      break;
	    default : 
	      p->category = -1;
	      print_error("Parse error in the users database : \"%s\"\n",  rules_str);
	    }
	  if(p->category != -1)
	    {    
	      rules_str+=2;
	      p->name = emalloc(strlen(rules_str) + 1);
	      p->server = 0;
	      p->user = 0;
	      p->extra = 0;
	      if(level == 1)p->user = 1;
	      else p->extra = 1;
	      p->extra_flag = 0;
	      sprintf(p->name, "%s", rules_str);
	      p->next = emalloc(sizeof(struct nessus_rules));
	      p = p->next;
	      rules_str-=2;	  
	    }
	}
      if(!t)flag = 1;
      else rules_str = t+1;
    }
}


struct nessus_rules * rules_parse(name, r, server)
     char * name;
     struct nessus_rules * r;
     int server;
{
  char good = 1;
  unsigned int i;
  struct in_addr addr;
  char * a;
  char * lname = emalloc(strlen(name)+1);
  strncpy(lname, name, strlen(name));
  for(i=0;i<strlen(lname);i++)lname[i]=tolower(lname[i]);
  
  addr = nn_resolve(lname);
  a = inet_ntoa(addr);
  while(r && r->name && good)
    {
      if(server)
	{
	  if(r->server && ((!nessus_fnmatch(r->name, lname, 0))||
			   (!nessus_fnmatch(r->name, a,0))))good = 0;
	}
      else if((!nessus_fnmatch(r->name, lname, 0))||
              (!nessus_fnmatch(r->name, a,0)))good = 0;
      if(good) r = r->next;
    }
  efree(&lname);
  return(good ? NULL:r);
}

/*
 * Returns an index of hosts 
 * params
 */
short get_hostname_attributes(globals, name)
     struct arglist * globals;
     char * name;
{
  struct nessus_rules * p = arg_get_value(globals, "rules");
  short a=0;
  
  while(p && p->name)
    {
      if(p->server)
	{
	  p = rules_parse(name, p, 1);
	  if(p)
	    {
	      a += (a & p->category)?0:p->category;
	      if(p)p = p->next;
	    }
	}
      else p = p->next;
    }
  
  if(!(pTEST(a)))return(a);
  
  p = arg_get_value(globals, "rules");
  while(p && p->name)
    {
      if(p->user)
	{
	  p = rules_parse(name, p,0);
	  if(p)
	    {
	      a += (a & p->category)?0:p->category;
	      if(p)p = p->next;
	    }
	}
      else p=p->next;
    }
  if(!(pTEST(a)))return(a);
  
  p = arg_get_value(globals, "rules");
  while(p && p->name)
    {
      if((!p->user) && (!p->server))
	{
	  p = rules_parse(name, p,0);
	  if(p)
	    {
	      a += (a & p->category)?0:p->category;
	      if(p)p = p->next;
	    }
	}
      else p=p->next;
    }
  return(a);
} 


void rules_dup(dst, src)
     struct nessus_rules * dst;
     struct nessus_rules * src;
{
 while(src && src->name)
   {
     dst->name = emalloc(strlen(src->name)+1);
     strncpy(dst->name, src->name, strlen(src->name));
     dst->category = src->category;
     dst->server = src->server;
     dst->user = src->user;
     dst->extra = src->extra;
     dst->extra_flag = src->extra_flag;
     dst->next = emalloc(sizeof(struct nessus_rules));
     dst = dst->next;
     src = src->next;
   }
}

	
		
	
	  
