Logo Search packages:      
Sourcecode: nessus-core version File versions

pluginscheduler.c

/* Nessus
 * Copyright (C) 1998 - 2004 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.
 *
 *
 * pluginscheduler.c : 
 *  Tells nessusd which plugin should be executed now
 *
 */
 
#include <includes.h>
#define IN_SCHEDULER_CODE 1
#include "pluginscheduler.h"
#include "pluginload.h"
#include "pluginlaunch.h"
#include "preferences.h"
#include "log.h"


#define HASH_MAX 9973


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

int plugin_get_running_state(struct scheduler_plugin * plugin)
{
 return plugin->running_state;
}

void plugin_set_running_state(plugins_scheduler_t shed, struct scheduler_plugin * plugin, int state)
{
 if(plugin == NULL)
  return;

 plugin->running_state = state;
}

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


static unsigned int mkhash(char * name)
{
  int i;
  int h = 0;
  
  for(i=0; name[i] != '\0' ;i++)
   h = ((h * 128) + name[i]) % HASH_MAX;
   
 
  return h;
}

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


struct name_cache {
      char * name;
      int occurences;
      struct name_cache * next;
      struct name_cache * prev;
      };

static struct name_cache cache[HASH_MAX + 1];
static int cache_inited = 0;

static void cache_init()
{
 bzero(cache, sizeof(cache));
 cache_inited = 1;
}

static struct name_cache * 
cache_get_name(name)
 char * name;
{
 struct name_cache * nc;
 unsigned int h;
 
 if(cache_inited == 0)cache_init();
 
 if(!name)
  return NULL;
  
 h = mkhash(name);
 nc = cache[h].next;
 
 
 while(nc != NULL)
 {
  if(nc->name != NULL && 
    !strcmp(nc->name, name))return nc;
  else 
      nc = nc->next;
 }
 return NULL;
}

static struct name_cache *
cache_add_name(name)
 char * name;
{
 struct name_cache * nc;
 unsigned int h;
 
 if(name == NULL)
  return NULL;
 
 h = mkhash(name);
 
 
 
 nc = emalloc(sizeof(struct name_cache));
 nc->name = estrdup(name);
 nc->occurences = 1;
 nc->next = cache[h].next;
 nc->prev = NULL;
 if ( cache[h].next != NULL )
  cache[h].next->prev = nc;

 cache[h].next = nc;
 
 return nc;
}

static char *
cache_inc(name)
 char * name;
{
 struct name_cache * nc = cache_get_name(name);
 if(nc != NULL)
  nc->occurences ++;
 else
   nc = cache_add_name(name);  
 return nc->name;
}

static void 
cache_dec(name)
 char * name;
{
 struct name_cache* nc;

 if( name == NULL )
  return;

 nc  = cache_get_name(name);
 if( nc == NULL )
 {
  return;
 }
 
 nc->occurences --;
 if( nc->occurences == 0 )
  {
    unsigned int h = mkhash(name);
    efree(&nc->name);

    if( nc->next != NULL)
     nc->next->prev = nc->prev;
     
    if( nc->prev != NULL )
     nc->prev->next = nc->next;
    else
     cache[h].next = nc->next;

    efree(&nc);
  }
}



/*---------------------------------------------------------------------------*
 *
 * A minimalist HASH stucture
 *
 *---------------------------------------------------------------------------*/

      

static struct hash * hash_init()
{
 struct hash * h = emalloc(sizeof(*h) * HASH_MAX + 1);

 return h;
}

static void hash_link_destroy(struct hash * h)
{
 int i;
 if(h == NULL)
  return;
  
 if(h->next != NULL)
  hash_link_destroy(h->next);
 
 if( h->dependencies != NULL )
 {
  for(i=0;h->dependencies[i] != NULL;i++)
  {
   cache_dec(h->dependencies[i]);
  }
  efree(&h->dependencies);
 }

 arg_free_all(h->plugin->required_ports);
 arg_free_all(h->plugin->required_udp_ports);
 arg_free_all(h->plugin->required_keys);
 arg_free_all(h->plugin->excluded_keys);
 efree(&h->plugin);
 
 if( h->ports != NULL )
 {
  for(i=0;h->ports[i] != NULL;i++)
  {
   cache_dec(h->ports[i]);
  }
  efree(&h->ports);
 }
 
 efree(&h);
}

static void hash_destroy(struct hash * h)
{
 int i;
 
 for(i=0;i<HASH_MAX;i++)
  {
  hash_link_destroy(h[i].next);
  }
 efree(&h);
}


static int hash_add(struct hash * h, char * name, struct scheduler_plugin * plugin)
{
 struct hash * l = emalloc(sizeof(struct hash));
 unsigned int idx = mkhash(name);
 struct arglist * deps = plug_get_deps(plugin->arglist->value);
 struct arglist * ports = plug_get_required_ports(plugin->arglist->value);
 int num_deps = 0;
 
 l->plugin = plugin;
 l->name   = name;
 l->next = h[idx].next;
 h[idx].next = l;
 
 if( deps == NULL )
  l->dependencies = NULL;
 else
 {
  struct arglist * al = deps;
  int i = 0;
  while (al->next)
  { 
   num_deps ++;
   al = al->next;
  }
  l->dependencies = emalloc((num_deps + 1) * sizeof(char*));
  al = deps;
  while (al->next != NULL)
  {
   l->dependencies[i++] = cache_inc(al->name);
   l->num_deps ++;
   al = al->next;
  }
  arg_free_all(deps);
 }
 
 if( ports == NULL )
  l->ports = NULL;
 else
  {
   struct arglist * al = ports;
   int num_ports = 0;
   int i = 0;
   while( al->next != NULL )
   {
    num_ports ++;
    al = al->next;
   }
   
   l->ports = emalloc((num_ports + 1) * sizeof(char*));
   al = ports;
   while (al->next != NULL )
   {
    l->ports[i++] = cache_inc(al->name);
    al = al->next;
   }
   arg_free_all(ports);
  }
 return 0;
}



static struct hash * _hash_get(struct hash * h, char * name)
{
 unsigned int idx = mkhash(name);
 struct hash * l = h[idx].next;
 while(l != NULL)
 {
  if(strcmp(l->name, name) == 0)
   return l;
  else
   l = l->next;
 }
 return NULL;
}

static struct scheduler_plugin * hash_get(struct hash * h, char * name)
{
 struct hash * l = _hash_get(h, name);
 if(  l == NULL )
  return NULL;
 else
  return l->plugin;
}

static char ** hash_get_ports(struct hash * h, char * name)
{
 struct hash * l = _hash_get(h, name);
 if( l == NULL)
  return NULL;
 else
  return l->ports;
}


static char ** hash_get_deps(struct hash * h, char * name)
{
 struct hash * l = _hash_get(h, name);
 
 if( l == NULL )
  return NULL;
 
 if( l->dependencies == NULL )
  return NULL;
 
 return l->dependencies;
}


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

struct plist * pl_get(struct plist * list, char * name)
{
 while(list != NULL)
 {
  if( strcmp(list->name, name) == 0 )
   return list;
  else
   list = list->next;
 }
 return NULL;
}


/*----------------------------------------------------------------------*
 *                                                    *
 * Utilities                                                *
 *                                                    *
 *----------------------------------------------------------------------*/



void scheduler_mark_running_ports(plugins_scheduler_t sched, struct scheduler_plugin * plugin)
{
 char ** ports = hash_get_ports(sched->hash, plugin->arglist->name);
 int i;
 
 if( ports == NULL )
      return;
      
 for(i=0; ports[i] != NULL; i ++ )
 {
  struct plist * pl = pl_get(sched->plist, ports[i]);
      
  if(pl != NULL)
   pl->occurences ++;
  else
  {
   pl = emalloc(sizeof(struct plist));
   strncpy(pl->name, ports[i], sizeof(pl->name) - 1); /* Share cache_inc() ? */
   pl->occurences = 1;
   pl->next = sched->plist;
   if(sched->plist != NULL)
      sched->plist->prev = pl;
   pl->prev = NULL;
   sched->plist = pl;
  }
 } 
}

void scheduler_rm_running_ports(plugins_scheduler_t sched, struct scheduler_plugin * plugin)
{
 char ** ports; 
 int i;


 
 ports = hash_get_ports(sched->hash, plugin->arglist->name);

 
 if( ports == NULL )
  return;
 
 for (i = 0 ; ports[i] != NULL ; i ++ )
 {
  struct plist * pl = pl_get(sched->plist, ports[i]);
 
      
  if( pl != NULL )
  {
   pl->occurences --;
   if( pl->occurences == 0 )
   {
    if( pl->next != NULL )
     pl->next->prev = pl->prev;
    
    if( pl->prev != NULL )
     pl->prev->next = pl->next;
    else
     sched->plist = pl->next;
    
    efree(&pl);
   }
  }
  else printf("Warning: scheduler_rm_running_ports failed ?! (%s)\n", ports[i]);
 }
}


#if DISABLED_AND_BROKEN

/*
 * Returns the 'score' of the plugin, which means the number of
 * plugins that are already hammering the port this plugin will
 * hammer too
 */
int scheduler_plugin_score(plugins_scheduler_t sched, struct scheduler_plugin * plugin)
{
 char ** ports = hash_get_ports(sched->hash, plugin->arglist->name);
 int i;
 int score = 0;
 
 if( ports == NULL ) 
  return 0;
 

 for (i = 0; ports[i] != NULL; i ++)
 {
  struct plist * pl = pl_get(sched->plist, ports[i]);
  if(pl != NULL)
  { 
   if(pl->occurences > score)
      score = pl->occurences;
  }
 } 
 return score;
}


void scheduler_plugin_best_score(plugins_scheduler_t sched, int *bscore, struct arglist ** bplugin, struct arglist * plugin)
{
 int score = scheduler_plugin_score(sched, plugin);

 if(score < *bscore)
 {
  *bscore = score;
  *bplugin = plugin;
 }
}


#endif




struct scheduler_plugin * plugin_next_unrun_dependencie(plugins_scheduler_t sched, char ** dependencies, int already_in_dependencie)
{
 struct hash * h = sched->hash;
 int flag = 0;
 int counter = 0;
 int i;
 
 if(dependencies == NULL)
  return NULL;
  
 for(i=0;dependencies[i] != NULL;i++)
  {
   struct scheduler_plugin * plugin = hash_get(h, dependencies[i]);
   if(plugin != NULL)
   {
    int state = plugin_get_running_state(plugin);
    switch(state)
    {
     case PLUGIN_STATUS_UNRUN :
      {
      char ** deps = hash_get_deps(h, plugin->arglist->name);
      struct scheduler_plugin * ret;
      counter ++;
      if(deps == NULL)
        return plugin;  
      else
       {
       ret = plugin_next_unrun_dependencie(sched, deps, 1);
       if(ret == NULL)
            return plugin;
       else 
            if( ret == PLUG_RUNNING )
                  flag ++;
            else
                  return ret;
       }
     case PLUGIN_STATUS_RUNNING:
      flag++;
      break;
     case PLUGIN_STATUS_DONE:
      scheduler_rm_running_ports(sched, plugin);      
      plugin_set_running_state(sched, plugin, PLUGIN_STATUS_DONE_AND_CLEANED);
      break;
     case PLUGIN_STATUS_DONE_AND_CLEANED:
      break;
    }
   }
  }
  else fprintf(stderr, "%s could not be found\n", dependencies[i]);
 }
  
  if(flag == 0)
      return NULL;
  else
      return PLUG_RUNNING;
}

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

/*
 * Enables a plugin and its dependencies
 */
static void enable_plugin_and_dependencies(plugins_scheduler_t shed, struct arglist * plugin, char * name, int silent)
{
 char ** deps;
 int i;
 int status;
 
 deps = hash_get_deps(shed->hash, name);

 status = plug_get_launch(plugin);
 if ( status == LAUNCH_DISABLED )
 {
  if ( silent == 0 )
   plug_set_launch(plugin, LAUNCH_RUN);
  else
   plug_set_launch(plugin, LAUNCH_SILENT);
 }
 
 if(deps != NULL)
 {
   for(i=0;deps[i] != NULL;i++)
    {
     struct scheduler_plugin * p;
     p = hash_get(shed->hash, deps[i]);
     if( p != NULL )
       enable_plugin_and_dependencies(shed, p->arglist->value, p->arglist->name, silent);
     else
       log_write("'%s' depends on '%s' which could not be found\n", name, deps[i]);
    }
 }
}

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

plugins_scheduler_t plugins_scheduler_init(struct arglist * plugins, int autoload, int silent_dependencies)
{
 plugins_scheduler_t ret = emalloc(sizeof(*ret));
 struct arglist * arg;
 int i;
 
 
 
 
 if(plugins == NULL)
  return NULL;
 
 
 /*
  * Fill our lists
  */
  ret->hash = hash_init();
  arg = plugins;
  while(arg->next != NULL)
  {
  struct scheduler_plugin * scheduler_plugin;
  struct list * dup;
  int category =  plug_get_category(arg->value);
  
  scheduler_plugin = emalloc ( sizeof(struct scheduler_plugin) ) ;
  scheduler_plugin->arglist  = arg;
  scheduler_plugin->running_state  = PLUGIN_STATUS_UNRUN;
  scheduler_plugin->category = plug_get_category(arg->value);
  scheduler_plugin->timeout  = plug_get_timeout(arg->value);

  scheduler_plugin->required_ports = plug_get_required_ports(arg->value);
  scheduler_plugin->required_udp_ports = plug_get_required_udp_ports(arg->value);
  scheduler_plugin->required_keys = plug_get_required_keys(arg->value);
  scheduler_plugin->excluded_keys = plug_get_excluded_keys(arg->value);
 

  if(category > ACT_LAST)category = ACT_LAST;
  dup = emalloc(sizeof(struct list));
  dup->name = scheduler_plugin->arglist->name;
  dup->plugin = scheduler_plugin;
  dup->prev = NULL;
  dup->next = ret->list[category];
  if(ret->list[category] != NULL)
   ret->list[category]->prev = dup;
  ret->list[category] = dup;

  hash_add(ret->hash, arg->name, scheduler_plugin);
  arg = arg->next;
  }
 
 
 if(autoload != 0)
 {
 arg = plugins;
 while(arg->next != NULL)
  {
   if(plug_get_launch(arg->value) != LAUNCH_DISABLED)
      enable_plugin_and_dependencies(ret, arg->value, arg->name, silent_dependencies);
   arg = arg->next;
  }
 }
 
 
 /* Now, remove the plugins that won't be launched */
 for(i= ACT_FIRST ; i <= ACT_LAST ; i++)
 {
  struct list * l = ret->list[i];
  while (l != NULL )
  {
   if(plug_get_launch(l->plugin->arglist->value) == LAUNCH_DISABLED)
   {
    struct list * old = l->next;

    if(l->prev != NULL)
      l->prev->next = l->next;
    else
      ret->list[i] = l->next;
        
       
     if(l->next != NULL)
        l->next->prev = l->prev;

        efree(&l);
        l = old;
      continue;
    }
    l = l->next;
   }
  }
 
 return ret;
}



struct scheduler_plugin * plugins_scheduler_next(plugins_scheduler_t h)
{
 
 struct list * l;
 int category;
 int running_category = ACT_LAST;
 int flag = 0;
 
 if(h == NULL)
  return NULL;
 
 for(category = ACT_FIRST;category<=ACT_LAST;category++)
 {
 l = h->list[category];
 
 /*
  * Scanners (and DoS) must not be run in parrallel
  */

 if((category == ACT_SCANNER) ||
    (category == ACT_KILL_HOST) ||
    (category == ACT_FLOOD) ||
    (category == ACT_DENIAL))
    pluginlaunch_disable_parrallel_checks();
 else
    pluginlaunch_enable_parrallel_checks();
  
      
 while(l != NULL)
 {
   int state;
  
  state = plugin_get_running_state(l->plugin);
 
  
  switch(state)
  {
   case PLUGIN_STATUS_UNRUN:
    {
    char ** deps = hash_get_deps(h->hash, l->plugin->arglist->name);
    
    if(deps != NULL)
    {
     struct scheduler_plugin * p = plugin_next_unrun_dependencie(h, deps, 0);
     
     switch((int)p)
     {
      case (int)NULL :
            scheduler_mark_running_ports(h, l->plugin);
        plugin_set_running_state(h, l->plugin, PLUGIN_STATUS_RUNNING);
        return l->plugin;

       break;
     case (int)PLUG_RUNNING:
        {
      /* One of the dependencie is still running  -  we write down its category */
      if(l->plugin->category < running_category)
            running_category = l->plugin->category;
      flag ++;
      }
      break;
     default:
        { 
       /* Launch a dependencie  - don't pay attention to the type */
      scheduler_mark_running_ports(h, p);
        plugin_set_running_state(h, p, PLUGIN_STATUS_RUNNING);
      return p;
       }
    }
   }
    else /* No dependencies */
     {
        scheduler_mark_running_ports(h, l->plugin);
        plugin_set_running_state(h, l->plugin, PLUGIN_STATUS_RUNNING);
        return l->plugin;
     }
   }
    break;
  case PLUGIN_STATUS_RUNNING:
        {
      if(l->plugin->category < running_category)
            running_category = l->plugin->category;
      flag ++;
      }
      break;

  case PLUGIN_STATUS_DONE :
      scheduler_rm_running_ports(h, l->plugin);
      plugin_set_running_state(h, l->plugin, PLUGIN_STATUS_DONE_AND_CLEANED);
      /* no break - we remove it right away */
  case PLUGIN_STATUS_DONE_AND_CLEANED:
      {
       struct list * old = l->next;

       if(l->prev != NULL)
        l->prev->next = l->next;
       else
        h->list[category] = l->next;
        
       
       if(l->next != NULL)
        l->next->prev = l->prev;

      efree(&l);
      l = old;
      
      continue;
      }
      break;
    }
  l = l->next; 
  }

  
  /* Could not find anything */
  if((category == ACT_SCANNER ||
     category == ACT_INIT) && flag != 0)
     {
      pluginlaunch_wait_for_free_process();
      flag = 0;
      category --;
     }
     
   if(category + 1 >= ACT_DENIAL && flag && running_category < ACT_DENIAL)
      { 
      return PLUG_RUNNING;  
      }
 }
 

 return flag != 0 ? PLUG_RUNNING : NULL;
}


void list_destroy(struct list * list)
{
 while(list != NULL)
 {
  struct list * next = list->next;
  efree(&list);
  list = next;
 }
}


void plugins_scheduler_free(plugins_scheduler_t sched)
{
 int i;
 hash_destroy(sched->hash);
 for(i=ACT_FIRST;i<ACT_LAST;i++)
      list_destroy(sched->list[i]); 
 efree(&sched);
}

Generated by  Doxygen 1.6.0   Back to index