/* Nessus
 * Copyright (C) 1998 - 2003 Renaud Deraison
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2,
 * as published by the Free Software Foundation
 *
 * 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.
 *
 * In addition, as a special exception, Renaud Deraison
 * gives permission to link the code of this program with any
 * version of the OpenSSL library which is distributed under a
 * license identical to that listed in the included COPYING.OpenSSL
 * file, and distribute linked combinations including the two.
 * You must obey the GNU General Public License in all respects
 * for all of the code used other than OpenSSL.  If you modify
 * this file, you may extend this exception to your version of the
 * file, but you are not obligated to do so.  If you do not wish to
 * do so, delete this exception statement from your version.
 *
 * Attack.c : 
 *  launch the plugins, and manages the multithreading 
 *
 */
 
#include <includes.h>
#include "attack.h"
#include "log.h"
#include "hosts_gatherer.h"
#include "sighand.h"
#include "rules.h"
#include "auth.h"
#include "processes.h"
#include "comm.h" 
#include "utils.h"
#include "preferences.h"
#include "ntp.h"
#include "ntp_11.h"
#include "pluginload.h"
#include "save_tests.h"
#include "save_kb.h"
#include "detached.h"

#include "pluginscheduler.h"
#include "pluginlaunch.h"
#include "plugs_req.h"
#include "hosts.h"

#define ERR_HOST_DEAD -1
#define ERR_CANT_FORK -2

#define MAX_FORK_RETRIES 10

extern u_short * getpts(char *, int *);

struct attack_start_args {
        struct arglist * globals;
        struct in_addr hostip;
        char * host_mac_addr;
        plugins_scheduler_t sched;
        int thread_socket;
        struct hg_globals * hg_globals;
        char hostname[1024];
};

/*******************************************************

		PRIVATE FUNCTIONS
		
********************************************************/


static void 
fork_sleep(int n)
{
 time_t then, now;
 
 now = then = time(NULL);
 while(now - then < n )
 {
   waitpid(-1, NULL, WNOHANG);
   usleep(10000);
   now = time(NULL);
 }
}
 

static void
attack_sigterm()
{
 hosts_stop_all();
 wait_for_children();
}


static void 
arg_addset_value(arg, name, type, len, value)
 struct arglist *arg;
 char * name;
 int type, len;
 void * value;
{
 if(arg_get_type(arg, name) < 0)
  arg_add_value(arg, name, type, len, value);
 else
  arg_set_value(arg, name, len, value);
}



/*-------------------------------------------------------

	Init. an arglist which can be used by 
	the plugins from an hostname and its ip
	
--------------------------------------------------------*/	
static struct arglist * 
attack_init_hostinfos(mac, hostname, ip)
     char * mac;
     char * hostname;
    struct in_addr * ip;
{
  struct arglist * hostinfos;
  struct in_addr addr;
  
  hostinfos = emalloc(sizeof(struct arglist));
  if(inet_aton(hostname, &addr) != 0)
  {
   char f[1024];
   hg_get_name_from_ip(addr, f, sizeof(f));
   arg_add_value(hostinfos, "FQDN", ARG_STRING, strlen(f), estrdup(f));
  }
  else
   arg_add_value(hostinfos, "FQDN", ARG_STRING, strlen(hostname), estrdup(hostname));
   
   
  if(mac)
  {
  	arg_add_value(hostinfos, "NAME", ARG_STRING, strlen(mac), mac);
	arg_add_value(hostinfos, "MAC", ARG_STRING, strlen(mac), mac);
  }
  else
  	arg_add_value(hostinfos, "NAME", ARG_STRING, strlen(hostname), estrdup(hostname));
	
  arg_add_value(hostinfos, "IP", ARG_PTR, sizeof(struct in_addr), ip);
  return(hostinfos);
}

/*--------------------------------------------------------
	
		 Return our user name
 
 ---------------------------------------------------------*/
 
static char *
attack_user_name(globals)
 struct arglist * globals;
{
 static char * user;
 if(!user)
   user = (char*)arg_get_value(globals, "user");
  
 return user;
}


static int
launch_plugin(globals, sched, plugin, hostname, cur_plug, num_plugs, hostinfos, kb, new_kb)
 struct arglist * globals;
 plugins_scheduler_t * sched;
 struct scheduler_plugin * plugin;
 char * hostname;
 int *cur_plug, num_plugs;
 struct arglist * hostinfos;
 struct kb_item ** kb;
 int new_kb;
{
  struct arglist * preferences = arg_get_value(globals,"preferences");
  struct arglist * args = plugin->arglist->value;
  char name[1024];
  int optimize = preferences_optimize_test(preferences);
  int category = plugin->category;
  static int last_status = 0;
      
  strncpy(name, plug_get_path(args), sizeof(name) - 1);
  name[sizeof(name) - 1 ] = '\0';

  if(plug_get_launch(args) || 
     category == ACT_INIT ||
    (category == ACT_SETTINGS)) /* can we launch it ? */
  {
   char * error;
   
   pl_class_t * cl_ptr = arg_get_value(args, "PLUGIN_CLASS");
   
  
  if(preferences_safe_checks_enabled(preferences) && 
  	(category == ACT_DESTRUCTIVE_ATTACK ||
	 category == ACT_KILL_HOST ||
	 category == ACT_FLOOD ||
	 category == ACT_DENIAL))
	 	{
		if(preferences_log_whole_attack(preferences))
		  log_write("user %s : Not launching %s against %s %s (this is not an error)\n",
	       			attack_user_name(globals),
				plugin->arglist->name, 
				hostname, 
				"because safe checks are enabled");
		plugin_set_running_state(sched, plugin, PLUGIN_STATUS_DONE);
		return 0;
		}

   (*cur_plug) ++;
   if ( ( *cur_plug * 100 ) / num_plugs  >= last_status )
   {
    last_status = (*cur_plug * 100 ) / num_plugs  + 2;
    if ( comm_send_status(globals, hostname, "attack", *cur_plug, num_plugs) < 0 )
    {
     /* Could not send our status back to our father -> exit */
     pluginlaunch_stop();
     return ERR_HOST_DEAD;
    }
   }


    if(save_kb(globals))
    {
     int id = plug_get_id(args);
     char asc_id[30];
	 
     snprintf(asc_id, sizeof(asc_id), "Launched/%d", id);
     if(kb_item_get_int(kb, asc_id) > 0 &&
	    !save_kb_replay_check(globals, category))
	  {
	   /* 
	    * XXX determine here if we should skip
	    * ACT_SCANNER, ACT_GATHER_INFO, ACT_ATTACK and ACT_DENIAL
	    */
	   if(preferences_log_whole_attack(preferences))
	    log_write("user %s : Not launching %s against %s %s (this is not an error)\n",
	       			attack_user_name(globals),
				plugin->arglist->name, 
				hostname, 
				"because it has already been launched in the past");
	   plugin_set_running_state(sched, plugin, PLUGIN_STATUS_DONE);			
	   return 0;
	  }
	  else {
                kb_item_add_int(kb, asc_id, 1);
		save_kb_write_int(globals, hostname, asc_id,  1);
		}
       }	     
	
	
	 
	 if(!optimize || !(error = requirements_plugin(kb, plugin, preferences)))
	 {
	  int pid;
	
	 /*
	  * Start the plugin
	  */
	 pid = plugin_launch(globals,sched, plugin, hostinfos, preferences, kb, name, cl_ptr);
	 if(pid  < 0)	
	 	{
		plugin_set_running_state(sched, plugin, PLUGIN_STATUS_UNRUN);
		return ERR_CANT_FORK;
		}
		 
	 if(preferences_log_whole_attack(preferences))
	 	log_write("user %s : launching %s against %s [%d]\n", 
	 				attack_user_name(globals),
					plugin->arglist->name, 
					hostname,
					pid);
					
	 	     
	 /*
	  * Stop the test if the host is 'dead'
	  */	 
        if(kb_item_get_int(kb, "Host/dead") > 0 ||
	   kb_item_get_int(kb, "Host/ping_failed") > 0)
	{
	  log_write("user %s : The remote host (%s) is dead\n",
	  				attack_user_name(globals),
	  				hostname);
	  pluginlaunch_stop();		
	  if(new_kb)save_kb_close(globals, hostname);	
	  if(kb_item_get_int(kb, "Host/ping_failed") > 0)
	  {
	   save_kb_restore_backup(globals, hostname);
	  }
	  
	  plugin_set_running_state(sched, plugin, PLUGIN_STATUS_DONE);				
	  return ERR_HOST_DEAD;
	}
       }
       
       else /* requirements_plugin() failed */
	  {
	   plugin_set_running_state(sched, plugin, PLUGIN_STATUS_DONE);
	   if(preferences_log_whole_attack(preferences))
	    log_write("user %s : Not launching %s against %s %s (this is not an error)\n",
	       			attack_user_name(globals),
				plugin->arglist->name, 
				hostname, 
				error);
	
	  }
      } /* if(plugins->launch) */
      else    
       plugin_set_running_state(sched, plugin, PLUGIN_STATUS_DONE);
       
      return 0;
}

/*--------------------------------------------------------
	
	          Attack _one_ host

----------------------------------------------------------*/	
static void 
attack_host      (globals, hostinfos, hostname,  sched) 
     
     struct arglist * globals;
     struct arglist * hostinfos;
     char * hostname;
     plugins_scheduler_t sched;
{ 

  /*
   * Used for the status
   */
  int num_plugs = 0;
  int cur_plug = 1;
  
  struct kb_item ** kb;
  int new_kb = 0;
  int kb_restored = 0;
 int forks_retry = 0;
 struct arglist * plugins = arg_get_value(globals, "plugins");
 struct arglist * tmp;
 
  setproctitle("testing %s", (char*)arg_get_value(hostinfos, "NAME"));
  
  if(save_kb(globals))
  {
   if( save_kb_exists(globals, hostname) != 0 && 
       save_kb_pref_restore(globals) != 0 )
     {
      save_kb_backup(globals, hostname);
      kb = save_kb_load_kb(globals, hostname);
      kb_restored = 1; 
     }
   else 
    {
     save_kb_new(globals, hostname);
     kb = kb_new();
     new_kb = 1;
    }

  arg_add_value(globals, "CURRENTLY_TESTED_HOST", ARG_STRING, strlen(hostname), hostname);
 }
 else kb = kb_new();
  

 num_plugs = get_active_plugins_number(plugins);
  
  tmp = emalloc(sizeof(struct arglist));
  arg_add_value(tmp, "HOSTNAME", ARG_ARGLIST, -1, hostinfos);
  
    
  /* launch the plugins */
  pluginlaunch_init(globals);
  
   
   for(;;)
   {
    struct scheduler_plugin * plugin;
    pid_t parent;
    
    /*
     * Check that our father is still alive 
     */
    parent = getppid();
    if(parent <= 1 || process_alive(parent) == 0 )
    {
     pluginlaunch_stop();
     return;
    }
     
    plugin = plugins_scheduler_next(sched);
    if(plugin != NULL && plugin != PLUG_RUNNING)
    { 
      int e;
 again:        
      if((e = launch_plugin( globals, sched, plugin, hostname, &cur_plug, num_plugs, hostinfos, kb, new_kb))  < 0)
		    {
		     /*
		      * Remote host died
		      */
		     if(e == ERR_HOST_DEAD)
		     	goto host_died;
		     else if(e == ERR_CANT_FORK )
		     {
		      if(forks_retry < MAX_FORK_RETRIES)
		      {
		       forks_retry++;
		       log_write("fork() failed - sleeping %d seconds (%s)", forks_retry, strerror(errno));
		       fork_sleep(forks_retry);
		       goto again;
		      }
		      else {
		      	log_write("fork() failed too many times - aborting");
			goto host_died;
			}
		     }
		    }
      }
     else if(plugin == NULL) break;
     else pluginlaunch_wait_for_free_process();
    }
  pluginlaunch_wait();
host_died: 
  arg_free(tmp); 
  pluginlaunch_stop();
  plugins_scheduler_free(sched);
  if(new_kb)save_kb_close(globals, hostname);
}

/*-----------------------------------------------------------------

  attack_start : set up some data and jump into
  attack_host()

 -----------------------------------------------------------------*/
static void
attack_start(args)
  struct attack_start_args * args;
{
 struct arglist * globals = args->globals;
 char * hostname = args->hostname;
 char * mac = args->host_mac_addr;
 struct arglist * plugs = arg_get_value(globals, "plugins");
 struct in_addr * hostip = &(args->hostip);
 struct arglist * hostinfos;
 
 struct arglist * preferences = arg_get_value(globals,"preferences");
 char * non_simult = arg_get_value(preferences, "non_simult_ports");
 int thread_socket = args->thread_socket;
 int soc;
 struct timeval then, now;
 plugins_scheduler_t sched = args->sched;
 int i;


 thread_socket = dup2(thread_socket, 4);
 for(i=5;i<getdtablesize();i++)
 {
  close(i);
 }


 gettimeofday(&then, NULL);


 if( non_simult == NULL )
 	{
        non_simult = estrdup("139, 445");
 	arg_add_value(preferences, "non_simult_ports", ARG_STRING, strlen(non_simult), non_simult);
	}
 arg_add_value(preferences, "non_simult_ports_list", ARG_ARGLIST, -1, (void*)list2arglist(non_simult));
 /*
  * Options regarding the communication with our father
  */
 nessus_deregister_connection((int)arg_get_value(globals, "global_socket"));
 arg_set_value(globals, "global_socket", -1, (void*)thread_socket);
 
 /*
  * Wait for the server to confirm it read our data
  * (prevents client desynch)
  */
 arg_add_value(globals, "confirm", ARG_INT, sizeof(int), (void*)1);
 
 soc = thread_socket;
 hostinfos = attack_init_hostinfos(mac, hostname,hostip);
 if(mac)
  hostname = mac;
  

  plugins_set_socket(plugs, soc);
  ntp_1x_timestamp_host_scan_starts(globals, hostname);
  attack_host(globals, hostinfos, hostname, sched);
  if(preferences_ntp_show_end(preferences))ntp_11_show_end(globals, hostname, 1);
  ntp_1x_timestamp_host_scan_ends(globals, hostname);
  gettimeofday(&now, NULL);
  if(now.tv_usec < then.tv_usec)
  {
   then.tv_sec ++;
   now.tv_usec += 1000000;
  }
  log_write("Finished testing %s. Time : %ld.%.2ld secs\n",
  		hostname,
  		(long)(now.tv_sec - then.tv_sec),
		(long)((now.tv_usec - then.tv_usec) / 10000));
  shutdown(soc, 2);		
  close(soc);
}

/*******************************************************

		PUBLIC FUNCTIONS
		
********************************************************/


/*------------------------------------------------

   This function attacks a whole network
 		
 -----------------------------------------------*/
int 
attack_network(globals)
    struct arglist * globals;
{
  int max_hosts			= 0;
  int num_tested		= 0;
  int host_pending		= 0;
  char hostname[1024];
  char * hostlist;
  struct in_addr host_ip;
  int hg_flags			= 0;
  int hg_res;
  struct hg_globals * hg_globals = NULL;
  int global_socket		= -1;
  struct arglist * preferences  = NULL;
  struct arglist * plugins      = NULL;
  ntp_caps* caps		= NULL;
  struct nessus_rules *rules	= NULL;
  struct arglist * rejected_hosts =  NULL;
  int restoring    = 0;
  harglst * tested = NULL;
  int  save_session= 0;  
  int continuous   = 0;
  int detached     = 0;
  hargwalk *  hw;
  harglst * files;
  char * key;
  int return_code = 0;
  char * port_range;
  plugins_scheduler_t sched;
  int fork_retries = 0;

  host_ip.s_addr = 0;
  preferences    = arg_get_value(globals, "preferences");
  detached = preferences_detached_scan(preferences);
  if(detached)
  {
   char *email;
   
   detached_new_session(globals, arg_get_value(preferences, "TARGET"));
   arg_addset_value(preferences, "ntp_keep_communication_alive", ARG_STRING, 0, NULL);
   
   /* 
    * Tell the client that the scan is finished (actually, we will
    * work hard to test the network, but this lazy client has the right
    * to get some rest...
    */
   log_write("user %s : running a detached scan\n", (char*)arg_get_value(globals, "user"));
   global_socket = (int)arg_get_value(globals, "global_socket");
   comm_terminate(globals);
   close_stream_connection(global_socket);
   global_socket = -1;
   arg_set_value(globals, "global_socket", sizeof(int), (void*)global_socket);
   
   nessus_signal(SIGTERM, attack_sigterm);
   
start_attack_network:
   if((email = preferences_detached_scan_email(preferences)))
   {
    /*
     * The user wants to receive the results by e-mail.
     */
    if(detached_setup_mail_file(globals, email))
    {
     /*
      * Could not create the file to store our data
      */
     close_stream_connection(global_socket);
     return -1;
    }
   }
   else arg_addset_value(globals, "detached_scan_email_address", ARG_STRING, 0, NULL);
  }  
  num_tested = 0;

  
  global_socket  = (int)arg_get_value(globals, "global_socket");
 
  plugins        = arg_get_value(globals, "plugins");
  caps           = arg_get_value(globals, "ntp_caps");
  rules          = arg_get_value(globals, "rules");
  rejected_hosts = emalloc(sizeof(struct arglist));
  
  if(detached)
    continuous = preferences_continuous_scan(preferences);
  
  save_session = preferences_save_session(preferences);
  if(continuous)
   restoring = 0;
  else
   restoring = ((int)arg_get_value(globals, "RESTORE-SESSION") == 1);
   
  if(restoring)tested = arg_get_value(globals, "TESTED_HOSTS");
  if(save_session)save_tests_init(globals);  


  hostlist = arg_get_value(preferences, "TARGET");
  if( hostlist == NULL ){
  	log_write("%s : TARGET not set ?!", 
			attack_user_name(globals));
	EXIT(1);
	}		
  
  
  port_range = arg_get_value(preferences, "port_range");
  if( port_range == NULL ||
      port_range[0] == '\0' )
      	port_range = "1-15000";
  
  if( strcmp(port_range, "-1") != 0 )
  {
   unsigned short * ports;
   ports = (unsigned short*)getpts(port_range, NULL);
   if( ports == NULL){
   	auth_printf(globals, "SERVER <|> ERROR <|> Invalid port range <|> SERVER\n");
	return -1; 
	}
  }
  /*
   * Initialization of the attack
   */
  sched  = plugins_scheduler_init(plugins,  preferences_autoload_dependencies(preferences) ); 
  
  
  hg_flags = preferences_get_host_expansion(preferences);
  max_hosts = get_max_hosts_number(globals, preferences);
  
  
  if( restoring == 0)
  {
  int max_checks  = get_max_checks_number(globals, preferences);
  log_write("user %s starts a new attack. Target(s) : %s, with max_hosts = %d and max_checks = %d\n",
			 attack_user_name(globals), 
			 hostlist,
			 max_hosts, 
			 max_checks);
  }
  else
  {
   int max_checks  = get_max_checks_number(globals, preferences);
   log_write("user %s restores session %s, with max_hosts = %d and max_checks = %d\n",
   			attack_user_name(globals),
			(char*)arg_get_value(globals, "RESTORE-SESSION-KEY"),
			max_hosts,
			max_checks);
			
   save_tests_playback(globals, arg_get_value(globals, "RESTORE-SESSION-KEY"),tested);
  }
  
  			 
  /* 
   * Initialize the hosts_gatherer library 
   */
  if ( preferences_get_slice_network_addresses ( preferences ) != 0 )
  	hg_flags |= HG_DISTRIBUTE;
				  
  hg_globals = hg_init(hostlist, hg_flags);
  hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
  if( tested != NULL )
   while(hg_res >= 0 && 
         harg_get_int( tested, hostname ) != 0 )
	 		{
			hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
			}
			
			
  if( hg_res < 0 )
   goto stop;
   
   hosts_init(global_socket, max_hosts);
  /*
   * Start the attack !
   */
   
   while( hg_res >= 0 )
    {
      nthread_t pid;
      
      
   /*
    * nessusd offers the ability to either test
    * only the hosts we tested in the past, or only
    * the hosts we never tested (or both, of course)
    */
   if(save_kb(globals))
    {
    if(save_kb_pref_tested_hosts_only(globals))
    {
    if(!save_kb_exists(globals, hostname))
     {
      log_write("user %s : not testing %s because it has never been tested before\n",
      		 attack_user_name(globals), 
		 hostname);
      hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
      if( tested != NULL )
      {
        while(hg_res >= 0 &&  harg_get_int( tested, hostname ) != 0 )
	 		hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
      }			
      continue;
     }
   }
   else if(save_kb_pref_untested_hosts_only(globals))
   {
    /* XXX */
    if(save_kb_exists(globals, hostname))
    {
     log_write("user %s : not testing %s because it has already been tested before\n", 
     			attack_user_name(globals), 
			hostname);
     hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
     if( tested != NULL )
      {
        while(hg_res >= 0 &&  harg_get_int( tested, hostname ) != 0 )
	 		hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
      }	
     continue;
    }
   }
  }

      host_pending = 0 ;
      if(CAN_TEST(get_host_rules(rules, host_ip,32)) == 0) /* do we have the right to test this host ? */ 
      {
       log_write("user %s : rejected attempt to scan %s", 
			attack_user_name(globals), hostname);
       arg_add_value(rejected_hosts, hostname, ARG_INT, sizeof(int), (void*)1);	
      }
      else
      {
        struct attack_start_args args;
	int s;
	char * MAC = NULL;
	int mac_err = -1;

	
	
	if(preferences_use_mac_addr(preferences) &&
	   is_local_ip(host_ip))
	{
	 mac_err = get_mac_addr(host_ip, &MAC);
	 if(mac_err > 0)
	 {
	  /* remote host is down */
	  hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
	  if( tested != NULL )
	  {
   		while(hg_res >= 0 && harg_get_int( tested, hostname ) != 0 )
	 		hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
	  }		
	  continue;
	 }
	}
	
	s = hosts_new(globals, hostname);
	if(s < 0)goto scan_stop;
	 
         

	args.globals = globals;
	strncpy(args.hostname, hostname, sizeof(args.hostname) - 1);
	args.hostname[sizeof(args.hostname) - 1] = '\0';
        args.hostip.s_addr = host_ip.s_addr;
        args.host_mac_addr = MAC;
        args.sched = sched;
        args.thread_socket = s;
   
forkagain:        
	pid = create_process((process_func_t)attack_start, &args); 
	if(pid < 0)
	 {
          fork_retries ++;
          if(fork_retries > MAX_FORK_RETRIES)
          {
	  log_write("fork() failed - %s. %s won't be tested\n", strerror(errno), hostname);
	  /*
	   * forking failed - we go to the wait queue
	   */
	  efree(&MAC);
          goto stop;
          }
          log_write("fork() failed - sleeping %d seconds and trying again...\n", fork_retries);
          fork_sleep(fork_retries);
          goto forkagain;
	 }

        hosts_set_pid(hostname, pid);
	log_write("user %s : testing %s (%s) [%d]\n", attack_user_name(globals), hostname, inet_ntoa(args.hostip), pid);
        if(MAC != NULL)efree(&MAC);
	} 
	
        
       num_tested++;
       hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
       if(tested != NULL)
         {
	 while(hg_res >= 0 &&
	       harg_get_int(tested, hostname))
		{
		hg_res = hg_next_host(hg_globals, &host_ip, hostname, sizeof(hostname));
		}
	}
     }
 
   
    

  /*
   * Every host is being tested... We have to wait for the threads
   * to terminate
   */
  
  while(hosts_read(globals) == 0);
  log_write("user %s : test complete", attack_user_name(globals));
scan_stop:    
   /*
     * Delete the files uploaded by the user, if any
     */
    files = arg_get_value(globals, "files_translation");
    if(files)
    {
     hw  = harg_walk_init(files);
     while((key = (char*)harg_walk_next(hw)))
      {
      unlink(harg_get_string(files, key));
      }
    }
 
  if(rejected_hosts && rejected_hosts->next)
   {
     char * banner = emalloc(4001);
     int length = 0;

     sprintf(banner, "SERVER <|> ERROR <|> These hosts could not be tested because you are not allowed to do so :;");
     length = strlen(banner);

     while(rejected_hosts->next && (length < (4000-3)))
	{
	  int n;
	  n = strlen(rejected_hosts->name);
	  if(length + n + 1 >= 4000)
	  {
	    n = 4000 - length  - 2;
	  }
	  strncat(banner, rejected_hosts->name, n);
	  strncat(banner, ";", 1);
	  length+=n+1;
	  rejected_hosts = rejected_hosts->next;
	}
      if( rejected_hosts->next != NULL )
       strcat(banner, "...");
       
     auth_printf(globals, "%s\n", banner);
   }
	
stop:
  if(save_session){
  	save_tests_close(globals);
	if(!preferences_save_empty_sessions(preferences))
	{
	 if(save_tests_empty(globals))
          {
            log_write("user %s : Nothing interesting found - deleting the session\n",
    		(char*)arg_get_value(globals, "user"));
             save_tests_delete_current(globals);
	  }
        }
   }
  
  hg_cleanup(hg_globals);
  
  arg_free_all(rejected_hosts);
  plugins_scheduler_free(sched);
  if(detached)
  {
   if(preferences_detached_scan_email(preferences))
    detached_send_email(globals);
  }
  
  if(continuous){
  	sleep(preferences_delay_between_scans(preferences));
	plugins = plugins_reload(preferences, plugins);
	arg_set_value(globals, "plugins", -1, plugins);
  	goto start_attack_network;
	}
  else if(detached)detached_end_session(globals);	
  
  return return_code;
}

   
 
