OpenVAS Scanner  7.0.0~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_tag (nvti)
71  && (g_str_has_prefix (nvti_tag (nvti), "deprecated=1")
72  || strstr (nvti_tag (nvti), "|deprecated=1")))
73  {
74  if (prefs_get_bool ("log_whole_attack"))
75  {
76  char *name = nvticache_get_filename (oid);
77  g_message ("Plugin %s is deprecated. "
78  "It will neither be loaded nor launched.",
79  name);
80  g_free (name);
81  }
82  nvti_free (nvti);
83  return 0;
84  }
85 
86  category = nvti_category (nvti);
87  if (!(category >= ACT_INIT && category <= ACT_END))
88  {
89  g_message ("The NVT with oid %s has no category assigned. This is "
90  "considered a fatal error, since the NVTI Cache "
91  "structure stored in Redis is out dated or corrupted.",
92  oid);
93  nvti_free (nvti);
94  return 1;
95  }
96  plugin = g_malloc0 (sizeof (struct scheduler_plugin));
98  plugin->oid = g_strdup (oid);
99  g_hash_table_insert (oids_table, plugin->oid, plugin);
100 
101  sched->list[category] = g_slist_prepend (sched->list[category], plugin);
102 
103  /* Add the plugin's dependencies too. */
104  if (autoload)
105  {
106  char *saveptr, *dep_name = NULL, *deps = nvti_dependencies (nvti);
107 
108  if (deps)
109  dep_name = strtok_r (deps, ", ", &saveptr);
110  while (dep_name)
111  {
112  struct scheduler_plugin *dep_plugin;
113  char *dep_oid;
114 
115  dep_oid = g_hash_table_lookup (names_table, dep_name);
116  if (!dep_oid)
117  {
118  dep_oid = nvticache_get_oid (dep_name);
119  g_hash_table_insert (names_table, g_strdup (dep_name), dep_oid);
120  }
121  if (dep_oid)
122  {
123  ret =
124  plugin_add (sched, oids_table, names_table, autoload, dep_oid);
125  if (ret)
126  return 1;
127  dep_plugin = g_hash_table_lookup (oids_table, dep_oid);
128  /* In case of autoload, no need to wait for plugin_add() to
129  * fill all enabled plugins to start filling dependencies
130  * lists. */
131  if (dep_plugin)
132  plugin->deps = g_slist_prepend (plugin->deps, dep_plugin);
133  else
134  g_warning ("There was a problem loading %s (%s), a "
135  "dependency of %s. This can happen e.g. when "
136  "depending on a deprecated NVT.",
137  dep_name, dep_oid, oid);
138  }
139  else
140  {
141  char *name = nvticache_get_name (oid);
142  g_warning (
143  "There was a problem trying to load %s, a dependency "
144  "of %s. This may be due to a parse error, or it failed "
145  "to find the dependency. Please check the path to the "
146  "file.",
147  dep_name, name);
148  g_free (name);
149  }
150  dep_name = strtok_r (NULL, ", ", &saveptr);
151  }
152  }
153  nvti_free (nvti);
154  return 0;
155 }
156 
157 static void
158 plugins_scheduler_fill_deps (plugins_scheduler_t sched, GHashTable *oids_table)
159 {
160  int category;
161 
162  for (category = ACT_INIT; category <= ACT_END; category++)
163  {
164  GSList *element = sched->list[category];
165 
166  while (element)
167  {
168  char *deps;
169  struct scheduler_plugin *plugin = element->data;
170 
171  assert (plugin->deps == NULL);
172  deps = nvticache_get_dependencies (plugin->oid);
173  if (deps)
174  {
175  int i;
176  char **array = g_strsplit (deps, ", ", 0);
177 
178  for (i = 0; array[i]; i++)
179  {
180  struct scheduler_plugin *dep_plugin;
181  char *dep_oid = nvticache_get_oid (array[i]);
182  dep_plugin = g_hash_table_lookup (oids_table, dep_oid);
183  if (dep_plugin)
184  plugin->deps = g_slist_prepend (plugin->deps, dep_plugin);
185  g_free (dep_oid);
186  }
187  g_strfreev (array);
188  g_free (deps);
189  }
190  element = element->next;
191  }
192  }
193 }
194 
195 /*
196  * Enable plugins in scheduler, from a list.
197  *
198  * param[in] sched Plugins scheduler.
199  * param[in] oid_list List of plugins to enable.
200  * param[in] autoload Whether to autoload dependencies.
201  */
202 static int
203 plugins_scheduler_enable (plugins_scheduler_t sched, const char *oid_list,
204  int autoload)
205 {
206  char *oids, *oid, *saveptr;
207  GHashTable *oids_table, *names_table;
208  int ret = 0;
209  static int error_counter = 0;
210 
211  oids_table = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
212  names_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
213 
214  /* Store list of plugins in hashtable. */
215  oids = g_strdup (oid_list);
216  oid = strtok_r (oids, ";", &saveptr);
217  while (oid)
218  {
219  ret = plugin_add (sched, oids_table, names_table, autoload, oid);
220  if (ret)
221  {
222  error_counter++;
223  if (error_counter >= 5)
224  {
225  g_message ("Stopped plugin scheduler: High number of errors.");
226  goto error;
227  }
228  }
229  oid = strtok_r (NULL, ";", &saveptr);
230  }
231 
232  /* When autoload is disabled, each plugin's deps list is still empty. */
233  if (!autoload)
234  plugins_scheduler_fill_deps (sched, oids_table);
235 
236 error:
237  g_hash_table_destroy (oids_table);
238  g_hash_table_destroy (names_table);
239  g_free (oids);
240  return ret;
241 }
242 
243 int
244 find_plugin_in_deps (GHashTable *checked, struct scheduler_plugin **array,
245  int pos)
246 {
247  GSList *element = array[pos]->deps;
248  int i;
249 
250  for (i = 0; i < pos; i++)
251  if (array[i] == array[pos])
252  return pos;
253 
254  if (g_hash_table_lookup (checked, array[pos]))
255  return -1;
256  while (element)
257  {
258  int ret;
259 
260  array[pos + 1] = element->data;
261  ret = find_plugin_in_deps (checked, array, pos + 1);
262  if (ret != -1)
263  return ret;
264  element = element->next;
265  }
266  g_hash_table_insert (checked, array[pos], array[pos]);
267  return -1;
268 }
269 
270 int
272 {
273  int i, j;
274  GHashTable *checked;
275 
276  checked = g_hash_table_new_full (g_str_hash, g_direct_equal, NULL, NULL);
277  for (i = ACT_INIT; i <= ACT_END; i++)
278  {
279  GSList *element = sched->list[i];
280 
281  while (element)
282  {
283  struct scheduler_plugin *array[1024];
284  int pos;
285 
286  array[0] = element->data;
287  pos = find_plugin_in_deps (checked, array, 0);
288  if (pos >= 0)
289  {
290  g_warning ("Dependency cycle:");
291  for (j = 0; j <= pos; j++)
292  {
293  char *name = nvticache_get_filename (array[j]->oid);
294 
295  g_message (" %s (%s)", name, array[j]->oid);
296  g_free (name);
297  }
298 
299  g_hash_table_destroy (checked);
300  return 1;
301  }
302  element = element->next;
303  }
304  }
305  g_hash_table_destroy (checked);
306  return 0;
307 }
308 
310 plugins_scheduler_init (const char *plugins_list, int autoload,
311  int only_network)
312 {
314  int i, err = 0;
315 
316  /* Fill our lists */
317  ret = g_malloc0 (sizeof (*ret));
318  err = plugins_scheduler_enable (ret, plugins_list, autoload);
319  if (err)
320  {
322  return NULL;
323  }
324 
325  if (only_network)
326  {
327  for (i = ACT_GATHER_INFO; i <= ACT_END; i++)
328  {
329  ret->list[i] = NULL;
330  }
331  }
332 
333  if (check_dependency_cycles (ret))
334  {
336  return NULL;
337  }
338  malloc_trim (0);
339  return ret;
340 }
341 
342 int
344 {
345  int ret = 0, i;
346  assert (sched);
347 
348  for (i = ACT_INIT; i <= ACT_END; i++)
349  ret += g_slist_length (sched->list[i]);
350  return ret;
351 }
352 
353 static struct scheduler_plugin *
354 plugins_next_unrun (GSList *plugins)
355 {
356  int still_running = 0;
357 
358  while (plugins)
359  {
360  struct scheduler_plugin *plugin = plugins->data;
361  switch (plugin->running_state)
362  {
363  case PLUGIN_STATUS_UNRUN:
364  {
365  struct scheduler_plugin *nplugin;
366  GSList *deps_list = plugin->deps;
367 
368  nplugin = plugins_next_unrun (deps_list);
369 
370  if (nplugin == PLUG_RUNNING)
371  still_running = 1;
372  else if (nplugin)
373  {
375  return nplugin;
376  }
377  else
378  {
380  return plugin;
381  }
382  break;
383  }
385  still_running = 1;
386  break;
387  case PLUGIN_STATUS_DONE:
388  break;
389  }
390  plugins = plugins->next;
391  }
392  return still_running ? PLUG_RUNNING : NULL;
393 }
394 
395 static struct scheduler_plugin *
396 get_next_in_range (plugins_scheduler_t h, int start, int end)
397 {
398  int category;
399  GSList *element;
400  int still_running = 0;
401 
402  for (category = start; category <= end; category++)
403  {
404  struct scheduler_plugin *plugin;
405  element = h->list[category];
406  if (category == ACT_SCANNER || category == ACT_KILL_HOST
407  || category == ACT_FLOOD || category == ACT_DENIAL)
409 
410  plugin = plugins_next_unrun (element);
411  if (plugin == PLUG_RUNNING)
412  still_running = 1;
413  else if (plugin)
414  return plugin;
416  }
417  return still_running ? PLUG_RUNNING : NULL;
418 }
419 
420 static void
421 scheduler_phase_cleanup (plugins_scheduler_t sched, int start, int end)
422 {
423  int category;
424 
425  assert (sched);
426  for (category = start; category <= end; category++)
427  {
428  GSList *element = sched->list[category];
429  while (element)
430  {
431  struct scheduler_plugin *plugin = element->data;
432 
433  g_free (plugin->oid);
434  g_slist_free (plugin->deps);
435  plugin->oid = NULL;
436  plugin->deps = NULL;
437  element = element->next;
438  }
439  }
440  malloc_trim (0);
441 }
442 
443 struct scheduler_plugin *
445 {
446  struct scheduler_plugin *ret;
447  static int scheduler_phase = 0;
448 
449  if (h == NULL)
450  return NULL;
451 
452  if (scheduler_phase == 0)
453  {
454  ret = get_next_in_range (h, ACT_INIT, ACT_INIT);
455  if (ret)
456  return ret;
457  scheduler_phase = 1;
459  }
460  if (scheduler_phase <= 1)
461  {
463  if (ret)
464  return ret;
465  scheduler_phase = 2;
467  }
468  if (scheduler_phase <= 2)
469  {
471  if (ret)
472  return ret;
473  scheduler_phase = 3;
475  }
476  if (scheduler_phase <= 3)
477  {
479  if (ret)
480  return ret;
481  scheduler_phase = 4;
483  }
484  if (scheduler_phase <= 4)
485  {
486  ret = get_next_in_range (h, ACT_END, ACT_END);
487  if (ret)
488  return ret;
489  scheduler_phase = 5;
491  }
492  return NULL;
493 }
494 
495 /*
496  * @brief Set all non-ACT_END plugins to stopped.
497  *
498  * @param sched Plugins scheduler.
499  */
500 void
502 {
503  int category;
504 
505  if (sched->stopped)
506  return;
507  for (category = ACT_INIT; category < ACT_END; category++)
508  {
509  GSList *element = sched->list[category];
510 
511  while (element)
512  {
513  struct scheduler_plugin *plugin = element->data;
514 
516  element = element->next;
517  }
518  }
519  sched->stopped = 1;
520 }
521 
522 void
524 {
525  struct scheduler_plugin *plugin;
526  if (!data)
527  return;
528 
529  plugin = data;
530  g_free (plugin->oid);
531  g_slist_free (plugin->deps);
532  g_free (plugin);
533 }
534 
535 void
537 {
538  int i;
539 
540  for (i = ACT_INIT; i <= ACT_END; i++)
541  g_slist_free_full (sched->list[i], scheduler_plugin_free);
542  g_free (sched);
543 }
ACT_FLOOD
@ ACT_FLOOD
Definition: nvt_categories.h:47
plugins_scheduler_enable
static int plugins_scheduler_enable(plugins_scheduler_t sched, const char *oid_list, int autoload)
Definition: pluginscheduler.c:203
plugins_scheduler_stop
void plugins_scheduler_stop(plugins_scheduler_t sched)
Definition: pluginscheduler.c:501
scheduler_phase_cleanup
static void scheduler_phase_cleanup(plugins_scheduler_t sched, int start, int end)
Definition: pluginscheduler.c:421
plugins_scheduler
Definition: pluginscheduler.c:49
scheduler_plugin
Definition: pluginscheduler.h:40
pluginlaunch_disable_parallel_checks
void pluginlaunch_disable_parallel_checks(void)
Definition: pluginlaunch.c:290
find_plugin_in_deps
int find_plugin_in_deps(GHashTable *checked, struct scheduler_plugin **array, int pos)
Definition: pluginscheduler.c:244
PLUGIN_STATUS_RUNNING
@ PLUGIN_STATUS_RUNNING
Definition: pluginscheduler.h:36
ACT_ATTACK
@ ACT_ATTACK
Definition: nvt_categories.h:42
plugins_scheduler_free
void plugins_scheduler_free(plugins_scheduler_t sched)
Definition: pluginscheduler.c:536
get_next_in_range
static struct scheduler_plugin * get_next_in_range(plugins_scheduler_t h, int start, int end)
Definition: pluginscheduler.c:396
PLUGIN_STATUS_DONE
@ PLUGIN_STATUS_DONE
Definition: pluginscheduler.h:37
plugins_scheduler_init
plugins_scheduler_t plugins_scheduler_init(const char *plugins_list, int autoload, int only_network)
Definition: pluginscheduler.c:310
ACT_END
@ ACT_END
Definition: nvt_categories.h:48
name
const char * name
Definition: nasl_init.c:377
check_dependency_cycles
int check_dependency_cycles(plugins_scheduler_t sched)
Definition: pluginscheduler.c:271
plugins_scheduler_fill_deps
static void plugins_scheduler_fill_deps(plugins_scheduler_t sched, GHashTable *oids_table)
Definition: pluginscheduler.c:158
plugins_scheduler_count_active
int plugins_scheduler_count_active(plugins_scheduler_t sched)
Definition: pluginscheduler.c:343
ACT_SETTINGS
@ ACT_SETTINGS
Definition: nvt_categories.h:40
ACT_DENIAL
@ ACT_DENIAL
Definition: nvt_categories.h:45
pluginload.h
pluginload.c header.
oid
const char * oid
Definition: nasl_builtin_find_service.c:57
scheduler_plugin::running_state
enum plugin_status running_state
Definition: pluginscheduler.h:44
scheduler_plugin_free
void scheduler_plugin_free(void *data)
Definition: pluginscheduler.c:523
plugins_scheduler::list
GSList * list[ACT_END+1]
Definition: pluginscheduler.c:51
plugin_add
static int plugin_add(plugins_scheduler_t sched, GHashTable *oids_table, GHashTable *names_table, int autoload, char *oid)
Definition: pluginscheduler.c:58
plugins_scheduler::stopped
int stopped
Definition: pluginscheduler.c:52
PLUG_RUNNING
#define PLUG_RUNNING
Definition: pluginscheduler.h:49
scheduler_plugin::deps
GSList * deps
Definition: pluginscheduler.h:43
scheduler_plugin::oid
char * oid
Definition: pluginscheduler.h:42
plugins_next_unrun
static struct scheduler_plugin * plugins_next_unrun(GSList *plugins)
Definition: pluginscheduler.c:354
PLUGIN_STATUS_UNRUN
@ PLUGIN_STATUS_UNRUN
Definition: pluginscheduler.h:35
ACT_SCANNER
@ ACT_SCANNER
Definition: nvt_categories.h:39
pluginscheduler.h
header for pluginscheduler.c
pluginlaunch.h
pluginlaunch.c header.
ACT_GATHER_INFO
@ ACT_GATHER_INFO
Definition: nvt_categories.h:41
ACT_KILL_HOST
@ ACT_KILL_HOST
Definition: nvt_categories.h:46
ACT_INIT
@ ACT_INIT
Definition: nvt_categories.h:38
pluginlaunch_enable_parallel_checks
void pluginlaunch_enable_parallel_checks(void)
Definition: pluginlaunch.c:296
plugins_scheduler_next
struct scheduler_plugin * plugins_scheduler_next(plugins_scheduler_t h)
Definition: pluginscheduler.c:444
list
Definition: nasl_builtin_synscan.c:259