OpenVAS Scanner  5.1.3
pluginscheduler.c
Go to the documentation of this file.
1 /* OpenVAS
2 * $Id$
3 * Description: Tells openvassd which plugin should be executed next.
4 *
5 * Authors: - Renaud Deraison <deraison@nessus.org> (Original pre-fork develoment)
6 * - Tim Brown <mailto:timb@openvas.org> (Initial fork)
7 * - Laban Mwangi <mailto:labanm@openvas.org> (Renaming work)
8 * - Tarik El-Yassem <mailto:tarik@openvas.org> (Headers section)
9 *
10 * Copyright:
11 * Portions Copyright (C) 2006 Software in the Public Interest, Inc.
12 * Based on work Copyright (C) 1998 - 2006 Tenable Network Security, Inc.
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2,
16 * as published by the Free Software Foundation
17 *
18 * This program is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with this program; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26 *
27 *
28 */
29 
30 #include <string.h> /* for strcmp() */
31 
32 #include <openvas/base/nvti.h> /* for nvti_t */
33 
34 #include <openvas/misc/nvt_categories.h> /* for ACT_SCANNER */
35 #include <openvas/misc/plugutils.h> /* for plug_get_launch */
36 
37 #include <openvas/base/nvticache.h> /* for nvticache_t */
38 
39 #include <glib.h>
40 
41 #include "pluginscheduler.h"
42 #include "pluginload.h"
43 #include "pluginlaunch.h"
44 #include "log.h"
45 
50 #define HASH_MAX 2713
51 
52 struct hash
53 {
56  struct hash *next;
57 };
58 
59 struct list
60 {
62  struct list *next;
63  struct list *prev;
64 };
65 
66 struct plist
67 {
68  gchar *name;
70  struct plist *next;
71  struct plist *prev;
72 };
73 
75 {
76  struct hash *hash;
77  struct list *list[ACT_LAST + 1];
78  struct plist *plist;
79 };
80 
81 static unsigned int
82 mkhash (char *name)
83 {
84  return g_str_hash (name) % HASH_MAX;
85 }
86 
87 
88 /*---------------------------------------------------------------------------*
89  *
90  * A minimalist HASH stucture
91  *
92  *---------------------------------------------------------------------------*/
93 
94 static struct hash *
95 hash_init ()
96 {
97  struct hash *h = g_malloc0 (HASH_MAX * sizeof (*h));
98 
99  return h;
100 }
101 
102 static void
103 hash_link_destroy (struct hash *h)
104 {
105  if (h == NULL)
106  return;
107 
108  if (h->next != NULL)
109  hash_link_destroy (h->next);
110 
111  g_free (h->dependencies_ptr);
112  g_free (h->plugin);
113  g_free (h);
114 }
115 
116 static void
117 hash_destroy (struct hash *h)
118 {
119  int i;
120 
121  for (i = 0; i < HASH_MAX; i++)
122  {
123  hash_link_destroy (h[i].next);
124  }
125  g_free (h);
126 }
127 
128 
129 static void
130 hash_add (struct hash *h, struct scheduler_plugin *plugin)
131 {
132  struct hash *l = g_malloc0 (sizeof (struct hash));
133  unsigned int idx = mkhash (plugin->oid);
134 
135  l->plugin = plugin;
136  l->plugin->parent_hash = l;
137  l->next = h[idx].next;
138  h[idx].next = l;
139  l->dependencies_ptr = NULL;
140 
141 }
142 
143 
144 static struct hash *
145 _hash_get (struct hash *h, char *name)
146 {
147  unsigned int idx = mkhash (name);
148  struct hash *l = h[idx].next;
149  while (l != NULL)
150  {
151  if (strcmp (l->plugin->oid, name) == 0)
152  return l;
153  else
154  l = l->next;
155  }
156  return NULL;
157 }
158 
159 
160 static struct hash **
161 hash_get_deps_ptr (struct hash *h, char *name)
162 {
163  struct hash *l = _hash_get (h, name);
164 
165  if (l == NULL)
166  return NULL;
167 
168  return l->dependencies_ptr;
169 }
170 
171 static void
172 hash_fill_deps (struct hash *h, struct hash *l)
173 {
174  int i, j = 0, num_deps;
175  char *dependencies, **array;
176 
177  if (!l->plugin)
178  return;
179  dependencies = nvticache_get_dependencies (l->plugin->oid);
180  if (!dependencies)
181  return;
182  array = g_strsplit (dependencies, ", ", 0);
183  g_free (dependencies);
184  if (!array)
185  return;
186 
187  for (num_deps = 0; array[num_deps]; num_deps++)
188  ;
189  if (num_deps == 0)
190  return;
191 
192  l->dependencies_ptr = g_malloc0 ((1 + num_deps) * sizeof (struct hash *));
193  for (i = 0; array[i]; i++)
194  {
195  char *oid;
196  struct hash *d;
197 
198  oid = nvticache_get_oid (array[i]);
199  if (!oid)
200  {
201  log_write ("scheduler: %s depends on %s which could not be found",
202  l->plugin->oid, array[i]);
203  continue;
204  }
205  d = _hash_get (h, oid);
206  if (d != NULL)
207  l->dependencies_ptr[j++] = d;
208  else
209  log_write ("scheduler: %s depends on %s which could not be found",
210  l->plugin->oid, array[i]);
211  g_free (oid);
212  }
213  l->dependencies_ptr[j] = NULL;
214  g_strfreev (array);
215 }
216 
217 /*----------------------------------------------------------------------*/
218 
219 struct plist *
220 pl_get (struct plist *list, char *name)
221 {
222  while (list != NULL)
223  {
224  if (strcmp (list->name, name) == 0)
225  return list;
226  else
227  list = list->next;
228  }
229  return NULL;
230 }
231 
232 
233 /*----------------------------------------------------------------------*
234  * *
235  * Utilities *
236  * *
237  *----------------------------------------------------------------------*/
238 
239 
240 
241 void
243  struct scheduler_plugin *plugin)
244 {
245  char *ports, **array;
246  int i;
247 
248  ports = nvticache_get_required_ports (plugin->oid);
249  if (!ports)
250  return;
251 
252  array = g_strsplit (ports, ", ", 0);
253  g_free (ports);
254  if (!array)
255  return;
256  for (i = 0; array[i] != NULL; i++)
257  {
258  struct plist *pl = pl_get (sched->plist, array[i]);
259 
260  if (pl != NULL)
261  pl->occurences++;
262  else
263  {
264  pl = g_malloc0 (sizeof (struct plist));
265  pl->name = g_strdup (array[i]);
266  pl->occurences = 1;
267  pl->next = sched->plist;
268  if (sched->plist != NULL)
269  sched->plist->prev = pl;
270  pl->prev = NULL;
271  sched->plist = pl;
272  }
273  }
274  g_strfreev (array);
275 }
276 
277 void
279  struct scheduler_plugin *plugin)
280 {
281  char *ports, **array;
282  int i;
283 
284  ports = nvticache_get_required_ports (plugin->oid);
285  if (!ports)
286  return;
287 
288  array = g_strsplit (ports, ", ", 0);
289  g_free (ports);
290  if (!array)
291  return;
292  for (i = 0; array[i] != NULL; i++)
293  {
294  struct plist *pl = pl_get (sched->plist, array[i]);
295 
296  if (pl != NULL)
297  {
298  pl->occurences--;
299  if (pl->occurences == 0)
300  {
301  if (pl->next != NULL)
302  pl->next->prev = pl->prev;
303 
304  if (pl->prev != NULL)
305  pl->prev->next = pl->next;
306  else
307  sched->plist = pl->next;
308 
309  g_free (pl->name);
310  g_free (pl);
311  }
312  }
313  else
314  log_write ("Warning: scheduler_rm_running_ports failed ?! (%s)\n",
315  array[i]);
316  }
317  g_strfreev (array);
318 }
319 
320 
321 struct scheduler_plugin *
323  struct hash **dependencies_ptr, int calls)
324 {
325  int flag = 0;
326  int i;
327 
328  if (dependencies_ptr == NULL)
329  return NULL;
330 
331  if (calls > 100)
332  {
333  log_write ("Possible dependency cycle detected %s",
334  dependencies_ptr[0]->plugin->oid);
335  return NULL;
336  }
337  if (calls && calls % 15 == 0)
339 
340  for (i = 0; dependencies_ptr[i] != NULL; i++)
341  {
342  struct scheduler_plugin *plugin;
343 
344  plugin = dependencies_ptr[i]->plugin;
345  if (plugin == NULL)
346  continue;
347 
348  switch (plugin->running_state)
349  {
350  case PLUGIN_STATUS_UNRUN:
351  {
352  struct hash **deps_ptr;
353  struct scheduler_plugin *ret;
354 
355  deps_ptr = dependencies_ptr[i]->dependencies_ptr;
356  if (deps_ptr == NULL)
357  return plugin;
358 
359  ret = plugin_next_unrun_dependency (sched, deps_ptr, calls + 1);
360  if (ret == NULL)
361  return plugin;
362 
363  if (ret == PLUG_RUNNING)
364  flag = 1;
365  else
366  return ret;
367  }
368  break;
370  flag = 1;
371  break;
372  case PLUGIN_STATUS_DONE:
373  scheduler_rm_running_ports (sched, plugin);
375  break;
377  break;
378  }
379  }
380 
381  if (!flag)
382  return NULL;
383 
384  return PLUG_RUNNING;
385 }
386 
387 /*---------------------------------------------------------------------------*/
388 
389 /*
390  * Enables a plugin and its dependencies
391  */
392 static void
393 enable_plugin_and_dependencies (plugins_scheduler_t shed,
394  struct scheduler_plugin *plugin,
395  GHashTable *deps_table)
396 {
397  struct hash **deps_ptr;
398  int i;
399 
400  if (plugin == NULL)
401  return;
402 
403  if (g_hash_table_lookup (deps_table, plugin->oid))
404  return;
405  else
406  g_hash_table_insert (deps_table, g_strdup (plugin->oid), plugin->oid);
407 
408  plugin->enabled = TRUE;
409  deps_ptr = hash_get_deps_ptr (shed->hash, plugin->oid);
410  if (deps_ptr == NULL)
411  return;
412  for (i = 0; deps_ptr[i] != NULL; i++)
413  {
414  struct scheduler_plugin *p;
415  p = deps_ptr[i]->plugin;
416  if (p)
417  enable_plugin_and_dependencies (shed, p, deps_table);
418  }
419 }
420 
421 /*---------------------------------------------------------------------------*/
422 
423 /*
424  * Enable plugins in scheduler, from a list.
425  *
426  * param[in] sched Plugins scheduler.
427  * param[in] oid_list List of plugins to enable.
428  * param[in] autoload Whether to autoload dependencies.
429  */
430 static void
431 plugins_scheduler_enable (plugins_scheduler_t sched, const char *oid_list,
432  int autoload)
433 {
434  int i;
435  char *oids, *oid;
436  GHashTable *oids_table;
437 
438  oids_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
439 
440  /* Store list of plugins in hashtable. */
441  oids = g_strdup (oid_list);
442  oid = strtok (oids, ";");
443  while (oid)
444  {
445  g_hash_table_insert (oids_table, oid, oid);
446  oid = strtok (NULL, ";");
447  }
448 
449  /* Enable plugins found in hashtable. */
450  for (i = ACT_FIRST; i <= ACT_LAST; i++)
451  {
452  struct list *element = sched->list[i];
453 
454  while (element)
455  {
456  if (g_hash_table_lookup (oids_table, element->plugin->oid))
457  element->plugin->enabled = TRUE;
458 
459  element = element->next;
460  }
461  }
462  g_hash_table_destroy (oids_table);
463  g_free (oids);
464 
465  if (autoload != 0)
466  {
467  for (i = ACT_FIRST; i <= ACT_LAST; i++)
468  {
469  struct list *element = sched->list[i];
470 
471  while (element)
472  {
473  /* deps_table is used to prevent circular dependencies. */
474  GHashTable *deps_table;
475 
476  deps_table = g_hash_table_new_full
477  (g_str_hash, g_str_equal, g_free, NULL);
478  if (element->plugin->enabled)
479  enable_plugin_and_dependencies (sched, element->plugin,
480  deps_table);
481 
482  g_hash_table_destroy (deps_table);
483  element = element->next;
484  }
485  }
486  }
487 }
488 
489 static void
490 plugins_scheduler_fill (plugins_scheduler_t sched)
491 {
492  int i;
493  GSList *list, *element;
494 
495  list = element = nvticache_get_oids ();
496  while (element)
497  {
499  struct list *dup;
500  int category;
501 
502  category = nvticache_get_category (element->data);
503  scheduler_plugin = g_malloc0 (sizeof (struct scheduler_plugin));
505  scheduler_plugin->oid = g_strdup (element->data);
506  scheduler_plugin->enabled = FALSE;
507 
508  assert (category <= ACT_LAST);
509  dup = g_malloc0 ( sizeof (struct list));
510  dup->plugin = scheduler_plugin;
511  dup->prev = NULL;
512  dup->next = sched->list[category];
513  if (sched->list[category] != NULL)
514  sched->list[category]->prev = dup;
515  sched->list[category] = dup;
516 
517  hash_add (sched->hash, scheduler_plugin);
518  element = element->next;
519  }
520  g_slist_free_full (list, g_free);
521 
522  for (i = 0; i < HASH_MAX; i++)
523  {
524  struct hash *l = &sched->hash[i];
525  while (l != NULL)
526  {
527  hash_fill_deps (sched->hash, l);
528  l = l->next;
529  }
530  }
531 
532 }
533 
535 plugins_scheduler_init (const char *plugins_list, int autoload, int only_network)
536 {
538  int i;
539 
540  /* Fill our lists */
541  ret = g_malloc0 (sizeof (*ret));
542  ret->hash = hash_init ();
543  plugins_scheduler_fill (ret);
544 
545  plugins_scheduler_enable (ret, plugins_list, autoload);
546 
547  /* Now, remove the plugins that won't be launched */
548  for (i = ACT_FIRST; i <= ACT_LAST; i++)
549  {
550  struct list *plist = ret->list[i];
551 
552  while (plist != NULL)
553  {
554  if (!plist->plugin->enabled)
555  {
556  struct list *old = plist->next;
557 
558  if (plist->prev != NULL)
559  plist->prev->next = plist->next;
560  else
561  ret->list[i] = plist->next;
562 
563  if (plist->next != NULL)
564  plist->next->prev = plist->prev;
565 
566  g_free (plist);
567  plist = old;
568  continue;
569  }
570  plist = plist->next;
571  }
572  }
573 
574  if (only_network)
575  {
576  for (i = ACT_GATHER_INFO; i <= ACT_LAST; i++)
577  {
578  ret->list[i] = NULL;
579  }
580  }
581  return ret;
582 }
583 
584 int
586 {
587  int ret = 0, i;
588  assert (sched);
589 
590  for (i = ACT_FIRST; i <= ACT_LAST; i++)
591  {
592  struct list *element = sched->list[i];
593 
594  while (element)
595  {
596  if (element->plugin->enabled)
597  ret++;
598  element = element->next;
599  }
600  }
601  return ret;
602 }
603 
604 static struct scheduler_plugin *
605 get_next_plugin (plugins_scheduler_t h, struct scheduler_plugin *plugin,
606  int *still_running)
607 {
608  assert (plugin);
609 
610  switch (plugin->running_state)
611  {
612  case PLUGIN_STATUS_UNRUN:
613  {
614  struct hash **deps_ptr = plugin->parent_hash->dependencies_ptr;
615 
616  if (deps_ptr)
617  {
618  struct scheduler_plugin *p =
619  plugin_next_unrun_dependency (h, deps_ptr, 0);
620 
621  switch (GPOINTER_TO_SIZE (p))
622  {
623  case GPOINTER_TO_SIZE (NULL):
624  scheduler_mark_running_ports (h, plugin);
626  return plugin;
627 
628  break;
629  case GPOINTER_TO_SIZE (PLUG_RUNNING):
630  {
631  /* One of the dependency is still running */
632  *still_running = 1;
633  }
634  break;
635  default:
636  {
637  /* Launch a dependency - don't pay attention to the type */
640  return p;
641  }
642  }
643  }
644  else /* No dependencies */
645  {
646  scheduler_mark_running_ports (h, plugin);
648  return plugin;
649  }
650  }
651  break;
653  *still_running = 1;
654  break;
655  case PLUGIN_STATUS_DONE:
656  scheduler_rm_running_ports (h, plugin);
658  /* fallthrough */
660  return NULL;
661  }
662  return NULL;
663 }
664 
665 static struct scheduler_plugin *
666 get_next_in_range (plugins_scheduler_t h, int start, int end)
667 {
668  int category;
669  struct list *element;
670  int still_running = 0;
671 
672  for (category = start; category <= end; category++)
673  {
674  element = h->list[category];
675  if (category == ACT_SCANNER || category == ACT_KILL_HOST
676  || category == ACT_FLOOD || category == ACT_DENIAL)
678  while (element)
679  {
680  struct scheduler_plugin *plugin = get_next_plugin (h, element->plugin,
681  &still_running);
682  if (plugin)
683  return plugin;
684  element = element->next;
685  }
687  }
688  if (still_running)
689  return PLUG_RUNNING;
690  return NULL;
691 }
692 
693 struct scheduler_plugin *
695 {
696  struct scheduler_plugin *ret;
697 
698  if (h == NULL)
699  return NULL;
700  ret = get_next_in_range (h, ACT_INIT, ACT_INIT);
701  if (ret)
702  return ret;
703  ret = get_next_in_range (h, ACT_SCANNER, ACT_SCANNER);
704  if (ret)
705  return ret;
706  ret = get_next_in_range (h, ACT_SETTINGS, ACT_GATHER_INFO);
707  if (ret)
708  return ret;
709  ret = get_next_in_range (h, ACT_ATTACK, ACT_FLOOD);
710  if (ret)
711  return ret;
712  ret = get_next_in_range (h, ACT_END, ACT_END);
713  if (ret)
714  return ret;
715  return NULL;
716 }
717 
718 void
720 {
721  while (list != NULL)
722  {
723  struct list *next = list->next;
724  g_free (list);
725  list = next;
726  }
727 }
728 
729 void
731 {
732  int i;
733  hash_destroy (sched->hash);
734  for (i = ACT_FIRST; i <= ACT_LAST; i++)
735  list_destroy (sched->list[i]);
736  g_free (sched);
737 }
struct list * list[ACT_LAST+1]
struct scheduler_plugin * plugin_next_unrun_dependency(plugins_scheduler_t sched, struct hash **dependencies_ptr, int calls)
void pluginlaunch_enable_parrallel_checks(void)
Definition: pluginlaunch.c:372
void log_write(const char *str,...)
Write into the logfile / syslog.
Definition: log.c:140
plugins_scheduler_t plugins_scheduler_init(const char *plugins_list, int autoload, int only_network)
struct scheduler_plugin * plugins_scheduler_next(plugins_scheduler_t h)
gchar * name
void scheduler_rm_running_ports(plugins_scheduler_t sched, struct scheduler_plugin *plugin)
struct hash * hash
void plugins_scheduler_free(plugins_scheduler_t sched)
int plugins_scheduler_count_active(plugins_scheduler_t sched)
#define HASH_MAX
void pluginlaunch_wait_for_free_process(void)
Waits and &#39;pushes&#39; processes until the number of running processes has changed.
Definition: pluginlaunch.c:499
struct scheduler_plugin * plugin
void scheduler_mark_running_ports(plugins_scheduler_t sched, struct scheduler_plugin *plugin)
#define PLUGIN_STATUS_DONE
struct plist * next
#define PLUGIN_STATUS_RUNNING
struct hash ** dependencies_ptr
void pluginlaunch_disable_parrallel_checks(void)
Definition: pluginlaunch.c:366
#define PLUG_RUNNING
#define PLUGIN_STATUS_UNRUN
struct list * prev
struct hash * next
void list_destroy(struct list *list)
struct scheduler_plugin * plugin
int occurences
struct list * next
#define PLUGIN_STATUS_DONE_AND_CLEANED
struct plist * plist
struct plist * pl_get(struct plist *list, char *name)
struct hash * parent_hash
struct plist * prev