/* 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.
 *
 * Nessus Communication Manager -- it manages the NTP Protocol, version 1.0 and 1.1
 *
 */ 
 
#include <includes.h>


#include "auth.h"
#include "rules.h"
#include "comm.h" 
#include "threads.h"
#include "sighand.h"
#include "ntp.h"
#include "ntp_10.h"
#include "ntp_11.h"
#include "log.h"




/*
 * comm_init() :
 * Initializes the communication between the
 * server (us) and the client.
 */
int 
comm_init(soc)
     int soc;
{  
  char * buf = emalloc(20);
  int ntp_version;
  /* We must read the version of the NTP the client
     wants us to use */
#ifndef NESSUSNT
  signal(SIGALRM, sighand_alarm);
  alarm(CLIENT_TIMEOUT);   
  signal(SIGPIPE, sighand_pipe);    
#endif  
  recv_line(soc, buf, 20);
#ifndef NESSUSNT
  signal(SIGALRM, SIG_IGN);
  signal(SIGPIPE, SIG_IGN);
  alarm(0);              
#endif
  if(!strncmp(buf, "< NTP/1.0 >", 11))
    {
      ntp_version = NTP_10;
      send(soc, "< NTP/1.0 >\n",12,0);
    }
  else if(!strncmp(buf, "< NTP/1.1 >", 11))
    {
      ntp_version = NTP_11;
      send(soc, "< NTP/1.1 >\n", 12, 0);
    }  
  else
    {
      shutdown(soc, 2);
      EXIT(0);
    }
  efree(&buf);
  return(ntp_version);
}


/*
 * This function must be called at the end
 * of a session. 
 */
void 
comm_terminate(globals)
 struct arglist * globals;
{
  char * buf = emalloc(200);
  auth_printf(globals, "SERVER <|> BYE <|> BYE <|> SERVER\n");
#ifndef NESSUSNT
  signal(SIGALRM, sighand_alarm);
  alarm(10);
#endif
  auth_gets(globals, buf, 199); /* wait for the ack. of the client */
  efree(&buf);
#ifndef NESSUSNT
  alarm(0);
#endif
}


/*
 * Sends the list of plugins that the server
 * could load to the client, using the 
 * NTP format
 */
void 
comm_send_pluginlist(globals)
 struct arglist * globals;
{
  int i=1,j, k;
  const char * categories[] =
  	{ "infos", "attack", "denial", "sniffer", "scanner", "unknown" };
  struct arglist * plugins = arg_get_value(globals, "plugins");
  struct arglist * scanners = arg_get_value(globals, "scanners");
  struct arglist * w = NULL;
  
  auth_printf(globals, "SERVER <|> PLUGIN_LIST <|>\n");
  for(k=0;k<2;k++)
  {
   if(!w)w=plugins;
   else w=scanners;
  while(w && w->next)
    {
      struct arglist * args;
      char * t;
      
	  
      args = arg_get_value(w->value, "plugin_args");
	  arg_add_value(args, "ID", ARG_INT, sizeof(int), (void *)i);
      t = arg_get_value(args, "DESCRIPTION");
      while((t=strchr(t,'\n')))t[0]=';';
      j = (int)arg_get_value(args, "CATEGORY");
      if((j>ACT_SCANNER) || (j<ACT_GATHER_INFO))j=6;
      auth_printf(globals, "%d <|> %s <|> %s <|> %s <|> %s <|> %s <|> %s\n",
      		  i, 
		  (const char *) arg_get_value(args, "NAME"),
		  categories[j-1],
		  (const char *) arg_get_value(args, "COPYRIGHT"),
		  (const char *) arg_get_value(args, "DESCRIPTION"),
		  (const char *) arg_get_value(args, "SUMMARY"),
		  plug_get_family(args));
      i++;
      w = w->next;
    }
   }
  auth_printf(globals, "<|> SERVER\n");
}

/*
 * Sends the rules of the user
 */
void
comm_send_rules(globals)
 struct arglist * globals;
{
 struct nessus_rules * rules = arg_get_value(globals, "rules");
 auth_printf(globals, "SERVER <|> RULES <|>\n");
 while(rules && rules->next)
 {
  char c = 0;
  switch(rules->category)
  { 
   case p_DONT_TEST :
    c = 'n';
    break;
   case p_DO_TEST :
    c = 'y';
    break;
   case p_DO_NOT_TEST :
    c = 'N';
    break;
   }
  if(c)auth_printf(globals, "%c:%s;\n", c, rules->name);
  rules = rules->next;
 }
 auth_printf(globals, "<|> SERVER\n");
}

/*
 * Sends the preferences of the server
 */
void
comm_send_preferences(globals)
 struct arglist * globals;
{
 struct arglist * prefs = arg_get_value(globals, "preferences");
 
 /* We have to be backward compatible with the NTP/1.0 */
 auth_printf(globals, "SERVER <|> PREFERENCES <|>\n");
 while(prefs && prefs->next)
 {
  auth_printf(globals, "%s <|> %s\n", prefs->name, (const char *) prefs->value);
  prefs = prefs->next;
 }
 auth_printf(globals, "<|> SERVER\n");
}


/*
 * This function waits for the attack order
 * of the client
 * Meanwhile, it processes all the messages the client could
 * send
 */
void
comm_wait_order(globals)
	struct arglist * globals;
{
  char * str = emalloc(512);
  int problem = 1;
  int ntp_version = (int)arg_get_value(globals, "ntp_version");
  
  while(problem)
  {
  auth_gets(globals, str, 511);
  if(!strlen(str))
  {
	  log_write("Communication closed by the client\n");
	  EXIT(0);
  }
  if(ntp_version < NTP_11)
   problem = ntp_10_parse_input(globals, str);
  else
   problem = ntp_11_parse_input(globals, str);
  }
}


/* 
 * Marks the plugins that will be
 * launched, according to the list
 * provided by the client (list of numbers
 * we should use)
 */
void 
comm_setup_plugins(globals, id_list)
     struct arglist * globals;
     char * id_list;
{
  char * list = id_list;
  char * buf;
  int id;
  int i = 0;
  int num_plugins=0;
  int num_scanners=0;
  struct arglist * plugins = arg_get_value(globals, "plugins");
  struct arglist * scanners = arg_get_value(globals, "scanners");
  struct arglist * p = plugins;
  /* list = a string like '16;5;3' */
  
 
  while(plugins && plugins->next){
    num_plugins++;
    plug_set_launch(plugins->value, 0);
    plugins = plugins->next;
  }
  plugins = p;
  p = scanners;
  while(scanners && scanners->next){
    num_scanners++;
    plug_set_launch(scanners->value, 0);
    scanners = scanners->next;
  }
  scanners = p;
  
  buf = emalloc(strlen(id_list)+1);
  while(sscanf(list, "%d;%s", &id, buf) && strlen(list))
    {
      if(id==0)break;
      p = plugins;
      if(id<0)
 	{
	  struct arglist * lp = NULL;
          int i;
          
          for(i=0;i<2;i++)
          {
           if(!lp)lp=plugins;
           else lp = scanners;
          
	  while(lp && lp->next)
	    {
	      plug_set_launch(lp->value, 1);
	      lp = lp->next;
	    }
          }
	  break;
 	}
      if(id>num_plugins)
	{
          if((id-num_plugins)<=num_scanners)
          {
           id -= num_plugins;
           p = scanners;
          }
          else
          {
	  auth_printf(globals, 
          	"SERVER <|> ERROR <|> There is no plugin of id %d <|> SERVER\n", id);
	  p = NULL;
          }
	}
      if(p)for(i=1;i!=id;i++)p = p->next;
      if(p)plug_set_launch(p->value, 1);
      sprintf(list, "%s", buf);
      bzero(buf, strlen(id_list)+1);
    }
}


/*
 * Sends the status of an action
 */
void 
comm_send_status(globals, hostname, action, current,max)
  struct arglist * globals;
  char * hostname;
  char * action;
  int current, max;
{
  int ntp_version = (int)arg_get_value(globals, "ntp_version");
  if(ntp_version == NTP_10)
  {
   auth_printf(globals, "SERVER <|> STAT <|> %s <|> %d/%d <|> SERVER\n",
	      hostname, current, max);
  }
  else auth_printf(globals, "SERVER <|> STATUS <|> %s <|> %s <|> %d/%d <|> SERVER\n",
  	      hostname, action, current, max);
}
