OpenVAS Scanner  7.0.1~git
pluginscheduler.c
Go to the documentation of this file.
1 /* Portions Copyright (C) 2009-2019 Greenbone Networks GmbH
2  * Portions Copyright (C) 2006 Software in the Public Interest, Inc.
3  * Based on work Copyright (C) 1998 - 2006 Tenable Network Security, Inc.
4  *
5  * SPDX-License-Identifier: GPL-2.0-only
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20 
26 #include "pluginscheduler.h"
27 
28 #include "../misc/nvt_categories.h" /* for ACT_SCANNER */
29 #include "../misc/plugutils.h" /* for plug_get_launch */
30 #include "pluginlaunch.h"
31 #include "pluginload.h"
32 
33 #include <glib.h>
34 #include <gvm/base/prefs.h> /* for prefs_get() */
35 #include <gvm/util/nvticache.h> /* for nvticache_t */
36 #include <malloc.h>
37 #include <string.h> /* for strcmp() */
38 
39 #undef G_LOG_DOMAIN
40 
43 #define G_LOG_DOMAIN "sd main"
44 
50 {
51  GSList *list[ACT_END + 1];
52  int stopped;
53 };
54 
55 /*---------------------------------------------------------------------------*/
56 
57 static int
58 plugin_add (plugins_scheduler_t sched, GHashTable *oids_table,
59  GHashTable *names_table, int autoload, char *oid)
60 {
61  struct scheduler_plugin *plugin;
62  int category;
63  nvti_t *nvti;
64  int ret = 0;
65  if (g_hash_table_lookup (oids_table, oid))
66  return 0;
67 
68  /* Check if the plugin is deprecated */
69  nvti = nvticache_get_nvt (oid);
70  if (nvti == NULL)
71  {
72  g_warning ("The NVT with oid %s was not found in the nvticache.", oid);
73  return 1;
74  }
75 
76  if (nvti_tag (nvti)
77  && (g_str_has_prefix (nvti_tag (nvti), "deprecated=1")
78  || strstr (nvti_tag (nvti), "|deprecated=1")))
79  {
80  if (prefs_get_bool ("log_whole_attack"))
81  {
82  char *name = nvticache_get_filename (oid);
83  g_message ("Plugin %s is deprecated. "
84  "It will neither be loaded nor launched.",
85  name);
86  g_free (name);
87  }
88  nvti_free (nvti);
89  return 0;
90  }
91 
92  category = nvti_category (nvti);
93  if (!(category >= ACT_INIT && category <= ACT_END))
94  {
95  g_warning ("The NVT with oid %s has no category assigned. This is "
96  "considered a fatal error, since the NVTI Cache "
97  "structure stored in Redis is out dated or corrupted.",
98  oid);
99  nvti_free (nvti);
100  return 1;
101  }
102  plugin = g_malloc0 (sizeof (struct scheduler_plugin));
104  plugin->oid = g_strdup (oid);
105  g_hash_table_insert (oids_table, plugin->oid, plugin);
106 
107  sched->list[category] = g_slist_prepend (sched->list[category], plugin);
108 
109  /* Add the plugin's dependencies too. */
110  if (autoload)
111  {
112  char *saveptr, *dep_name = NULL, *deps = nvti_dependencies (nvti);
113 
114  if (deps)
115  dep_name = strtok_r (deps, ", ", &saveptr);
116  while (dep_name)
117  {
118  struct scheduler_plugin *dep_plugin;
119  char *dep_oid;
120 
121  dep_oid = g_hash_table_lookup (names_table, dep_name);
122  if (!dep_oid)
123  {
124  dep_oid = nvticache_get_oid (dep_name);
125  g_hash_table_insert (names_table, g_strdup (dep_name), dep_oid);
126  }
127  if (dep_oid)
128  {
129  ret =
130  plugin_add (sched, oids_table, names_table, autoload, dep_oid);
131  if (ret)
132  return 1;
133  dep_plugin = g_hash_table_lookup (oids_table, dep_oid);
134  /* In case of autoload, no need to wait for plugin_add() to
135  * fill all enabled plugins to start filling dependencies
136  * lists. */
137  if (dep_plugin)
138  plugin->deps = g_slist_prepend (plugin->deps, dep_plugin);
139  else
140  g_warning ("There was a problem loading %s (%s), a "
141  "dependency of %s. This can happen e.g. when "
142  "depending on a deprecated NVT.",
143  dep_name, dep_oid, oid);
144  }
145  else
146  {
147  char *name = nvticache_get_name (oid);
148  g_warning (
149  "There was a problem trying to load %s, a dependency "
150  "of %s. This may be due to a parse error, or it failed "
151  "to find the dependency. Please check the path to the "
152  "file.",
153  dep_name, name);
154  g_free (name);
155  }
156  dep_name = strtok_r (NULL, ", ", &saveptr);
157  }
158  }
159  nvti_free (nvti);
160  return 0;
161 }
162 
163 static void
164 plugins_scheduler_fill_deps (plugins_scheduler_t sched, GHashTable *oids_table)
165 {
166  int category;
167 
168  for (category = ACT_INIT; category <= ACT_END; category++)
169  {
170  GSList *element = sched->list[category];
171 
172  while (element)
173  {
174  char *deps;
175  struct scheduler_plugin *plugin = element->data;
176 
177  assert (plugin->deps == NULL);
178  deps = nvticache_get_dependencies (plugin->oid);
179  if (deps)
180  {
181  int i;
182  char **array = g_strsplit (deps, ", ", 0);
183 
184  for (i = 0; array[i]; i++)
185  {
186  struct scheduler_plugin *dep_plugin;
187  char *dep_oid = nvticache_get_oid (array[i]);
188  dep_plugin = g_hash_table_lookup (oids_table, dep_oid);
189  if (dep_plugin)
190  plugin->deps = g_slist_prepend (plugin->deps, dep_plugin);
191  g_free (dep_oid);
192  }
193  g_strfreev (array);
194  g_free (deps);
195  }
196  element = element->next;
197  }
198  }
199 }
200 
201 /*
202  * Enable plugins in scheduler, from a list.
203  *
204  * param[in] sched Plugins scheduler.
205  * param[in] oid_list List of plugins to enable.
206  * param[in] autoload Whether to autoload dependencies.
207  *
208  * return error_counter Number of errors found during the schecuduling.
209  */
210 static int
211 plugins_scheduler_enable (plugins_scheduler_t sched, const char *oid_list,
212  int autoload)
213 {
214  char *oids, *oid, *saveptr;
215  GHashTable *oids_table, *names_table;
216  int error_counter = 0;
217 
218  oids_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
219  names_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
220 
221  /* Store list of plugins in hashtable. */
222  oids = g_strdup (oid_list);
223  oid = strtok_r (oids, ";", &saveptr);
224  while (oid)
225  {
226  error_counter +=
227  plugin_add (sched, oids_table, names_table, autoload, oid);
228  oid = strtok_r (NULL, ";", &saveptr);
229  }
230 
231  /* When autoload is disabled, each plugin's deps list is still empty. */
232  if (!autoload)
233  plugins_scheduler_fill_deps (sched, oids_table);
234 
235  if (error_counter > 0)
236  g_warning ("%s: %d errors were found during the plugin scheduling.",
237  __func__, error_counter);
238 
239  g_hash_table_destroy (oids_table);
240  g_hash_table_destroy (names_table);
241  g_free (oids);
242 
243  return error_counter;
244 }
245 
246 int
247 find_plugin_in_deps (GHashTable *checked, struct scheduler_plugin **array,
248  int pos)
249 {
250  GSList *element = array[pos]->deps;
251  int i;
252 
253  for (i = 0; i < pos; i++)
254  if (array[i] == array[pos])
255  return pos;
256 
257  if (g_hash_table_lookup (checked, array[pos]))
258  return -1;
259  while (element)
260  {
261  int ret;
262 
263  array[pos + 1] = element->data;
264  ret = find_plugin_in_deps (checked, array, pos + 1);
265  if (ret != -1)
266  return ret;
267  element = element->next;
268  }
269  g_hash_table_insert (checked, array[pos], array[pos]);
270  return -1;
271 }
272 
273 int
275 {
276  int i, j;
277  GHashTable *checked;
278 
279  checked = g_hash_table_new_full (g_str_hash, g_direct_equal, NULL, NULL);
280  for (i = ACT_INIT; i <= ACT_END; i++)
281  {
282  GSList *element = sched->list[i];
283 
284  while (element)
285  {
286  struct scheduler_plugin *array[1024];
287  int pos;
288 
289  array[0] = element->data;
290  pos = find_plugin_in_deps (checked, array, 0);
291  if (pos >= 0)
292  {
293  g_warning ("Dependency cycle:");
294  for (j = 0; j <= pos; j++)
295  {
296  char *name = nvticache_get_filename (array[j]->oid);
297 
298  g_message (" %s (%s)", name, array[j]->oid);
299  g_free (name);
300  }
301 
302  g_hash_table_destroy (checked);
303  return 1;
304  }
305  element = element->next;
306  }
307  }
308  g_hash_table_destroy (checked);
309  return 0;
310 }
311 
313 plugins_scheduler_init (const char *plugins_list, int autoload,
314  int only_network, int *error)
315 {
317  int i;
318 
319  /* Fill our lists */
320  ret = g_malloc0 (sizeof (*ret));
321  *error = plugins_scheduler_enable (ret, plugins_list, autoload);
322 
323  if (only_network)
324  {
325  for (i = ACT_GATHER_INFO; i <= ACT_END; i++)
326  {
327  ret->list[i] = NULL;
328  }
329  }
330 
331  if (check_dependency_cycles (ret))
332  {
334  return NULL;
335  }
336  malloc_trim (0);
337  return ret;
338 }
339 
340 int
342 {
343  int ret = 0, i;
344  assert (sched);
345 
346  for (i = ACT_INIT; i <= ACT_END; i++)
347  ret += g_slist_length (sched->list[i]);
348  return ret;
349 }
350 
351 static struct scheduler_plugin *
352 plugins_next_unrun (GSList *plugins)
353 {
354  int still_running = 0;
355 
356  while (plugins)
357  {
358  struct scheduler_plugin *plugin = plugins->data;
359  switch (plugin->running_state)
360  {
361  case PLUGIN_STATUS_UNRUN:
362  {
363  struct scheduler_plugin *nplugin;
364  GSList *deps_list = plugin->deps;
365 
366  nplugin = plugins_next_unrun (deps_list);
367 
368  if (nplugin == PLUG_RUNNING)
369  still_running = 1;
370  else if (nplugin)
371  {
373  return nplugin;
374  }
375  else
376  {
378  return plugin;
379  }
380  break;
381  }
383  still_running = 1;
384  break;
385  case PLUGIN_STATUS_DONE:
386  break;
387  }
388  plugins = plugins->next;
389  }
390  return still_running ? PLUG_RUNNING : NULL;
391 }
392 
393 static struct scheduler_plugin *
394 get_next_in_range (plugins_scheduler_t h, int start, int end)
395 {
396  int category;
397  GSList *element;
398  int still_running = 0;
399 
400  for (category = start; category <= end; category++)
401  {
402  struct scheduler_plugin *plugin;
403  element = h->list[category];
404  if (category == ACT_SCANNER || category == ACT_KILL_HOST
405  || category == ACT_FLOOD || category == ACT_DENIAL)
407 
408  plugin = plugins_next_unrun (element);
409  if (plugin == PLUG_RUNNING)
410  still_running = 1;
411  else if (plugin)
412  return plugin;
414  }
415  return still_running ? PLUG_RUNNING : NULL;
416 }
417 
418 static void
419 scheduler_phase_cleanup (plugins_scheduler_t sched, int start, int end)
420 {
421  int category;
422 
423  assert (sched);
424  for (category = start; category <= end; category++)
425  {
426  GSList *element = sched->list[category];
427  while (element)
428  {
429  struct scheduler_plugin *plugin = element->data;
430 
431  g_free (plugin->oid);
432  g_slist_free (plugin->deps);
433  plugin->oid = NULL;
434  plugin->deps = NULL;
435  element = element->next;
436  }
437  }
438  malloc_trim (0);
439 }
440 
441 struct scheduler_plugin *
443 {
444  struct scheduler_plugin *ret;
445  static int scheduler_phase = 0;
446 
447  if (h == NULL)
448  return NULL;
449 
450  if (scheduler_phase == 0)
451  {
452  ret = get_next_in_range (h, ACT_INIT, ACT_INIT);
453  if (ret)
454  return ret;
455  scheduler_phase = 1;
457  }
458  if (scheduler_phase <= 1)
459  {
461  if (ret)
462  return ret;
463  scheduler_phase = 2;
465  }
466  if (scheduler_phase <= 2)
467  {
469  if (ret)
470  return ret;
471  scheduler_phase = 3;
473  }
474  if (scheduler_phase <= 3)
475  {
477  if (ret)
478  return ret;
479  scheduler_phase = 4;
481  }
482  if (scheduler_phase <= 4)
483  {
484  ret = get_next_in_range (h, ACT_END, ACT_END);
485  if (ret)
486  return ret;
487  scheduler_phase = 5;
489  }
490  return NULL;
491 }
492 
493 /*
494  * @brief Set all non-ACT_END plugins to stopped.
495  *
496  * @param sched Plugins scheduler.
497  */
498 void
500 {
501  int category;
502 
503  if (sched->stopped)
504  return;
505  for (category = ACT_INIT; category < ACT_END; category++)
506  {
507  GSList *element = sched->list[category];
508 
509  while (element)
510  {
511  struct scheduler_plugin *plugin = element->data;
512 
514  element = element->next;
515  }
516  }
517  sched->stopped = 1;
518 }
519 
520 void
522 {
523  struct scheduler_plugin *plugin;
524  if (!data)
525  return;
526 
527  plugin = data;
528  g_free (plugin->oid);
529  g_slist_free (plugin->deps);
530  g_free (plugin);
531 }
532 
533 void
535 {
536  int i;
537 
538  for (i = ACT_INIT; i <= ACT_END; i++)
539  g_slist_free_full (sched->list[i], scheduler_plugin_free);
540  g_free (sched);
541 }
plugins_scheduler_t plugins_scheduler_init(const char *plugins_list, int autoload, int only_network, int *error)
struct scheduler_plugin * plugins_scheduler_next(plugins_scheduler_t h)
static int plugin_add(plugins_scheduler_t sched, GHashTable *oids_table, GHashTable *names_table, int autoload, char *oid)
const char * oid
void plugins_scheduler_stop(plugins_scheduler_t sched)
void plugins_scheduler_free(plugins_scheduler_t sched)
int plugins_scheduler_count_active(plugins_scheduler_t sched)
void pluginlaunch_disable_parallel_checks(void)
Definition: pluginlaunch.c:290
static struct scheduler_plugin * plugins_next_unrun(GSList *plugins)
static void scheduler_phase_cleanup(plugins_scheduler_t sched, int start, int end)
void pluginlaunch_enable_parallel_checks(void)
Definition: pluginlaunch.c:296
const char * name
Definition: nasl_init.c:377
pluginlaunch.c header.
int find_plugin_in_deps(GHashTable *checked, struct scheduler_plugin **array, int pos)
static struct scheduler_plugin * get_next_in_range(plugins_scheduler_t h, int start, int end)
static void plugins_scheduler_fill_deps(plugins_scheduler_t sched, GHashTable *oids_table)
enum plugin_status running_state
static int plugins_scheduler_enable(plugins_scheduler_t sched, const char *oid_list, int autoload)
GSList * list[ACT_END+1]
#define PLUG_RUNNING
int check_dependency_cycles(plugins_scheduler_t sched)
pluginload.c header.
void scheduler_plugin_free(void *data)
header for pluginscheduler.c