1 /* Copyright (C) 2019-2021 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: AGPL-3.0-or-later
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Affero General Public License as
7  * published by the Free Software Foundation, either version 3 of the
8  * License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Affero General Public License for more details.
14  *
15  * You should have received a copy of the GNU Affero General Public License
16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 
19 /**
20  * @file manage_sql_configs.c
21  * @brief GVM management layer: Config SQL
22  *
23  * The Config SQL for the GVM management layer.
24  */
25 
26 #include "manage_configs.h"
27 #include "manage_acl.h"
28 #include "manage_sql.h"
29 #include "manage_sql_configs.h"
30 #include "manage_sql_nvts.h"
31 #include "sql.h"
32 
33 #include <assert.h>
34 #include <errno.h>
35 #include <glib/gstdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include <gvm/util/uuidutils.h>
40 
41 #undef G_LOG_DOMAIN
42 /**
43  * @brief GLib log domain.
44  */
45 #define G_LOG_DOMAIN "md manage"
46 
47 
48 /* Static headers for internal non-SQL functions. */
49 
50 int
51 sync_configs_with_feed (gboolean);
52 
53 
54 /* Static headers. */
55 
56 static int
57 switch_representation (config_t, int);
58 
59 static void
60 update_config_caches (config_t);
61 
62 
63 /* Helpers. */
64 
65 /**
66  * @brief Test whether a string equal to a given string exists in an array.
67  *
68  * @param[in]  array   Array of gchar* pointers.
69  * @param[in]  string  String.
70  *
71  * @return 1 if a string equal to \arg string exists in \arg array, else 0.
72  */
73 static int
member(GPtrArray * array,const char * string)74 member (GPtrArray *array, const char *string)
75 {
76   const gchar *item;
77   int index = 0;
78   while ((item = (gchar*) g_ptr_array_index (array, index++)))
79     if (strcmp (item, string) == 0) return 1;
80   return 0;
81 }
82 
83 
84 /* NVT selectors.  This is part of Configs.
85  *
86  * An NVT selector is a named selection of NVT's from the cache of all
87  * NVT's.
88  *
89  * An NVT selector is made up of zero or more selectors.  The selectors
90  * combine in id order to make a selection.  Depending on the choice
91  * of selectors the selection can be static or growing.  A growing
92  * selection can grow when new NVT's enter the NVT cache, either because it
93  * selects new families or because it selects new NVT's within existing
94  * families.
95  *
96  * There are three types of selectors that an NVT selector can contain.
97  *
98  *   1) The "all selector", which selects all families and all NVT's in
99  *      those families.  The only way to construct the NVT selector so
100  *      that it grows to includes new families, is to add this selector.
101  *
102  *   2) A "family" selector, which designates an entire family.
103  *
104  *   3) An "NVT" selector, which designates a single NVT.
105  *
106  *      The naming overlaps here.  It's a selector of type NVT, which is
107  *      part of an "NVT selector" (a named collection of selectors).
108  *
109  * The family and NVT type selectors can either include or exclude the
110  * designated NVT's.
111  *
112  * While the all selector provides a way to select every single NVT, the
113  * empty NVT selector corresponds to an empty NVT set.
114  *
115  * The selectors provide a mechanism to select a wide range of NVT
116  * combinations.  The mechanism allows for complex selections involving
117  * redundant selectors.  The Manager, however, only implements a simple
118  * subset of the possible combinations of selectors.  This simple subset
119  * is split into two cases.
120  *
121  *   1) Constraining the universe.
122  *
123  *      The all selector and an optional exclude for each family,
124  *      optional NVT includes in the excluded families, and optional NVT
125  *      excludes in all other families.
126  *
127  *      This allows a growing collection of families, while any family
128  *      can still have a static NVT selection.
129  *
130  *   2) Generating from empty.
131  *
132  *      An empty set of selectors with an optional include for each family,
133  *      optional NVT excludes in the included families, and optional NVT
134  *      includes in all other families.
135  *
136  *      This allows a static collection of families, while any family
137  *      can still grow when new NVT's enter the family.
138  *
139  * Either case allows one or more NVT's to be excluded from the family, both
140  * when the family is growing and when the family is static.
141  */
142 
143 /* These could handle strange cases, like when a family is
144  * included then excluded, or all is included then later excluded.
145  * However, GMP prevents those cases from occurring. */
146 
147 /**
148  * @brief Get the number of families selected by an NVT selector.
149  *
150  * A growing family which has all current NVT's excluded is still
151  * considered as selected by the NVT selector.
152  *
153  * @param[in]  quoted_selector   SQL-quoted selector name.
154  * @param[in]  families_growing  1 if families are growing, else 0.
155  *
156  * @return The number of families selected by an NVT selector.
157  */
158 int
nvt_selector_family_count(const char * quoted_selector,int families_growing)159 nvt_selector_family_count (const char* quoted_selector, int families_growing)
160 {
161   if (families_growing)
162     /* Assume the only family selectors are excludes. */
163     return family_count ()
164            - sql_int ("SELECT COUNT(distinct family_or_nvt) FROM nvt_selectors"
165                       " WHERE name = '%s'"
166                       " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
167                       " AND exclude = 0"
168                       " LIMIT 1;",
169                       quoted_selector);
170 
171   /* Assume that the only family selectors are includes, and that if a
172    * selection has any NVT includes then it only has NVT includes. */
173   return sql_int ("SELECT COUNT (DISTINCT family)"
174                   " FROM (SELECT DISTINCT family FROM nvt_selectors"
175                   "       WHERE name = '%s'"
176                   "       AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
177                   "       AND exclude = 0"
178                   "       UNION SELECT family FROM nvt_selectors"
179                   "             WHERE name = '%s'"
180                   "             AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
181                   "             AND exclude = 0"
182                   "             AND family IS NOT NULL) AS subquery;",
183                   quoted_selector,
184                   quoted_selector);
185 }
186 
187 /**
188  * @brief Get the family growth status of an NVT selector.
189  *
190  * @param[in]  selector  NVT selector.
191  *
192  * @return 1 growing, 0 static.
193  */
194 static int
nvt_selector_families_growing(const char * selector)195 nvt_selector_families_growing (const char* selector)
196 {
197   gchar *quoted_selector;
198   char *string;
199 
200   /* The number of families can only grow if there is selector that includes
201    * all. */
202 
203   quoted_selector = sql_quote (selector);
204   string = sql_string ("SELECT name FROM nvt_selectors"
205                        " WHERE name = '%s'"
206                        " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_ALL)
207                        " AND exclude = 0"
208                        " LIMIT 1;",
209                        quoted_selector);
210   g_free (quoted_selector);
211   if (string == NULL) return 0;
212   free (string);
213   return 1;
214 }
215 
216 /**
217  * @brief Get the NVT growth status of an NVT selector.
218  *
219  * @param[in]  quoted_selector   SQL-quoted selector name.
220  * @param[in]  families_growing  1 if families are growing, else 0.
221  *
222  * @return 1 growing, 0 static.
223  */
224 static int
nvt_selector_nvts_growing_2(const char * quoted_selector,int families_growing)225 nvt_selector_nvts_growing_2 (const char* quoted_selector, int families_growing)
226 {
227   if (families_growing)
228     /* Assume the only family selectors are excludes. */
229     return (family_count ()
230             - sql_int ("SELECT COUNT(distinct family_or_nvt) FROM nvt_selectors"
231                        " WHERE name = '%s'"
232                        " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
233                        " AND exclude = 0"
234                        " LIMIT 1;",
235                        quoted_selector))
236            > 0;
237 
238   /* Assume the only family selectors are includes. */
239   return sql_int ("SELECT COUNT(*) FROM nvt_selectors"
240                   " WHERE name = '%s'"
241                   " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
242                   " AND exclude = 0"
243                   " LIMIT 1;",
244                   quoted_selector)
245          > 0;
246 }
247 
248 /** @todo Move these config functions to the config section. */
249 
250 /**
251  * @brief Get the NVT growth status of a config.
252  *
253  * @param[in]  config  Config.
254  *
255  * @return 1 growing, 0 static.
256  */
257 int
config_nvts_growing(config_t config)258 config_nvts_growing (config_t config)
259 {
260   return sql_int ("SELECT nvts_growing FROM configs"
261                   " WHERE id = %llu;",
262                   config);
263 }
264 
265 /**
266  * @brief Get the family growth status of a config.
267  *
268  * @param[in]  config  Config.
269  *
270  * @return 1 growing, 0 static.
271  */
272 int
config_families_growing(config_t config)273 config_families_growing (config_t config)
274 {
275   return sql_int ("SELECT families_growing FROM configs"
276                   " WHERE id = %llu;",
277                   config);
278 }
279 
280 /**
281  * @brief Initialise an NVT selector iterator.
282  *
283  * @param[in]  iterator  Iterator.
284  * @param[in]  selector  Name of single selector to iterate over, NULL for all.
285  * @param[in]  config    Config to limit iteration to, 0 for all.
286  * @param[in]  type      Type of selector.  All if config is given.
287  */
288 void
init_nvt_selector_iterator(iterator_t * iterator,const char * selector,config_t config,int type)289 init_nvt_selector_iterator (iterator_t* iterator, const char* selector,
290                             config_t config, int type)
291 {
292   gchar *sql;
293 
294   assert (selector ? config == 0 : (config ? selector == NULL : 1));
295   assert (config ? type == NVT_SELECTOR_TYPE_ANY : (type >= 0 && type <= 2));
296 
297   if (selector)
298     {
299       gchar *quoted_selector = sql_quote (selector);
300       sql = g_strdup_printf ("SELECT exclude, family_or_nvt, name, type"
301                              " FROM nvt_selectors"
302                              " WHERE name = '%s' AND type = %i;",
303                              quoted_selector,
304                              type);
305       g_free (quoted_selector);
306     }
307   else if (config)
308     sql = g_strdup_printf ("SELECT exclude, family_or_nvt, name, type"
309                            " FROM nvt_selectors"
310                            " WHERE name ="
311                            " (SELECT nvt_selector FROM configs"
312                            "  WHERE configs.id = %llu);",
313                            config);
314   else
315     sql = g_strdup_printf ("SELECT exclude, family_or_nvt, name, type"
316                            " FROM nvt_selectors"
317                            " WHERE type = %i;",
318                            type);
319   init_iterator (iterator, "%s", sql);
320   g_free (sql);
321 }
322 
323 /**
324  * @brief Get whether the selector rule is an include rule.
325  *
326  * @param[in]  iterator  Iterator.
327  *
328  * @return -1 if iteration is complete, 1 if include, else 0.
329  */
330 int
nvt_selector_iterator_include(iterator_t * iterator)331 nvt_selector_iterator_include (iterator_t* iterator)
332 {
333   int ret;
334   if (iterator->done) return -1;
335   ret = iterator_int (iterator, 0);
336   return ret == 0;
337 }
338 
339 /**
340  * @brief Get the NVT or family from an NVT selector iterator.
341  *
342  * @param[in]  iterator  Iterator.
343  *
344  * @return NVT selector, or NULL if iteration is complete.
345  */
346 DEF_ACCESS (nvt_selector_iterator_nvt, 1);
347 
348 /**
349  * @brief Get the name from an NVT selector iterator.
350  *
351  * @param[in]  iterator  Iterator.
352  *
353  * @return NVT selector, or NULL if iteration is complete.
354  */
355 DEF_ACCESS (nvt_selector_iterator_name, 2);
356 
357 /**
358  * @brief Get the type from an NVT selector.
359  *
360  * @param[in]  iterator  Iterator.
361  *
362  * @return -1 if iteration is complete, 1 if include, else 0.
363  */
364 int
nvt_selector_iterator_type(iterator_t * iterator)365 nvt_selector_iterator_type (iterator_t* iterator)
366 {
367   int ret;
368   if (iterator->done) return -1;
369   ret = iterator_int (iterator, 3);
370   return ret;
371 }
372 
373 /**
374  * @brief Initialise an NVT selector family iterator.
375  *
376  * @param[in]  iterator   Iterator.
377  * @param[in]  all        True if families are growing in the selector, else 0.
378  *                        Only considered with a selector.
379  * @param[in]  selector   Name of NVT selector.  NULL for all families.
380  * @param[in]  ascending  Whether to sort ascending or descending.
381  */
382 void
init_family_iterator(iterator_t * iterator,int all,const char * selector,int ascending)383 init_family_iterator (iterator_t* iterator, int all, const char* selector,
384                       int ascending)
385 {
386   gchar *quoted_selector;
387 
388   if (selector == NULL)
389     {
390       init_iterator (iterator,
391                      "SELECT distinct family FROM nvts"
392                      " WHERE family != 'Credentials'"
393                      " ORDER BY family %s;",
394                      ascending ? "ASC" : "DESC");
395       return;
396     }
397 
398   quoted_selector = sql_quote (selector);
399   if (all)
400     /* Constraining the universe.  Presume there is a family exclude for
401      * every NVT include. */
402     init_iterator (iterator,
403                    "SELECT distinct family FROM nvts"
404                    " WHERE family != 'Credentials'"
405                    " EXCEPT"
406                    " SELECT distinct family FROM nvt_selectors"
407                    " WHERE type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
408                    " AND exclude = 1"
409                    " AND name = '%s'"
410                    " UNION"
411                    " SELECT distinct family FROM nvt_selectors"
412                    " WHERE type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
413                    " AND exclude = 0"
414                    " AND name = '%s'"
415                    " ORDER BY 1 %s;", /* 1 is family. */
416                    quoted_selector,
417                    quoted_selector,
418                    ascending ? "ASC" : "DESC");
419   else
420     /* Generating from empty.  Presume any exclude is covered by an include. */
421     init_iterator (iterator,
422                    "SELECT distinct family FROM nvt_selectors"
423                    " WHERE (type = 1 OR type = 2) AND name = '%s'"
424                    " AND family != 'Credentials'"
425                    " ORDER BY 1 %s;", /* 1 is family. */
426                    quoted_selector,
427                    ascending ? "ASC" : "DESC");
428   g_free (quoted_selector);
429 }
430 
431 /**
432  * @brief Get the name from a family iterator.
433  *
434  * @param[in]  iterator  Iterator.
435  *
436  * @return Name, or NULL if iteration is complete.  Freed by
437  *         cleanup_iterator.
438  */
439 DEF_ACCESS (family_iterator_name, 0);
440 
441 /**
442  * @brief Get whether an NVT selector selects every NVT in a family.
443  *
444  * @param[in]  selector  NVT selector.
445  * @param[in]  family    Family name.
446  * @param[in]  all       True if selector is an "all" selector, else 0.
447  *
448  * @return 1 yes, 0 no.
449  */
450 static int
nvt_selector_entire_and_growing(const char * selector,const char * family,int all)451 nvt_selector_entire_and_growing (const char *selector,
452                                  const char *family,
453                                  int all)
454 {
455   int ret;
456   gchar *quoted_family;
457   gchar *quoted_selector;
458 
459   quoted_selector = sql_quote (selector);
460   quoted_family = sql_quote (family);
461 
462   if (all)
463     {
464       /* Constraining the universe. */
465 
466       ret = sql_int ("SELECT COUNT(*) FROM nvt_selectors"
467                      " WHERE name = '%s'"
468                      " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
469                      " AND family_or_nvt = '%s'"
470                      " AND exclude = 1"
471                      " LIMIT 1;",
472                      quoted_selector,
473                      quoted_family);
474 
475       if (ret)
476         /* There's an exclude for the family, so family is static. */
477         ret = 0;
478       else
479         {
480           ret = sql_int ("SELECT COUNT(*) FROM nvt_selectors"
481                          " WHERE name = '%s'"
482                          " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
483                          " AND exclude = 1"
484                          /* And NVT is in family. */
485                          " AND EXISTS (SELECT * FROM nvts"
486                          "             WHERE oid = family_or_nvt"
487                          "             AND family = '%s')"
488                          " LIMIT 1;",
489                          quoted_selector,
490                          quoted_family);
491           if (ret)
492             /* Growing, but some NVTs excluded. */
493             ret = 0;
494           else
495             /* Growing, every NVT included. */
496             ret = 1;
497         }
498 
499       g_free (quoted_selector);
500       g_free (quoted_family);
501 
502       return ret;
503     }
504 
505   /* Generating from empty. */
506 
507   ret = sql_int ("SELECT COUNT(*) FROM nvt_selectors"
508                  " WHERE name = '%s'"
509                  " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
510                  " AND family_or_nvt = '%s'"
511                  " AND exclude = 0"
512                  " LIMIT 1;",
513                  quoted_selector,
514                  quoted_family);
515 
516   if (ret)
517     {
518       if (sql_int ("SELECT COUNT(*) FROM nvt_selectors"
519                    " WHERE name = '%s'"
520                    " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
521                    " AND exclude = 1"
522                    /* And NVT is in family. */
523                    " AND EXISTS (SELECT * FROM nvts"
524                    "             WHERE oid = family_or_nvt"
525                    "             AND family = '%s')"
526                    " LIMIT 1;",
527                    quoted_selector,
528                    quoted_family))
529         /* Growing, but some NVTs excluded. */
530         ret = 0;
531       else
532         /* Growing, every NVT included. */
533         ret = 1;
534     }
535   else
536     /* Family is not included, so family is static. */
537     ret = 0;
538 
539   g_free (quoted_selector);
540   g_free (quoted_family);
541 
542   return ret;
543 }
544 
545 /**
546  * @brief Get whether an NVT selector family is growing.
547  *
548  * @param[in]  selector  NVT selector.
549  * @param[in]  family    Family name.
550  * @param[in]  all       True if selector is an "all" selector, else 0.
551  *
552  * @return 1 growing, 0 static.
553  */
554 int
nvt_selector_family_growing(const char * selector,const char * family,int all)555 nvt_selector_family_growing (const char *selector,
556                              const char *family,
557                              int all)
558 {
559   int ret;
560   gchar *quoted_family;
561   gchar *quoted_selector;
562 
563   quoted_selector = sql_quote (selector);
564   quoted_family = sql_quote (family);
565 
566   if (all)
567     {
568       /* Constraining the universe.  It's static if there is a family
569        * exclude. */
570 
571       ret = sql_int ("SELECT COUNT(*) FROM nvt_selectors"
572                      " WHERE name = '%s'"
573                      " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
574                      " AND family_or_nvt = '%s'"
575                      " AND exclude = 1"
576                      " LIMIT 1;",
577                      quoted_selector,
578                      quoted_family);
579 
580       g_free (quoted_selector);
581       g_free (quoted_family);
582 
583       return ret ? 0 : 1;
584     }
585 
586   /* Generating from empty.  It's growing if there is a family include. */
587 
588   ret = sql_int ("SELECT COUNT(*) FROM nvt_selectors"
589                  " WHERE name = '%s'"
590                  " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
591                  " AND family_or_nvt = '%s'"
592                  " AND exclude = 0"
593                  " LIMIT 1;",
594                  quoted_selector,
595                  quoted_family);
596 
597   g_free (quoted_selector);
598   g_free (quoted_family);
599 
600   return ret ? 1 : 0;
601 }
602 
603 /**
604  * @brief Get the number of NVTs selected by an NVT selector.
605  *
606  * @param[in]  selector  NVT selector.
607  * @param[in]  family    Family name.  NULL for all.
608  * @param[in]  growing   True if the given family is growing, else 0.
609  *                       If family is NULL, true if the the families
610  *                       are growing, else 0.
611  *
612  * @return Number of NVTs selected in one or all families.
613  */
614 int
nvt_selector_nvt_count(const char * selector,const char * family,int growing)615 nvt_selector_nvt_count (const char *selector,
616                         const char *family,
617                         int growing)
618 {
619   if (family)
620     {
621       int ret;
622 
623       /* Count in a single family. */
624 
625       if (growing)
626         {
627           gchar *quoted_family = sql_quote (family);
628           gchar *quoted_selector = sql_quote (selector);
629           ret = sql_int ("SELECT COUNT(*) FROM nvts WHERE family = '%s';",
630                          quoted_family);
631           ret -= sql_int ("SELECT COUNT(*) FROM nvt_selectors"
632                           " WHERE exclude = 1 AND type = 2"
633                           " AND name = '%s' AND family = '%s';",
634                           quoted_selector,
635                           quoted_family);
636           g_free (quoted_family);
637           g_free (quoted_selector);
638         }
639       else
640         {
641           gchar *quoted_selector = sql_quote (selector);
642           gchar *quoted_family = sql_quote (family);
643           ret = sql_int ("SELECT COUNT(*) FROM nvt_selectors"
644                          " WHERE exclude = 0 AND type = 2"
645                          " AND name = '%s' AND family = '%s';",
646                          quoted_selector,
647                          quoted_family);
648           g_free (quoted_family);
649           g_free (quoted_selector);
650         }
651 
652       return ret;
653    }
654  else
655    {
656      int count;
657      iterator_t families;
658 
659      /* Count in each family. */
660 
661      count = 0;
662      init_family_iterator (&families, 0, NULL, 1);
663      while (next (&families))
664        {
665          const char *name = family_iterator_name (&families);
666          if (name)
667            count += nvt_selector_nvt_count (selector,
668                                             name,
669                                             nvt_selector_family_growing
670                                              (selector, name, growing));
671        }
672      cleanup_iterator (&families);
673 
674      return count;
675    }
676 }
677 
678 /**
679  * @brief Remove all selectors of a certain family from an NVT selector.
680  *
681  * @param[in]  quoted_selector  SQL-quoted selector name.
682  * @param[in]  quoted_family    SQL-quoted family name.
683  * @param[in]  type             Selector type to remove.
684  */
685 static void
nvt_selector_remove(const char * quoted_selector,const char * quoted_family,int type)686 nvt_selector_remove (const char* quoted_selector,
687                      const char* quoted_family,
688                      int type)
689 {
690   if (strcmp (quoted_selector, MANAGE_NVT_SELECTOR_UUID_ALL) == 0)
691     return;
692   if (type == NVT_SELECTOR_TYPE_ANY)
693     sql ("DELETE FROM nvt_selectors"
694          " WHERE name = '%s'"
695          " AND"
696          " ((type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
697          "   AND family = '%s')"
698          "  OR (type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
699          "      AND family_or_nvt = '%s'));",
700          quoted_selector,
701          quoted_family,
702          quoted_family);
703   else if (type == NVT_SELECTOR_TYPE_NVT)
704     sql ("DELETE FROM nvt_selectors"
705          " WHERE name = '%s'"
706          " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
707          " AND family = '%s';",
708          quoted_selector,
709          quoted_family);
710   else if (type == NVT_SELECTOR_TYPE_FAMILY)
711     sql ("DELETE FROM nvt_selectors"
712          " WHERE name = '%s'"
713          " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
714          " AND family_or_nvt = '%s';",
715          quoted_selector,
716          quoted_family);
717 }
718 
719 /**
720  * @brief Remove all selectors of a certain type from an NVT selector.
721  *
722  * @param[in]  quoted_selector  SQL-quoted selector name.
723  * @param[in]  family_or_nvt    SQL-quoted family name or NVT UUID.
724  * @param[in]  type             Selector type to remove.
725  */
726 static void
nvt_selector_remove_selector(const char * quoted_selector,const char * family_or_nvt,int type)727 nvt_selector_remove_selector (const char* quoted_selector,
728                               const char* family_or_nvt,
729                               int type)
730 {
731   if (strcmp (quoted_selector, MANAGE_NVT_SELECTOR_UUID_ALL) == 0)
732     return;
733   if (type == NVT_SELECTOR_TYPE_ANY)
734     sql ("DELETE FROM nvt_selectors"
735          " WHERE name = '%s' AND family_or_nvt = '%s');",
736          quoted_selector,
737          family_or_nvt);
738   else if (type == NVT_SELECTOR_TYPE_ALL)
739     sql ("DELETE FROM nvt_selectors"
740          " WHERE name = '%s'"
741          " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_ALL) ";",
742          quoted_selector);
743   else
744     sql ("DELETE FROM nvt_selectors"
745          " WHERE name = '%s'"
746          " AND type = %i"
747          " AND family_or_nvt = '%s';",
748          quoted_selector,
749          type,
750          family_or_nvt);
751 }
752 
753 /**
754  * @brief Add a selector to an NVT selector.
755  *
756  * @param[in]  quoted_selector  SQL-quoted selector name.
757  * @param[in]  quoted_family_or_nvt  SQL-quoted family or NVT name.
758  * @param[in]  quoted_family    SQL-quoted family name (NULL for families).
759  * @param[in]  exclude          1 exclude selector, 0 include selector.
760  */
761 static void
nvt_selector_add(const char * quoted_selector,const char * quoted_family_or_nvt,const char * quoted_family,int exclude)762 nvt_selector_add (const char* quoted_selector,
763                   const char* quoted_family_or_nvt,
764                   const char* quoted_family,
765                   int exclude)
766 {
767   if (quoted_family == NULL)
768     sql ("INSERT INTO nvt_selectors"
769          " (name, exclude, type, family_or_nvt, family)"
770          " VALUES ('%s', %i, "
771          G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
772          ", '%s', '%s');",
773          quoted_selector,
774          exclude,
775          quoted_family_or_nvt,
776          quoted_family_or_nvt);
777   else
778     sql ("INSERT INTO nvt_selectors"
779          " (name, exclude, type, family_or_nvt, family)"
780          " VALUES ('%s', %i, "
781          G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
782          ", '%s', '%s');",
783          quoted_selector,
784          exclude,
785          quoted_family_or_nvt,
786          quoted_family);
787 }
788 
789 /**
790  * @brief Set the family of an NVT selector.
791  *
792  * @param[in]  quoted_selector  SQL-quoted selector name.
793  * @param[in]  family_or_nvt    Family name or NVT OID of selector.
794  * @param[in]  type             Selector type to remove.
795  * @param[in]  family           New family.
796  */
797 static void
nvt_selector_set_family(const char * quoted_selector,const char * family_or_nvt,int type,const char * family)798 nvt_selector_set_family (const char* quoted_selector,
799                          const char* family_or_nvt,
800                          int type,
801                          const char *family)
802 {
803   gchar *quoted_family_or_nvt, *quoted_family;
804 
805   quoted_family_or_nvt = sql_quote (family_or_nvt);
806   quoted_family = sql_quote (family);
807   sql ("UPDATE nvt_selectors SET family = '%s'"
808        " WHERE name = '%s'"
809        " AND family_or_nvt = '%s'"
810        " AND type = %i;",
811        quoted_family,
812        quoted_selector,
813        quoted_family_or_nvt,
814        type);
815   g_free (quoted_family);
816   g_free (quoted_family_or_nvt);
817 }
818 
819 /**
820  * @brief Check whether a family is selected.
821  *
822  * Only works for "generating from empty" selection.
823  *
824  * @param[in]  quoted_selector  SQL-quoted selector name.
825  * @param[in]  quoted_family    SQL-quoted family name (NULL for families).
826  *
827  * @return 1 if selected, else 0.
828  */
829 static int
family_is_selected(const char * quoted_selector,const char * quoted_family)830 family_is_selected (const char* quoted_selector, const char* quoted_family)
831 {
832   return sql_int ("SELECT count(*) FROM nvt_selectors"
833                   " WHERE name = '%s'"
834                   " AND (type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
835                   "      AND family = '%s')"
836                   " OR (type = " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY)
837                   "     AND family_or_nvt = '%s');",
838                   quoted_selector,
839                   quoted_family,
840                   quoted_family);
841 }
842 
843 /**
844  * @brief Check whether an NVT selector has a particular selector.
845  *
846  * @param[in]  quoted_selector  SQL-quoted selector name.
847  * @param[in]  family_or_nvt    SQL-quoted UUID of NVT, or family name.
848  * @param[in]  type             Selector type.
849  * @param[in]  exclude          1 exclude, 0 include.
850  *
851  * @return 1 if contains include/exclude, else 0.
852  */
853 static int
nvt_selector_has(const char * quoted_selector,const char * family_or_nvt,int type,int exclude)854 nvt_selector_has (const char* quoted_selector, const char* family_or_nvt,
855                   int type, int exclude)
856 {
857   return sql_int ("SELECT count(*) FROM nvt_selectors"
858                   " WHERE name = '%s'"
859                   " AND type = %i"
860                   " AND exclude = %i"
861                   " AND family_or_nvt = '%s'"
862                   " LIMIT 1;",
863                   quoted_selector,
864                   type,
865                   exclude,
866                   family_or_nvt);
867 }
868 
869 /**
870  * @brief Starts the SQL transaction for modify_config and finds the config.
871  *
872  * @param[in]  config_id    UUID of the config to find.
873  * @param[out] config_out   Row ID of the config or 0 if not found.
874  *
875  * @return 0 success, 1 config not found, -1 error.
876  */
877 int
manage_modify_config_start(const char * config_id,config_t * config_out)878 manage_modify_config_start (const char *config_id, config_t *config_out)
879 {
880   sql_begin_immediate ();
881 
882   if (find_config_with_permission (config_id, config_out, "modify_config"))
883     {
884       sql_rollback ();
885       return -1;
886     }
887   if (*config_out == 0)
888     {
889       sql_rollback ();
890       return 1;
891     }
892 
893   return 0;
894 }
895 
896 /**
897  * @brief Cancels a manage_config command and rolls back the changes.
898  */
899 void
manage_modify_config_cancel()900 manage_modify_config_cancel ()
901 {
902   sql_rollback ();
903 }
904 
905 /**
906  * @brief Commits the changes of a manage_config command.
907  */
908 void
manage_modify_config_commit()909 manage_modify_config_commit ()
910 {
911   sql_commit ();
912 }
913 
914 /**
915  * @brief Refresh NVT selection of a config from given families.
916  *
917  * @param[in]  config                Config to modify.
918  * @param[in]  growing_all_families  Growing families with all selection.
919  * @param[in]  static_all_families   Static families with all selection.
920  * @param[in]  growing_families      The rest of the growing families.
921  * @param[in]  grow_families         1 if families should grow, else 0.
922  * @param[out] rejected_family       Return of family if one was rejected.
923  *
924  * @return 0 success, 1 config in use, 2 whole-only families must be growing
925  *         and include entire family, -1 error.
926  */
927 int
manage_set_config_families(config_t config,GPtrArray * growing_all_families,GPtrArray * static_all_families,GPtrArray * growing_families,int grow_families,gchar ** rejected_family)928 manage_set_config_families (config_t config,
929                             GPtrArray* growing_all_families,
930                             GPtrArray* static_all_families,
931                             GPtrArray* growing_families,
932                             int grow_families,
933                             gchar **rejected_family)
934 {
935   static const gchar *wholes[] = FAMILIES_WHOLE_ONLY;
936   iterator_t families;
937   gchar *quoted_selector;
938   int constraining;
939   char *selector;
940 
941   /* Ensure that whole-only families include all NVTs and are growing. */
942 
943   if (rejected_family)
944     *rejected_family = NULL;
945 
946   for (const gchar **whole = wholes; *whole; whole++)
947     {
948       if (member (static_all_families, *whole)
949           || member (growing_families, *whole))
950         {
951           if (member (static_all_families, *whole))
952             g_debug ("%s rejected static/all whole-only family %s",
953                      __func__, *whole);
954           else if (member (growing_families, *whole))
955             g_debug ("%s rejected growing/empty whole-only family %s",
956                      __func__, *whole);
957 
958           if (rejected_family)
959             *rejected_family = g_strdup (*whole);
960           return 2;
961         }
962     }
963 
964   /* Check the args. */
965 
966   if (sql_int ("SELECT count(*) FROM tasks"
967                " WHERE config = %llu AND hidden = 0;",
968                config))
969     {
970       return 1;
971     }
972 
973   if (config_type (config) > 0)
974     {
975       return 0;
976     }
977   constraining = config_families_growing (config);
978 
979   if (constraining + grow_families == 1)
980     {
981       if (switch_representation (config, constraining))
982         {
983           return -1;
984         }
985       constraining = constraining == 0;
986     }
987 
988   selector = config_nvt_selector (config);
989   if (selector == NULL)
990     {
991       /* The config should always have a selector. */
992       return -1;
993     }
994   quoted_selector = sql_quote (selector);
995 
996   /* Loop through all the known families. */
997 
998   init_family_iterator (&families, 1, NULL, 1);
999   while (next (&families))
1000     {
1001       const char *family;
1002 
1003       family = family_iterator_name (&families);
1004       if (family)
1005         {
1006           int old_nvt_count, new_nvt_count = 0, was_selected, max_nvt_count;
1007           int family_growing;
1008           int growing_all = member (growing_all_families, family);
1009           int static_all = member (static_all_families, family);
1010           gchar *quoted_family = sql_quote (family);
1011 
1012           assert ((growing_all && static_all) == 0);
1013 
1014           family_growing = nvt_selector_family_growing (selector,
1015                                                         family,
1016                                                         constraining);
1017 
1018           old_nvt_count
1019             = nvt_selector_nvt_count (selector, family, family_growing);
1020 
1021           max_nvt_count = family_nvt_count (family);
1022 
1023           if (growing_all || static_all)
1024             {
1025               if (old_nvt_count == max_nvt_count
1026                   && ((growing_all && family_growing)
1027                       || (static_all && family_growing == 0)))
1028                 {
1029                   /* Already in required state. */
1030                   g_free (quoted_family);
1031                   continue;
1032                 }
1033 
1034               was_selected = family_is_selected (quoted_selector,
1035                                                  quoted_family);
1036 
1037               /* Flush all selectors in the family from the config. */
1038 
1039               nvt_selector_remove (quoted_selector,
1040                                    quoted_family,
1041                                    NVT_SELECTOR_TYPE_ANY);
1042 
1043               if (static_all)
1044                 {
1045                   iterator_t nvts;
1046 
1047                   /* Static selection of all the NVT's currently in the
1048                    * family. */
1049 
1050                   if (constraining)
1051                     {
1052                       /* Constraining the universe. */
1053 
1054                       /* Add an exclude for the family. */
1055 
1056                       nvt_selector_add (quoted_selector,
1057                                         quoted_family,
1058                                         NULL,
1059                                         1);
1060                     }
1061                   else
1062                     {
1063                       /* Generating from empty. */
1064                     }
1065 
1066                   /* Add an include for every NVT in the family. */
1067 
1068                   init_nvt_iterator (&nvts, (nvt_t) 0, (config_t) 0, family,
1069                                      NULL, 1, NULL);
1070                   while (next (&nvts))
1071                     {
1072                       nvt_selector_add (quoted_selector,
1073                                         nvt_iterator_oid (&nvts),
1074                                         quoted_family,
1075                                         0);
1076                       new_nvt_count++;
1077                     }
1078                   cleanup_iterator (&nvts);
1079                 }
1080               else if (growing_all)
1081                 {
1082                   /* Selection of an entire family, which grows with the family. */
1083 
1084                   if (constraining)
1085                     {
1086                       /* Constraining the universe. */
1087                     }
1088                   else
1089                     {
1090                       /* Generating from empty.  Add an include for the
1091                        * family. */
1092 
1093                       nvt_selector_add (quoted_selector,
1094                                         quoted_family,
1095                                         NULL,
1096                                         0);
1097 
1098                     }
1099 
1100                   new_nvt_count = max_nvt_count;
1101                 }
1102 
1103               /* Update the cached config info. */
1104 
1105               sql ("UPDATE configs SET nvt_count = nvt_count - %i + %i,"
1106                    " nvts_growing = %i, family_count = family_count + %i,"
1107                    " modification_time = m_now ()"
1108                    " WHERE id = %llu;",
1109                    old_nvt_count,
1110                    new_nvt_count,
1111                    growing_all
1112                     ? 1
1113                     /* Recalculate the NVT growing state. */
1114                     : nvt_selector_nvts_growing_2 (quoted_selector,
1115                                                    constraining),
1116                    was_selected ? 0 : 1,
1117                    config);
1118             }
1119           else
1120             {
1121               int must_grow = member (growing_families, family);
1122 
1123               if (must_grow)
1124                 {
1125                   /* The resulting family must be growing.  If currently
1126                    * growing, leave as is, otherwise switch family to
1127                    * growing. */
1128 
1129                   if (old_nvt_count == max_nvt_count)
1130                     {
1131                       iterator_t nvts;
1132 
1133                       /* All were selected.  Clear selection, ensuring that
1134                        * the family is growing in the process.  */
1135 
1136                       nvt_selector_remove (quoted_selector,
1137                                            quoted_family,
1138                                            NVT_SELECTOR_TYPE_ANY);
1139 
1140                       if (constraining == 0)
1141                         /* Generating. */
1142                         nvt_selector_add (quoted_selector,
1143                                           quoted_family,
1144                                           NULL,
1145                                           0);
1146 
1147                       /* Add an exclude for every NVT in the family. */
1148 
1149                       init_nvt_iterator (&nvts, (nvt_t) 0, (config_t) 0,
1150                                          family, NULL, 1, NULL);
1151                       while (next (&nvts))
1152                         nvt_selector_add (quoted_selector,
1153                                           nvt_iterator_oid (&nvts),
1154                                           quoted_family,
1155                                           1);
1156                       cleanup_iterator (&nvts);
1157 
1158                       /* Update the cached config info. */
1159 
1160                       sql ("UPDATE configs SET nvt_count = nvt_count - %i,"
1161                            " nvts_growing = 1, modification_time = m_now ()"
1162                            " WHERE id = %llu;",
1163                            old_nvt_count,
1164                            config);
1165                     }
1166                   else if (family_growing == 0)
1167                     {
1168                       iterator_t nvts;
1169 
1170                       if (constraining == 0)
1171                         nvt_selector_add (quoted_selector,
1172                                           quoted_family,
1173                                           NULL,
1174                                           0);
1175 
1176                       /* Remove any included NVT, add excludes for all
1177                        * other NVT's. */
1178 
1179                       init_nvt_iterator (&nvts, (nvt_t) 0, (config_t) 0,
1180                                          family, NULL, 1, NULL);
1181                       while (next (&nvts))
1182                         if (nvt_selector_has (quoted_selector,
1183                                               nvt_iterator_oid (&nvts),
1184                                               NVT_SELECTOR_TYPE_NVT,
1185                                               0))
1186                           nvt_selector_remove_selector
1187                            (quoted_selector,
1188                             nvt_iterator_oid (&nvts),
1189                             NVT_SELECTOR_TYPE_NVT);
1190                         else
1191                           nvt_selector_add (quoted_selector,
1192                                             nvt_iterator_oid (&nvts),
1193                                             quoted_family,
1194                                             1);
1195                       cleanup_iterator (&nvts);
1196 
1197                       /* Update the cached config info. */
1198 
1199                       sql ("UPDATE configs SET nvts_growing = 1,"
1200                            " modification_time = m_now ()"
1201                            " WHERE id = %llu;",
1202                            config);
1203                     }
1204                 }
1205               else
1206                 {
1207                   /* The resulting family must be static.  If currently
1208                    * static, leave as is, otherwise switch family to
1209                    * static. */
1210 
1211                   if (old_nvt_count == max_nvt_count)
1212                     {
1213                       /* All were selected, clear selection, ensuring the
1214                        * family is static in the process. */
1215 
1216                       nvt_selector_remove (quoted_selector,
1217                                            quoted_family,
1218                                            NVT_SELECTOR_TYPE_ANY);
1219                       if (constraining)
1220                         nvt_selector_add (quoted_selector,
1221                                           quoted_family,
1222                                           NULL,
1223                                           1);
1224 
1225                       /* Update the cached config info. */
1226 
1227                       sql ("UPDATE configs SET nvts_growing = %i,"
1228                            " nvt_count = nvt_count - %i,"
1229                            " family_count = family_count - 1,"
1230                            " modification_time = m_now ()"
1231                            " WHERE id = %llu;",
1232                            /* Recalculate the NVT growing state. */
1233                            nvt_selector_nvts_growing_2 (quoted_selector,
1234                                                         constraining),
1235                            old_nvt_count,
1236                            config);
1237                     }
1238                   else if (family_growing)
1239                     {
1240                       iterator_t nvts;
1241 
1242                       if (constraining)
1243                         nvt_selector_add (quoted_selector,
1244                                           quoted_family,
1245                                           NULL,
1246                                           1);
1247                       else
1248                         nvt_selector_remove (quoted_selector,
1249                                              quoted_family,
1250                                              NVT_SELECTOR_TYPE_FAMILY);
1251 
1252                       /* Remove any excluded NVT; add includes for all
1253                        * other NVT's. */
1254 
1255                       init_nvt_iterator (&nvts, (nvt_t) 0, (config_t) 0,
1256                                          family, NULL, 1, NULL);
1257                       while (next (&nvts))
1258                         if (nvt_selector_has (quoted_selector,
1259                                               nvt_iterator_oid (&nvts),
1260                                               NVT_SELECTOR_TYPE_NVT,
1261                                               1))
1262                           nvt_selector_remove_selector
1263                             (quoted_selector,
1264                              nvt_iterator_oid (&nvts),
1265                              NVT_SELECTOR_TYPE_NVT);
1266                         else
1267                           nvt_selector_add (quoted_selector,
1268                                             nvt_iterator_oid (&nvts),
1269                                             quoted_family,
1270                                             0);
1271                       cleanup_iterator (&nvts);
1272 
1273                       /* Update the cached config info. */
1274 
1275                       sql ("UPDATE configs SET nvts_growing = %i,"
1276                            " modification_time = m_now ()"
1277                            " WHERE id = %llu;",
1278                            /* Recalculate the NVT growing state. */
1279                            nvt_selector_nvts_growing_2 (quoted_selector,
1280                                                         constraining),
1281                            config);
1282                     }
1283                 }
1284             }
1285 
1286           g_free (quoted_family);
1287         }
1288     }
1289   cleanup_iterator (&families);
1290 
1291   g_free (quoted_selector);
1292   free (selector);
1293   return 0;
1294 }
1295 
1296 /**
1297  * @brief Insert NVT selectors.
1298  *
1299  * @param[in]  quoted_name   Name of NVT selector.
1300  * @param[in]  selectors     NVT selectors.
1301  * @param[in]  allow_errors  Whether certain errors are allowed.
1302  *
1303  * @return 0 success, -1 error, -3 input error.
1304  */
1305 static int
insert_nvt_selectors(const char * quoted_name,const array_t * selectors,int allow_errors)1306 insert_nvt_selectors (const char *quoted_name,
1307                       const array_t* selectors, /* nvt_selector_t. */
1308                       int allow_errors)
1309 {
1310   int index = 0;
1311   const nvt_selector_t *selector;
1312   if (selectors == NULL) return -3;
1313   while ((selector = (nvt_selector_t*) g_ptr_array_index (selectors, index++)))
1314     {
1315       int type;
1316 
1317       if (selector->type == NULL) return -3;
1318 
1319       /** @todo Check that selector->type is actually an integer. */
1320       type = atoi (selector->type);
1321 
1322       if ((selector->family_or_nvt != NULL)
1323           && (type == NVT_SELECTOR_TYPE_NVT))
1324         {
1325           gchar *quoted_family_or_nvt, *quoted_family, *family = NULL;
1326 
1327           /* An NVT selector. */
1328 
1329           family = nvt_family (selector->family_or_nvt);
1330           if (family == NULL)
1331             g_debug ("%s: NVT '%s' in config '%s' does not have a family",
1332                      __func__,
1333                      selector->family_or_nvt,
1334                      quoted_name);
1335 
1336           quoted_family_or_nvt = sql_quote (selector->family_or_nvt);
1337           quoted_family = sql_quote (family ? family : "");
1338           sql ("INSERT into nvt_selectors (name, exclude, type, family_or_nvt,"
1339                " family)"
1340                " VALUES ('%s', %i, %i, '%s', '%s');",
1341                quoted_name,
1342                selector->include ? 0 : 1,
1343                type,
1344                quoted_family_or_nvt,
1345                quoted_family);
1346           g_free (quoted_family_or_nvt);
1347           g_free (quoted_family);
1348         }
1349       else if (selector->family_or_nvt)
1350         {
1351           gchar *quoted_family_or_nvt;
1352 
1353           /* A family selector. */
1354 
1355           if (type != NVT_SELECTOR_TYPE_FAMILY)
1356             {
1357               g_warning ("%s: skipping NVT '%s' from import of config '%s'"
1358                          " because the type is wrong (expected family)",
1359                          __func__,
1360                          selector->family_or_nvt,
1361                          quoted_name);
1362               if (allow_errors)
1363                 continue;
1364               return -1;
1365             }
1366 
1367           quoted_family_or_nvt = sql_quote (selector->family_or_nvt);
1368 
1369           sql ("INSERT into nvt_selectors (name, exclude, type, family_or_nvt,"
1370                " family)"
1371                " VALUES ('%s', %i, %i, '%s', '%s');",
1372                quoted_name,
1373                selector->include ? 0 : 1,
1374                type,
1375                quoted_family_or_nvt,
1376                quoted_family_or_nvt);
1377           g_free (quoted_family_or_nvt);
1378         }
1379       else
1380         {
1381           /* An "all" selector. */
1382 
1383           if (type != NVT_SELECTOR_TYPE_ALL)
1384             {
1385               g_warning ("%s: skipping NVT from import of config '%s'"
1386                          " because the type is wrong (expected all)",
1387                          __func__,
1388                          quoted_name);
1389               if (allow_errors)
1390                 continue;
1391               return -1;
1392             }
1393 
1394           sql ("INSERT into nvt_selectors (name, exclude, type, family_or_nvt,"
1395                " family)"
1396                " VALUES ('%s', %i, %i, NULL, NULL);",
1397                quoted_name,
1398                selector->include ? 0 : 1,
1399                type);
1400         }
1401     }
1402   return 0;
1403 }
1404 
1405 /**
1406  * @brief Change the family of an NVT in a config.
1407  *
1408  * @param[in]  config      Config.
1409  * @param[in]  oid         NVT OID.
1410  * @param[in]  old_family  Name of old family.
1411  * @param[in]  new_family  Name of new family.
1412  *
1413  * @return 0 success, -1 error.
1414  */
1415 static int
config_update_nvt_family(resource_t config,const char * oid,const char * old_family,const char * new_family)1416 config_update_nvt_family (resource_t config, const char *oid,
1417                           const char *old_family, const char *new_family)
1418 {
1419   int constraining;
1420   char* selector;
1421   gchar *quoted_selector;
1422 
1423   selector = config_nvt_selector (config);
1424   if (selector == NULL)
1425     {
1426       g_warning ("%s: Failed to get config selector", __func__);
1427       return -1;
1428     }
1429   quoted_selector = sql_quote (selector);
1430 
1431   constraining = config_families_growing (config);
1432 
1433   g_debug ("%s: Updating NVT family for selector '%s'", __func__, selector);
1434 
1435   if (constraining)
1436     {
1437       /* Constraining the universe. */
1438 
1439       g_debug ("%s:   Selector constrains universe", __func__);
1440 
1441       if (nvt_selector_family_growing (selector, old_family, constraining))
1442         {
1443           /* Old family is growing. */
1444 
1445           g_debug ("%s:   Old family is growing", __func__);
1446 
1447           if (nvt_selector_has (quoted_selector, oid, NVT_SELECTOR_TYPE_NVT,
1448                                 0 /* Included. */))
1449             {
1450               /* NVT explicitly included in old family, which is redundant, so
1451                * drop selector. */
1452               g_debug ("%s:   Drop selector", __func__);
1453               nvt_selector_remove_selector (quoted_selector,
1454                                             oid,
1455                                             NVT_SELECTOR_TYPE_NVT);
1456             }
1457           else if (nvt_selector_has (quoted_selector, oid,
1458                                      NVT_SELECTOR_TYPE_NVT,
1459                                      1 /* Excluded. */))
1460             {
1461               /* NVT explicitly excluded from old family. */
1462 
1463               g_debug ("%s:   NVT excluded from old family", __func__);
1464 
1465               if (nvt_selector_family_growing (selector, new_family,
1466                                                constraining))
1467                 {
1468                   /* New family is growing, change NVT to new family. */
1469                   g_debug ("%s:   Change family", __func__);
1470                   nvt_selector_set_family (quoted_selector,
1471                                            oid,
1472                                            NVT_SELECTOR_TYPE_NVT,
1473                                            new_family);
1474                 }
1475               else
1476                 {
1477                   /* New family static, NVT excluded already, so drop NVT
1478                    * selector. */
1479                   g_debug ("%s:   Remove selector", __func__);
1480                   nvt_selector_remove_selector (quoted_selector,
1481                                                 oid,
1482                                                 NVT_SELECTOR_TYPE_NVT);
1483                 }
1484             }
1485         }
1486       else
1487         {
1488           /* Old family is static. */
1489 
1490           g_debug ("%s:   Old family is static", __func__);
1491 
1492           if (nvt_selector_has (quoted_selector, oid, NVT_SELECTOR_TYPE_NVT,
1493                                 0 /* Included. */))
1494             {
1495               /* NVT explicitly included in old family. */
1496 
1497               g_debug ("%s:   NVT included in old family", __func__);
1498 
1499               if (nvt_selector_family_growing (selector, new_family,
1500                                                constraining))
1501                 {
1502                   /* New family is growing so it already includes the NVT.
1503                    * Remove the NVT selector. */
1504                   g_debug ("%s:   Remove selector", __func__);
1505                   nvt_selector_remove_selector (quoted_selector,
1506                                                 oid,
1507                                                 NVT_SELECTOR_TYPE_NVT);
1508                 }
1509               else
1510                 {
1511                   /* New family static, change NVT to new family. */
1512                   g_debug ("%s:   Change family", __func__);
1513                   nvt_selector_set_family (quoted_selector,
1514                                            oid,
1515                                            NVT_SELECTOR_TYPE_NVT,
1516                                            new_family);
1517                 }
1518             }
1519           else if (nvt_selector_has (quoted_selector, oid,
1520                                      NVT_SELECTOR_TYPE_NVT,
1521                                      1 /* Excluded. */))
1522             {
1523               /* NVT explicitly excluded from old family, which is redundant, so
1524                * remove NVT selector. */
1525               g_debug ("%s:   Remove selector", __func__);
1526               nvt_selector_remove_selector (quoted_selector,
1527                                             oid,
1528                                             NVT_SELECTOR_TYPE_NVT);
1529             }
1530         }
1531     }
1532   else
1533     {
1534       /* Generating from empty. */
1535 
1536       g_debug ("%s:   Selector generates from empty", __func__);
1537 
1538       if (nvt_selector_family_growing (selector, old_family, constraining))
1539         {
1540           /* Old family is growing. */
1541 
1542           g_debug ("%s:   Old family is growing", __func__);
1543 
1544           if (nvt_selector_has (quoted_selector, oid, NVT_SELECTOR_TYPE_NVT,
1545                                 0 /* Included. */))
1546             {
1547               /* NVT explicitly included in old family.  This is redundant, so
1548                * just remove the NVT selector. */
1549               g_debug ("%s:   Remove selector", __func__);
1550               nvt_selector_remove_selector (quoted_selector,
1551                                             oid,
1552                                             NVT_SELECTOR_TYPE_NVT);
1553             }
1554           else if (nvt_selector_has (quoted_selector, oid,
1555                                      NVT_SELECTOR_TYPE_NVT,
1556                                      1 /* Excluded. */))
1557             {
1558               /* NVT explicitly excluded from old family. */
1559 
1560               g_debug ("%s:   NVT excluded from old family", __func__);
1561 
1562               if (nvt_selector_family_growing (selector, new_family,
1563                                                constraining))
1564                 {
1565                   /* New family is growing, change NVT to new family. */
1566                   g_debug ("%s:   Change family", __func__);
1567                   nvt_selector_set_family (quoted_selector,
1568                                            oid,
1569                                            NVT_SELECTOR_TYPE_NVT,
1570                                            new_family);
1571                 }
1572               else
1573                 {
1574                   /* New family static, so the NVT is already excluded from the
1575                    * new family.  Remove the NVT selector. */
1576                   g_debug ("%s:   Remove selector", __func__);
1577                   nvt_selector_remove_selector (quoted_selector,
1578                                                 oid,
1579                                                 NVT_SELECTOR_TYPE_NVT);
1580                 }
1581             }
1582         }
1583       else
1584         {
1585           /* Old family is static. */
1586 
1587           g_debug ("%s:   Old family is static", __func__);
1588 
1589           if (nvt_selector_has (quoted_selector, oid, NVT_SELECTOR_TYPE_NVT,
1590                                 0 /* Included. */))
1591             {
1592               /* NVT explicitly included in old family. */
1593 
1594               g_debug ("%s:   NVT included in old family", __func__);
1595 
1596               if (nvt_selector_family_growing (selector, new_family,
1597                                                constraining))
1598                 {
1599                   /* New family growing, so the NVT is already in there.  Remove
1600                    * the NVT selector. */
1601                   g_debug ("%s:   Remove selector", __func__);
1602                   nvt_selector_remove_selector (quoted_selector,
1603                                                 oid,
1604                                                 NVT_SELECTOR_TYPE_NVT);
1605                 }
1606               else
1607                 {
1608                   /* New family is static, change NVT to new family. */
1609                   g_debug ("%s:   Change family", __func__);
1610                   nvt_selector_set_family (quoted_selector,
1611                                            oid,
1612                                            NVT_SELECTOR_TYPE_NVT,
1613                                            new_family);
1614                 }
1615             }
1616           else if (nvt_selector_has (quoted_selector, oid,
1617                                      NVT_SELECTOR_TYPE_NVT,
1618                                      1 /* Excluded. */))
1619             {
1620               /* NVT explicitly excluded from old family.  This is redundant,
1621                * so just remove the NVT selector. */
1622               g_debug ("%s:   NVT exclude from old family, remove selector",
1623                        __func__);
1624               nvt_selector_remove_selector (quoted_selector,
1625                                             oid,
1626                                             NVT_SELECTOR_TYPE_NVT);
1627             }
1628         }
1629     }
1630 
1631   g_free (quoted_selector);
1632   free (selector);
1633   return 0;
1634 }
1635 
1636 /**
1637  * @brief Change the family of an NVT in all configs.
1638  *
1639  * @param[in]  oid         NVT OID.
1640  * @param[in]  old_family  Name of old family.
1641  * @param[in]  new_family  Name of new family.
1642  *
1643  * @return 0 success, -1 error.
1644  */
1645 static int
update_nvt_family(const char * oid,const char * old_family,const char * new_family)1646 update_nvt_family (const char *oid, const char *old_family,
1647                    const char *new_family)
1648 {
1649   int ret;
1650   iterator_t rows;
1651 
1652   ret = 0;
1653   init_iterator (&rows, "SELECT id FROM configs WHERE type = 0;");
1654   while (next (&rows))
1655     if (config_update_nvt_family (iterator_int64 (&rows, 0), oid, old_family,
1656                                   new_family))
1657       ret = -1;
1658   cleanup_iterator (&rows);
1659   return ret;
1660 }
1661 
1662 /**
1663  * @brief Ensure that all configs refer to the right NVT families.
1664  *
1665  * When the family of an NVT is changed in the feed, then the config
1666  * refers to the wrong family.
1667  *
1668  * @return 0 success, -1 error.
1669  */
1670 int
check_config_families()1671 check_config_families ()
1672 {
1673   int ret;
1674   iterator_t selectors;
1675 
1676   ret = 0;
1677   /* Get all NVT selectors that have the wrong family. */
1678   init_iterator (&selectors,
1679                  "SELECT DISTINCT family_or_nvt, family,"
1680                  "       (SELECT family FROM nvts WHERE oid = family_or_nvt)"
1681                  " FROM nvt_selectors"
1682                  " WHERE type = 2"
1683                  " AND family != (SELECT family FROM nvts"
1684                  "                WHERE oid = family_or_nvt);");
1685   while (next (&selectors))
1686     /* Update the family of the NVT selector. */
1687     if (update_nvt_family (iterator_string (&selectors, 0),
1688                            iterator_string (&selectors, 1),
1689                            iterator_string (&selectors, 2)))
1690       ret = -1;
1691   cleanup_iterator (&selectors);
1692   return ret;
1693 }
1694 
1695 
1696 /* NVT preferences.  This is part of Configs. */
1697 
1698 /**
1699  * @brief Add/replace an NVT preference.
1700  *
1701  * @param[in]  name    The name of the preference.
1702  * @param[in]  value   The value of the preference.
1703  */
1704 void
manage_nvt_preference_add(const char * name,const char * value)1705 manage_nvt_preference_add (const char* name, const char* value)
1706 {
1707   gchar* quoted_name = sql_quote (name);
1708   gchar* quoted_value = sql_quote (value);
1709 
1710   if (strcmp (name, "port_range"))
1711     {
1712       if (sql_int ("SELECT EXISTS"
1713                    "  (SELECT * FROM nvt_preferences"
1714                    "   WHERE name = '%s')",
1715                    quoted_name))
1716         sql ("DELETE FROM nvt_preferences WHERE name = '%s';", quoted_name);
1717 
1718       sql ("INSERT into nvt_preferences (name, value)"
1719            " VALUES ('%s', '%s');",
1720            quoted_name, quoted_value);
1721     }
1722 
1723   g_free (quoted_name);
1724   g_free (quoted_value);
1725 }
1726 
1727 /**
1728  * @brief Initialise an NVT preference iterator.
1729  *
1730  * @param[in]  iterator  Iterator.
1731  * @param[in]  oid       OID of NVT, NULL for all preferences.
1732  */
1733 void
init_nvt_preference_iterator(iterator_t * iterator,const char * oid)1734 init_nvt_preference_iterator (iterator_t* iterator, const char *oid)
1735 {
1736   if (oid)
1737     {
1738       gchar *quoted_oid = sql_quote (oid);
1739       init_iterator (iterator,
1740                      "SELECT name, value FROM nvt_preferences"
1741                      " WHERE name %s '%s:%%'"
1742                      " AND name != 'cache_folder'"
1743                      " AND name != 'include_folders'"
1744                      " AND name != 'nasl_no_signature_check'"
1745                      " AND name != 'network_targets'"
1746                      " AND name != 'ntp_save_sessions'"
1747                      " AND name != '%s:0:entry:Timeout'"
1748                      " AND name NOT %s 'server_info_%%'"
1749                      /* Task preferences. */
1750                      " AND name != 'max_checks'"
1751                      " AND name != 'max_hosts'"
1752                      " ORDER BY name ASC",
1753                      sql_ilike_op (),
1754                      quoted_oid,
1755                      quoted_oid,
1756                      sql_ilike_op ());
1757       g_free (quoted_oid);
1758     }
1759   else
1760     init_iterator (iterator,
1761                    "SELECT name, value FROM nvt_preferences"
1762                    " WHERE name != 'cache_folder'"
1763                    " AND name != 'include_folders'"
1764                    " AND name != 'nasl_no_signature_check'"
1765                    " AND name != 'network_targets'"
1766                    " AND name != 'ntp_save_sessions'"
1767                    " AND name NOT %s '%%:0:entry:Timeout'"
1768                    " AND name NOT %s 'server_info_%%'"
1769                    /* Task preferences. */
1770                    " AND name != 'max_checks'"
1771                    " AND name != 'max_hosts'"
1772                    " ORDER BY name ASC",
1773                    sql_ilike_op (),
1774                    sql_ilike_op ());
1775 }
1776 
1777 /**
1778  * @brief Get the name from an NVT preference iterator.
1779  *
1780  * @param[in]  iterator  Iterator.
1781  *
1782  * @return Name, or NULL if iteration is complete.  Freed by
1783  *         cleanup_iterator.
1784  */
1785 DEF_ACCESS (nvt_preference_iterator_name, 0);
1786 
1787 /**
1788  * @brief Get the value from an NVT preference iterator.
1789  *
1790  * @param[in]  iterator  Iterator.
1791  *
1792  * @return Value, or NULL if iteration is complete.  Freed by
1793  *         cleanup_iterator.
1794  */
1795 DEF_ACCESS (nvt_preference_iterator_value, 1);
1796 
1797 /**
1798  * @brief Get the real name from an NVT preference iterator.
1799  *
1800  * @param[in]  iterator  Iterator.
1801  *
1802  * @return Real name.
1803  */
1804 char*
nvt_preference_iterator_real_name(iterator_t * iterator)1805 nvt_preference_iterator_real_name (iterator_t* iterator)
1806 {
1807   const char *ret;
1808   char *real_name = NULL;
1809   if (iterator->done) return NULL;
1810   ret = iterator_string (iterator, 0);
1811   if (ret)
1812     {
1813       char **splits = g_strsplit (ret, ":", 4);
1814       if (splits && g_strv_length (splits) == 4)
1815         real_name = g_strdup (splits[3]);
1816       g_strfreev (splits);
1817       return real_name ?: g_strdup (ret);
1818     }
1819   return NULL;
1820 }
1821 
1822 /**
1823  * @brief Get the type from an NVT preference iterator.
1824  *
1825  * @param[in]  iterator  Iterator.
1826  *
1827  * @return Type.
1828  */
1829 char*
nvt_preference_iterator_type(iterator_t * iterator)1830 nvt_preference_iterator_type (iterator_t* iterator)
1831 {
1832   const char *ret;
1833   char *type = NULL;
1834   if (iterator->done)
1835     return NULL;
1836   ret = iterator_string (iterator, 0);
1837   if (ret)
1838     {
1839       char **splits = g_strsplit (ret, ":", 4);
1840       if (splits && g_strv_length (splits) == 4)
1841         type = g_strdup (splits[2]);
1842       g_strfreev (splits);
1843     }
1844   return type;
1845 }
1846 
1847 /**
1848  * @brief Get the NVT from an NVT preference iterator.
1849  *
1850  * @param[in]  iterator  Iterator.
1851  *
1852  * @return NVT.
1853  */
1854 char*
nvt_preference_iterator_oid(iterator_t * iterator)1855 nvt_preference_iterator_oid (iterator_t* iterator)
1856 {
1857   const char *ret;
1858   char *oid = NULL;
1859   if (iterator->done)
1860     return NULL;
1861   ret = iterator_string (iterator, 0);
1862   if (ret)
1863     {
1864       char **splits = g_strsplit (ret, ":", 4);
1865       if (splits && g_strv_length (splits) == 4)
1866         oid = g_strdup (splits[0]);
1867       g_strfreev (splits);
1868     }
1869   return oid;
1870 }
1871 
1872 /**
1873  * @brief Get the ID from an NVT preference iterator.
1874  *
1875  * @param[in]  iterator  Iterator.
1876  *
1877  * @return NVT.
1878  */
1879 char*
nvt_preference_iterator_id(iterator_t * iterator)1880 nvt_preference_iterator_id (iterator_t* iterator)
1881 {
1882   const char *ret;
1883   char *id = NULL;
1884 
1885   if (iterator->done)
1886     return NULL;
1887   ret = iterator_string (iterator, 0);
1888   if (ret)
1889     {
1890       char **splits = g_strsplit (ret, ":", 4);
1891       if (splits && g_strv_length (splits) == 4)
1892         id = g_strdup (splits[1]);
1893       g_strfreev (splits);
1894     }
1895   return id;
1896 }
1897 
1898 /**
1899  * @brief Get the config value from an NVT preference iterator.
1900  *
1901  * @param[in]  iterator  Iterator.
1902  * @param[in]  config    Config.
1903  *
1904  * @return Freshly allocated config value.
1905  */
1906 char*
nvt_preference_iterator_config_value(iterator_t * iterator,config_t config)1907 nvt_preference_iterator_config_value (iterator_t* iterator, config_t config)
1908 {
1909   gchar *quoted_name, *value;
1910   const char *ret;
1911   if (iterator->done) return NULL;
1912 
1913   quoted_name = sql_quote (iterator_string (iterator, 0));
1914   value = sql_string ("SELECT value FROM config_preferences"
1915                       " WHERE config = %llu"
1916                       " AND name = '%s'"
1917                       /* Ensure that the NVT pref comes first, in case an
1918                        * error in the GSA added the NVT pref as a Scanner
1919                        * pref. */
1920                       " ORDER BY type",
1921                       config,
1922                       quoted_name);
1923   g_free (quoted_name);
1924   if (value) return value;
1925 
1926   ret = iterator_string (iterator, 1);
1927   if (ret) return g_strdup (ret);
1928   return NULL;
1929 }
1930 
1931 /**
1932  * @brief Get the number preferences available for an NVT.
1933  *
1934  * @param[in]  oid  OID of NVT.
1935  *
1936  * @return Number of possible preferences on NVT.
1937  */
1938 int
nvt_preference_count(const char * oid)1939 nvt_preference_count (const char *oid)
1940 {
1941   gchar *quoted_oid = sql_quote (oid);
1942   int ret = sql_int ("SELECT COUNT(*) FROM nvt_preferences"
1943                      " WHERE name != '%s:0:entry:Timeout'"
1944                      "   AND name %s '%s:%%';",
1945                      quoted_oid,
1946                      sql_ilike_op (),
1947                      quoted_oid);
1948   g_free (quoted_oid);
1949   return ret;
1950 }
1951 
1952 /**
1953  * @brief Get the value of a task preference.
1954  *
1955  * @param[in]  task  Task.
1956  * @param[in]  name  Preference name.
1957  *
1958  * @return Freshly allocated task preference value or NULL if pref missing.
1959  */
1960 char*
task_preference_value(task_t task,const char * name)1961 task_preference_value (task_t task, const char *name)
1962 {
1963   gchar *quoted_name, *value;
1964 
1965   quoted_name = sql_quote (name);
1966   value = sql_string ("SELECT value FROM task_preferences"
1967                       " WHERE task = %llu"
1968                       " AND name = '%s';",
1969                       task,
1970                       quoted_name);
1971   if (value)
1972     {
1973       g_free (quoted_name);
1974       return value;
1975     }
1976 
1977   value = sql_string ("SELECT value FROM nvt_preferences"
1978                       " WHERE name = '%s';",
1979                       quoted_name);
1980   g_free (quoted_name);
1981   return value;
1982 }
1983 
1984 /**
1985  * @brief Set the preferences of a task.
1986  *
1987  * Only the given preferences are affected.  A NULL value means to remove
1988  * the preference (reverts to using scanner value).
1989  *
1990  * @param[in]  task         Task.
1991  * @param[in]  preferences  Preferences.
1992  *
1993  * @return 0 success, 1 invalid auto_delete value, 2 auto_delete_data out of
1994  *         range.
1995  */
1996 int
set_task_preferences(task_t task,array_t * preferences)1997 set_task_preferences (task_t task, array_t *preferences)
1998 {
1999   if (preferences)
2000     {
2001       guint index;
2002       for (index = 0; index < preferences->len; index++)
2003         {
2004           name_value_t *pair;
2005           pair = (name_value_t*) g_ptr_array_index (preferences, index);
2006           if (pair && pair->name)
2007             {
2008               gchar *quoted_name;
2009               quoted_name = sql_quote (pair->name);
2010               if (pair->value)
2011                 {
2012                   gchar *quoted_value;
2013 
2014                   if ((strcmp (pair->name, "auto_delete") == 0)
2015                       && (strcmp (pair->value, "keep"))
2016                       && (strcmp (pair->value, "no")))
2017                     {
2018                       return 1;
2019                     }
2020 
2021                   if (strcmp (pair->name, "auto_delete_data") == 0)
2022                     {
2023                       int keep;
2024                       keep = atoi (pair->value);
2025                       if (keep < AUTO_DELETE_KEEP_MIN
2026                           || keep > AUTO_DELETE_KEEP_MAX)
2027                         return 2;
2028                     }
2029 
2030                   if ((strcmp (pair->name, "in_assets") == 0)
2031                       && scanner_type (task_scanner (task)) == SCANNER_TYPE_CVE)
2032                     quoted_value = g_strdup ("no");
2033                   else
2034                     quoted_value = sql_quote (pair->value);
2035                   sql_begin_immediate ();
2036                   if (sql_int ("SELECT COUNT(*) FROM task_preferences"
2037                                " WHERE task = %llu AND name = '%s';",
2038                                task,
2039                                quoted_name))
2040                     sql ("UPDATE task_preferences"
2041                          " SET value = '%s'"
2042                          " WHERE task = %llu AND name = '%s';",
2043                          quoted_value,
2044                          task,
2045                          quoted_name);
2046                   else
2047                     sql ("INSERT INTO task_preferences"
2048                          " (task, name, value)"
2049                          " VALUES"
2050                          " (%llu, '%s', '%s');",
2051                          task,
2052                          quoted_name,
2053                          quoted_value);
2054                   sql_commit ();
2055                   g_free (quoted_value);
2056                 }
2057               else
2058                 sql ("DELETE FROM task_preferences"
2059                      " WHERE task = %llu AND name = '%s';",
2060                      task, quoted_name);
2061               g_free (quoted_name);
2062               sql ("UPDATE tasks SET modification_time = m_now ()"
2063                    " WHERE id = %llu;",
2064                    task);
2065             }
2066         }
2067     }
2068   return 0;
2069 }
2070 
2071 
2072 /* Configs. */
2073 
2074 /**
2075  * @brief Find a config for a set of permissions, given a UUID.
2076  *
2077  * @param[in]   uuid        UUID of config.
2078  * @param[out]  config      Config return, 0 if successfully failed to find
2079  *                          config.
2080  * @param[in]   permission  Permission.
2081  *
2082  * @return FALSE on success (including if failed to find config), TRUE on error.
2083  */
2084 gboolean
find_config_with_permission(const char * uuid,config_t * config,const char * permission)2085 find_config_with_permission (const char* uuid, config_t* config,
2086                              const char *permission)
2087 {
2088   return find_resource_with_permission ("config", uuid, config, permission, 0);
2089 }
2090 
2091 /**
2092  * @brief Find a config given a UUID.
2093  *
2094  * This does not do any permission checks.
2095  *
2096  * @param[in]   uuid     UUID of resource.
2097  * @param[out]  config   Config return, 0 if no such config.
2098  *
2099  * @return FALSE on success (including if no such config), TRUE on error.
2100  */
2101 gboolean
find_config_no_acl(const char * uuid,config_t * config)2102 find_config_no_acl (const char *uuid, config_t *config)
2103 {
2104   gchar *quoted_uuid;
2105 
2106   quoted_uuid = sql_quote (uuid);
2107   switch (sql_int64 (config,
2108                      "SELECT id FROM configs WHERE uuid = '%s';",
2109                      quoted_uuid))
2110     {
2111       case 0:
2112         break;
2113       case 1:        /* Too few rows in result of query. */
2114         *config = 0;
2115         break;
2116       default:       /* Programming error. */
2117         assert (0);
2118       case -1:
2119         g_free (quoted_uuid);
2120         return TRUE;
2121         break;
2122     }
2123 
2124   g_free (quoted_uuid);
2125   return FALSE;
2126 }
2127 
2128 /**
2129  * @brief Find a trash config given a UUID.
2130  *
2131  * This does not do any permission checks.
2132  *
2133  * @param[in]   uuid     UUID of resource.
2134  * @param[out]  config   Config return, 0 if no such config.
2135  *
2136  * @return FALSE on success (including if no such config), TRUE on error.
2137  */
2138 gboolean
find_trash_config_no_acl(const char * uuid,config_t * config)2139 find_trash_config_no_acl (const char *uuid, config_t *config)
2140 {
2141   gchar *quoted_uuid;
2142 
2143   quoted_uuid = sql_quote (uuid);
2144   switch (sql_int64 (config,
2145                      "SELECT id FROM configs_trash WHERE uuid = '%s';",
2146                      quoted_uuid))
2147     {
2148       case 0:
2149         break;
2150       case 1:        /* Too few rows in result of query. */
2151         *config = 0;
2152         break;
2153       default:       /* Programming error. */
2154         assert (0);
2155       case -1:
2156         g_free (quoted_uuid);
2157         return TRUE;
2158         break;
2159     }
2160 
2161   g_free (quoted_uuid);
2162   return FALSE;
2163 }
2164 
2165 /**
2166  * @brief Gets an NVT preference by id or by name.
2167  *
2168  * Note: This currently only gets the fields needed by create_config.
2169  *
2170  * @param[in]  nvt_oid    OID of the NVT the preference belongs to.
2171  * @param[in]  find_id    Preference id to find, or NULL.
2172  * @param[in]  check_name Preference name to check.
2173  * @param[in]  check_type Preference name to check.
2174  * @param[in]  value      Value to assign to the preference.
2175  *
2176  * @return Newly allocated preference, freed with preference_free,
2177  *          or NULL (on error or if not found).
2178  */
2179 preference_t *
get_nvt_preference_by_id(const char * nvt_oid,const char * find_id,const char * check_name,const char * check_type,const char * value)2180 get_nvt_preference_by_id (const char *nvt_oid,
2181                           const char *find_id,
2182                           const char *check_name,
2183                           const char *check_type,
2184                           const char *value)
2185 {
2186   preference_t *new_pref;
2187   char *full_name, *id, *name, *type, *nvt_name, *default_value, *hr_name;
2188   array_t *alts;
2189   gchar *quoted_oid, *quoted_id;
2190 
2191   full_name = name = type = nvt_name = default_value = hr_name = NULL;
2192 
2193   /* Check parameters */
2194   if (nvt_oid == NULL)
2195     {
2196       g_warning ("%s: Missing nvt_oid", __func__);
2197       return NULL;
2198     }
2199   if (find_id == NULL || strcmp (find_id, "") == 0)
2200     {
2201       g_warning ("%s: Missing or empty find_id", __func__);
2202       return NULL;
2203     }
2204   if (value == NULL)
2205     {
2206       g_warning ("%s: Missing value", __func__);
2207       return NULL;
2208     }
2209 
2210   /* Try to get by id first */
2211   quoted_oid = sql_quote (nvt_oid);
2212   quoted_id = find_id ? sql_quote (find_id) : NULL;
2213 
2214   full_name = sql_string ("SELECT name FROM nvt_preferences"
2215                           " WHERE name LIKE '%s:%s:%%:%%'",
2216                           quoted_oid,
2217                           quoted_id);
2218 
2219   g_free (quoted_oid);
2220   g_free (quoted_id);
2221 
2222   if (full_name == NULL)
2223     {
2224       if (check_name == NULL || strcmp (check_name, "") == 0)
2225         {
2226           g_warning ("%s: Preference not found and given name is missing/empty",
2227                      __func__);
2228           return NULL;
2229         }
2230       if (check_type == NULL || strcmp (check_type, "") == 0)
2231         {
2232           g_warning ("%s: Preference not found and given name is missing/empty",
2233                      __func__);
2234           return NULL;
2235         }
2236       id = strdup (find_id);
2237       type = strdup (check_type);
2238       name = strdup (check_name);
2239     }
2240   else
2241     {
2242       char **full_name_split;
2243 
2244       /* Try to get components of the full name */
2245       full_name_split = g_strsplit (full_name, ":", 4);
2246 
2247       if (g_strv_length (full_name_split) != 4)
2248         {
2249           g_warning ("%s: Preference name %s does not have 4 parts",
2250                      __func__, full_name);
2251           g_strfreev (full_name_split);
2252           free (full_name);
2253           return NULL;
2254         }
2255       free (full_name);
2256 
2257       id = strdup (full_name_split[1]);
2258       type = strdup (full_name_split[2]);
2259       name = strdup (full_name_split[3]);
2260       g_strfreev (full_name_split);
2261 
2262       if (check_type && strcmp (check_type, "") && strcmp (check_type, type))
2263         g_warning ("%s: type of preference %s:%s (%s) has changed from %s to %s.",
2264                    __func__, nvt_oid, find_id, name, check_type, type);
2265 
2266       if (check_name && strcmp (check_name, "") && strcmp (check_name, name))
2267         g_message ("%s: name of preference %s:%s has changed from '%s' to '%s'.",
2268                    __func__, nvt_oid, find_id, check_name, name);
2269     }
2270 
2271   alts = make_array ();
2272   array_terminate (alts);
2273 
2274   new_pref = preference_new (id,
2275                              name,
2276                              type,
2277                              strdup (value),
2278                              nvt_name,
2279                              strdup (nvt_oid),
2280                              alts,
2281                              default_value,
2282                              hr_name,
2283                              1);
2284 
2285   return new_pref;
2286 }
2287 
2288 /**
2289  * @brief Insert preferences into a config.
2290  *
2291  * @param[in]  config       Config.
2292  * @param[in]  preferences  Preferences.
2293  * @param[in]  config_type  Config type.
2294  *
2295  * @return 0 success, -1 error, -4 input error.
2296  */
2297 static int
config_insert_preferences(config_t config,const array_t * preferences,const char * config_type)2298 config_insert_preferences (config_t config,
2299                            const array_t* preferences /* preference_t. */,
2300                            const char* config_type)
2301 {
2302   int index = 0;
2303   const preference_t *preference;
2304   if (preferences == NULL) return -4;
2305   while ((preference = (preference_t*) g_ptr_array_index (preferences, index++)))
2306     /* Simply skip the preference if the value is NULL, for exports
2307      * where sensitive information is left out. */
2308     if (preference->value)
2309       {
2310         GString *value;
2311         int alt_index = 0;
2312         const gchar *alt;
2313         gchar *quoted_value;
2314 
2315         if (preference->name == NULL) return -4;
2316         if (strcmp (preference->name, "Timeout") == 0)
2317           {
2318             gchar *quoted_nvt_oid;
2319 
2320             /* Special Timeout preference. */
2321 
2322             if (preference->nvt_oid == NULL
2323                 && (config_type == NULL || strcmp (config_type, "0") == 0))
2324               return -4;
2325 
2326             quoted_nvt_oid = sql_quote (preference->nvt_oid);
2327             quoted_value = sql_quote (preference->value);
2328 
2329             sql ("INSERT into config_preferences (config, type, name, value)"
2330                  " VALUES (%llu, 'SERVER_PREFS', 'timeout.%s', '%s');",
2331                  config,
2332                  quoted_nvt_oid,
2333                  quoted_value);
2334 
2335             g_free (quoted_nvt_oid);
2336             g_free (quoted_value);
2337           }
2338         else if (preference->type)
2339           {
2340             gchar *quoted_type, *quoted_nvt_oid, *quoted_preference_name;
2341             gchar *quoted_default, *quoted_preference_hr_name;
2342             gchar *quoted_preference_id;
2343 
2344             /* Presume NVT or OSP preference. */
2345 
2346             if (preference->nvt_oid == NULL
2347                 && (config_type == NULL || strcmp (config_type, "0") == 0))
2348               return -4;
2349 
2350             value = g_string_new (preference->value);
2351             while ((alt = (gchar*) g_ptr_array_index (preference->alts,
2352                                                       alt_index++)))
2353               {
2354                 g_string_append_printf (value, ";%s", alt);
2355               }
2356 
2357             quoted_nvt_oid = sql_quote (preference->nvt_oid ?: "");
2358             quoted_preference_id = sql_quote (preference->id ?: "");
2359             quoted_preference_name = sql_quote (preference->name);
2360             quoted_preference_hr_name
2361               = preference->hr_name
2362                   ? sql_quote (preference->hr_name)
2363                   : NULL;
2364             quoted_type
2365               = g_str_has_prefix (preference->type, "osp_")
2366                   ? sql_quote (preference->type + strlen ("osp_"))
2367                   : sql_quote (preference->type);
2368             quoted_value = sql_quote (value->str);
2369             g_string_free (value, TRUE);
2370             quoted_default = preference->default_value
2371                               ? sql_quote (preference->default_value)
2372                               : NULL;
2373 
2374             if (config_type == NULL || strcmp (config_type, "0") == 0)
2375               {
2376                 /* NVT preference */
2377                 /* OID:PrefID:PrefType:PrefName value */
2378                 sql ("INSERT INTO config_preferences"
2379                      " (config, type, name, value)"
2380                      " VALUES (%llu, 'PLUGINS_PREFS', '%s:%s:%s:%s', '%s');",
2381                      config,
2382                      quoted_nvt_oid,
2383                      quoted_preference_id,
2384                      quoted_type,
2385                      quoted_preference_name,
2386                      quoted_value);
2387               }
2388             else
2389               {
2390                 /* OSP preference */
2391                 sql ("INSERT into config_preferences"
2392                      " (config, type, name, value, default_value, hr_name)"
2393                      " VALUES (%llu, '%s', '%s', '%s', '%s', '%s');",
2394                      config,
2395                      quoted_type,
2396                      quoted_preference_name,
2397                      quoted_value,
2398                      quoted_default,
2399                      quoted_preference_hr_name
2400                       ? quoted_preference_name : quoted_preference_hr_name);
2401               }
2402             g_free (quoted_nvt_oid);
2403             g_free (quoted_preference_name);
2404             g_free (quoted_type);
2405             g_free (quoted_value);
2406             g_free (quoted_default);
2407             g_free (quoted_preference_hr_name);
2408             g_free (quoted_preference_id);
2409           }
2410         else
2411           {
2412             gchar *quoted_name;
2413 
2414             /* Presume scanner preference. */
2415 
2416             quoted_name = sql_quote (preference->name);
2417             quoted_value = sql_quote (preference->value);
2418             sql ("INSERT into config_preferences (config, type, name, value)"
2419                  " VALUES (%llu, 'SERVER_PREFS', '%s', '%s');",
2420                  config,
2421                  quoted_name,
2422                  quoted_value);
2423             g_free (quoted_name);
2424             g_free (quoted_value);
2425           }
2426       }
2427   return 0;
2428 }
2429 
2430 /**
2431  * @brief Create a config.
2432  *
2433  * If a config with the same name exists already then add a unique integer
2434  * suffix onto the name.
2435  *
2436  * @param[in]   check_access   Whether to check for create_config permission.
2437  * @param[in]   config_id      ID if one is required, else NULL.
2438  * @param[in]   proposed_name  Proposed name of config.
2439  * @param[in]   make_name_unique  Whether to make name unique.
2440  * @param[in]   comment        Comment on config.
2441  * @param[in]   all_selector   Whether to use "all" selector instead of selectors.
2442  * @param[in]   selectors      NVT selectors.
2443  * @param[in]   preferences    Preferences.
2444  * @param[in]   config_type    Config type.
2445  * @param[in]   usage_type     The usage type ("scan" or "policy")
2446  * @param[in]   allow_errors   Whether certain errors are allowed.
2447  * @param[in]   predefined     Whether config is predefined.
2448  * @param[out]  config         On success the config.
2449  * @param[out]  name           On success the name of the config.
2450  *
2451  * @return 0 success, 1 config exists already, 99 permission denied, -1 error,
2452  *         -2 name empty, -3 input error in selectors, -4 input error in
2453  *         preferences, -5 error in config_id.
2454  */
2455 static int
create_config_internal(int check_access,const char * config_id,const char * proposed_name,int make_name_unique,const char * comment,int all_selector,const array_t * selectors,const array_t * preferences,const char * config_type,const char * usage_type,int allow_errors,int predefined,config_t * config,char ** name)2456 create_config_internal (int check_access, const char *config_id,
2457                         const char *proposed_name,
2458                         int make_name_unique, const char *comment,
2459                         int all_selector,
2460                         const array_t *selectors /* nvt_selector_t. */,
2461                         const array_t *preferences /* preference_t. */,
2462                         const char *config_type, const char *usage_type,
2463                         int allow_errors, int predefined, config_t *config,
2464                         char **name)
2465 {
2466   int ret;
2467   gchar *quoted_comment, *candidate_name, *quoted_candidate_name;
2468   gchar *quoted_type;
2469   const char *actual_usage_type;
2470   char *selector_uuid;
2471   unsigned int num = 1;
2472 
2473   assert (current_credentials.uuid);
2474 
2475   if (config_id
2476       && (g_regex_match_simple ("^[-0123456789abcdef]{36}$",
2477                                 config_id, 0, 0)
2478           == FALSE))
2479     return -5;
2480 
2481   if (proposed_name == NULL || strlen (proposed_name) == 0) return -2;
2482 
2483   if (all_selector)
2484     selector_uuid = NULL;
2485   else
2486     {
2487       selector_uuid = gvm_uuid_make ();
2488       if (selector_uuid == NULL)
2489         return -1;
2490     }
2491 
2492   sql_begin_immediate ();
2493 
2494   if (check_access && (acl_user_may ("create_config") == 0))
2495     {
2496       sql_rollback ();
2497       free (selector_uuid);
2498       return 99;
2499     }
2500 
2501   candidate_name = g_strdup (proposed_name);
2502   quoted_candidate_name = sql_quote (candidate_name);
2503   quoted_type = config_type ? sql_quote (config_type) : g_strdup ("0");
2504   if (usage_type && strcasecmp (usage_type, "policy") == 0)
2505     actual_usage_type = "policy";
2506   else
2507     actual_usage_type = "scan";
2508 
2509   while (make_name_unique)
2510     {
2511       if (!resource_with_name_exists (quoted_candidate_name, "config", 0))
2512         break;
2513       g_free (candidate_name);
2514       g_free (quoted_candidate_name);
2515       candidate_name = g_strdup_printf ("%s %u", proposed_name, ++num);
2516       quoted_candidate_name = sql_quote (candidate_name);
2517     }
2518 
2519   if (comment)
2520     {
2521       quoted_comment = sql_nquote (comment, strlen (comment));
2522       sql ("INSERT INTO configs (uuid, name, owner, nvt_selector, comment,"
2523            " type, creation_time, modification_time, usage_type, predefined)"
2524            " VALUES (%s%s%s, '%s',"
2525            " (SELECT id FROM users WHERE users.uuid = '%s'),"
2526            " '%s', '%s', '%s', m_now (), m_now (), '%s', %i);",
2527            config_id ? "'" : "",
2528            config_id ? config_id : "make_uuid ()",
2529            config_id ? "'" : "",
2530            quoted_candidate_name,
2531            current_credentials.uuid,
2532            selector_uuid ? selector_uuid : MANAGE_NVT_SELECTOR_UUID_ALL,
2533            quoted_comment,
2534            quoted_type,
2535            actual_usage_type,
2536            predefined);
2537       g_free (quoted_comment);
2538     }
2539   else
2540     sql ("INSERT INTO configs (uuid, name, owner, nvt_selector, comment,"
2541          " type, creation_time, modification_time, usage_type, predefined)"
2542          " VALUES (%s%s%s, '%s',"
2543          " (SELECT id FROM users WHERE users.uuid = '%s'),"
2544          " '%s', '', '%s', m_now (), m_now (), '%s', %i);",
2545          config_id ? "'" : "",
2546          config_id ? config_id : "make_uuid ()",
2547          config_id ? "'" : "",
2548          quoted_candidate_name,
2549          current_credentials.uuid,
2550          selector_uuid ? selector_uuid : MANAGE_NVT_SELECTOR_UUID_ALL,
2551          quoted_type,
2552          actual_usage_type,
2553          predefined);
2554   g_free (quoted_candidate_name);
2555   g_free (quoted_type);
2556 
2557   /* Insert the selectors into the nvt_selectors table. */
2558 
2559   *config = sql_last_insert_id ();
2560 
2561   if (selector_uuid && (config_type == NULL || strcmp (config_type, "0") == 0))
2562     {
2563       if ((ret = insert_nvt_selectors (selector_uuid, selectors, allow_errors)))
2564         {
2565           sql_rollback ();
2566           free (selector_uuid);
2567           return ret;
2568         }
2569     }
2570   free (selector_uuid);
2571 
2572   /* Insert the preferences into the config_preferences table. */
2573 
2574   if ((ret = config_insert_preferences (*config, preferences, config_type)))
2575     {
2576       sql_rollback ();
2577       return ret;
2578     }
2579 
2580   /* Update family and NVT count caches. */
2581 
2582   update_config_caches (*config);
2583 
2584   sql_commit ();
2585   *name = candidate_name;
2586   return 0;
2587 }
2588 
2589 /**
2590  * @brief Create a config.
2591  *
2592  * If a config with the same name exists already then add a unique integer
2593  * suffix onto the name.
2594  *
2595  * @param[in]   config_id      ID if one is required, else NULL.
2596  * @param[in]   proposed_name  Proposed name of config.
2597  * @param[in]   make_name_unique  Whether to make name unique.
2598  * @param[in]   comment        Comment on config.
2599  * @param[in]   all_selector   Whether to use "all" selector instead of selectors.
2600  * @param[in]   selectors      NVT selectors.
2601  * @param[in]   preferences    Preferences.
2602  * @param[in]   config_type    Config type.
2603  * @param[in]   usage_type     The usage type ("scan" or "policy")
2604  * @param[out]  config         On success the config.
2605  * @param[out]  name           On success the name of the config.
2606  *
2607  * @return 0 success, 1 config exists already, 99 permission denied, -1 error,
2608  *         -2 name empty, -3 input error in selectors, -4 input error in
2609  *         preferences, -5 error in config_id.
2610  */
2611 int
create_config(const char * config_id,const char * proposed_name,int make_name_unique,const char * comment,int all_selector,const array_t * selectors,const array_t * preferences,const char * config_type,const char * usage_type,config_t * config,char ** name)2612 create_config (const char *config_id, const char *proposed_name,
2613                int make_name_unique, const char *comment, int all_selector,
2614                const array_t *selectors /* nvt_selector_t. */,
2615                const array_t *preferences /* preference_t. */,
2616                const char *config_type, const char *usage_type,
2617                config_t *config, char **name)
2618 {
2619   return create_config_internal (1, config_id, proposed_name, make_name_unique,
2620                                  comment, all_selector, selectors, preferences,
2621                                  config_type, usage_type, 1,
2622                                  0, /* Predefined. */
2623                                  config, name);
2624 }
2625 
2626 /**
2627  * @brief Create a config.
2628  *
2629  * If a config with the same name exists already then add a unique integer
2630  * suffix onto the name.
2631  *
2632  * @param[in]   config_id      ID if one is required, else NULL.
2633  * @param[in]   proposed_name  Proposed name of config.
2634  * @param[in]   make_name_unique  Whether to make name unique.
2635  * @param[in]   comment        Comment on config.
2636  * @param[in]   all_selector   Whether to use "all" selector instead of selectors.
2637  * @param[in]   selectors      NVT selectors.
2638  * @param[in]   preferences    Preferences.
2639  * @param[in]   config_type    Config type.
2640  * @param[in]   usage_type     The usage type ("scan" or "policy")
2641  * @param[out]  config         On success the config.
2642  * @param[out]  name           On success the name of the config.
2643  *
2644  * @return 0 success, 1 config exists already, 99 permission denied, -1 error,
2645  *         -2 name empty, -3 input error in selectors, -4 input error in
2646  *         preferences, -5 error in config_id.
2647  */
2648 int
create_config_no_acl(const char * config_id,const char * proposed_name,int make_name_unique,const char * comment,int all_selector,const array_t * selectors,const array_t * preferences,const char * config_type,const char * usage_type,config_t * config,char ** name)2649 create_config_no_acl (const char *config_id, const char *proposed_name,
2650                       int make_name_unique, const char *comment,
2651                       int all_selector,
2652                       const array_t *selectors /* nvt_selector_t. */,
2653                       const array_t *preferences /* preference_t. */,
2654                       const char *config_type, const char *usage_type,
2655                       config_t *config, char **name)
2656 {
2657   return create_config_internal (0, config_id, proposed_name, make_name_unique,
2658                                  comment, all_selector, selectors, preferences,
2659                                  config_type, usage_type, 0,
2660                                  1, /* Predefined. */
2661                                  config, name);
2662 }
2663 
2664 /**
2665  * @brief Get list of OSP Scanner parameters.
2666  *
2667  * @param[in]   scanner    Scanner.
2668  *
2669  * @return List of scanner parameters, NULL if error.
2670  */
2671 static GSList *
get_scanner_params(scanner_t scanner)2672 get_scanner_params (scanner_t scanner)
2673 {
2674   GSList *list = NULL;
2675   osp_connection_t *connection;
2676 
2677   connection = osp_scanner_connect (scanner);
2678   if (!connection)
2679     return NULL;
2680 
2681   osp_get_scanner_details (connection, NULL, &list);
2682   osp_connection_close (connection);
2683   return list;
2684 }
2685 
2686 /**
2687  * @brief Insert an OSP parameter into a config if not already present.
2688  *
2689  * @param[in]   param   OSP parameter to insert.
2690  * @param[in]   config  Config to insert parameter into.
2691  *
2692  * @return 1 if added, 0 otherwise.
2693  */
2694 static int
insert_osp_parameter(osp_param_t * param,config_t config)2695 insert_osp_parameter (osp_param_t *param, config_t config)
2696 {
2697   char *param_id, *param_name, *param_type, *param_def, *param_value = NULL;
2698   int ret = 0;
2699 
2700   if (!param)
2701     return ret;
2702   param_id = sql_quote (osp_param_id (param));
2703   param_name = sql_quote (osp_param_name (param));
2704   param_type = sql_quote (osp_param_type_str (param));
2705   if (!strcmp (param_type, "selection"))
2706     {
2707       char **strarray = g_strsplit (osp_param_default (param), "|", 2);
2708 
2709       param_value = sql_quote (strarray[0] ?: "");
2710       param_def = sql_quote (strarray[1] ?: param_value);
2711       g_strfreev (strarray);
2712     }
2713   else
2714     param_def = sql_quote (osp_param_default (param));
2715   if (sql_int ("SELECT count(*) FROM config_preferences"
2716                " WHERE config = %llu AND name = '%s' AND type = '%s'"
2717                " AND default_value = '%s';",
2718                config, param_id, param_type, param_def) == 0)
2719     {
2720       sql ("INSERT INTO config_preferences (config, name, type, value,"
2721            " default_value, hr_name)"
2722            " VALUES (%llu, '%s', '%s', '%s', '%s', '%s')",
2723            config , param_id, param_type, param_value ?: param_def,
2724            param_def, param_name);
2725       ret = 1;
2726     }
2727   g_free (param_name);
2728   g_free (param_id);
2729   g_free (param_type);
2730   g_free (param_def);
2731   g_free (param_value);
2732   return ret;
2733 }
2734 
2735 /**
2736  * @brief  Generate an extra WHERE clause for selecting configs
2737  *
2738  * @param[in]  usage_type   The usage type to limit the selection to.
2739  *
2740  * @return Newly allocated where clause string.
2741  */
2742 gchar *
configs_extra_where(const char * usage_type)2743 configs_extra_where (const char *usage_type)
2744 {
2745   gchar *extra_where = NULL;
2746   if (usage_type && strcmp (usage_type, ""))
2747     {
2748       gchar *quoted_usage_type;
2749       quoted_usage_type = sql_quote (usage_type);
2750       extra_where = g_strdup_printf (" AND usage_type = '%s'",
2751                                      quoted_usage_type);
2752       g_free (quoted_usage_type);
2753     }
2754   return extra_where;
2755 }
2756 
2757 /**
2758  * @brief Create a config from an OSP scanner.
2759  *
2760  * @param[in]   scanner_id  UUID of scanner to create config from.
2761  * @param[in]   name        Name for config.
2762  * @param[in]   comment     Comment for config.
2763  * @param[in]   usage_type  The usage type ("scan" or "policy")
2764  * @param[out]  uuid        Config UUID, on success.
2765  *
2766  * @return 0 success, 1 couldn't find scanner, 2 scanner not of OSP type,
2767  *         3 config name exists already, 4 couldn't get params from scanner,
2768  *         99 permission denied, -1 error.
2769  */
2770 int
create_config_from_scanner(const char * scanner_id,const char * name,const char * comment,const char * usage_type,char ** uuid)2771 create_config_from_scanner (const char *scanner_id, const char *name,
2772                             const char *comment, const char *usage_type,
2773                             char **uuid)
2774 {
2775   scanner_t scanner;
2776   config_t config;
2777   GSList *params, *element;
2778   char *quoted_name, *quoted_comment;
2779   const char *actual_usage_type;
2780 
2781   assert (current_credentials.uuid);
2782   assert (scanner_id);
2783   sql_begin_immediate ();
2784 
2785   if (acl_user_may ("create_config") == 0)
2786     {
2787       sql_rollback ();
2788       return 99;
2789     }
2790   if (find_scanner_with_permission (scanner_id, &scanner, "get_scanners"))
2791     {
2792       sql_rollback ();
2793       return -1;
2794     }
2795   if (scanner == 0)
2796     {
2797       sql_rollback ();
2798       return 1;
2799     }
2800   if (scanner_type (scanner) != SCANNER_TYPE_OSP)
2801     {
2802       sql_rollback ();
2803       return 2;
2804     }
2805   if (resource_with_name_exists (name, "config", 0))
2806     {
2807       sql_rollback ();
2808       return 3;
2809     }
2810 
2811   params = get_scanner_params (scanner);
2812   if (!params)
2813     {
2814       sql_rollback ();
2815       return 4;
2816     }
2817   quoted_name = sql_quote (name ?: "");
2818   quoted_comment = sql_quote (comment ?: "");
2819   if (usage_type && strcasecmp (usage_type, "policy") == 0)
2820     actual_usage_type = "policy";
2821   else
2822     actual_usage_type = "scan";
2823 
2824   /* Create new OSP config. */
2825   sql ("INSERT INTO configs (uuid, name, owner, nvt_selector, comment,"
2826        " type, scanner, creation_time, modification_time, usage_type)"
2827        " VALUES (make_uuid (), '%s',"
2828        " (SELECT id FROM users WHERE users.uuid = '%s'),"
2829        " '', '%s', 1, %llu, m_now (), m_now (), '%s');",
2830        quoted_name, current_credentials.uuid, quoted_comment, scanner,
2831        actual_usage_type);
2832   g_free (quoted_name);
2833   g_free (quoted_comment);
2834   config = sql_last_insert_id ();
2835   *uuid = config_uuid (config);
2836 
2837   element = params;
2838   while (element)
2839     {
2840       insert_osp_parameter (element->data, config);
2841       osp_param_free (element->data);
2842       element = element->next;
2843     }
2844   g_slist_free (params);
2845   sql_commit ();
2846   return 0;
2847 }
2848 
2849 /**
2850  * @brief Return the UUID of a config.
2851  *
2852  * @param[in]   config  Config.
2853  *
2854  * @return Newly allocated config uuid pointer.
2855  */
2856 char *
config_uuid(config_t config)2857 config_uuid (config_t config)
2858 {
2859   return sql_string ("SELECT uuid FROM configs WHERE id = %llu;", config);
2860 }
2861 
2862 /**
2863  * @brief Return the type of a config.
2864  *
2865  * @param[in]  config  Config.
2866  *
2867  * @return Config type, -1 if not found.
2868  */
2869 int
config_type(config_t config)2870 config_type (config_t config)
2871 {
2872   int type;
2873   char *str;
2874   str = sql_string ("SELECT type FROM configs WHERE id = %llu;", config);
2875   if (!str)
2876     return -1;
2877   type = atoi (str);
2878   g_free (str);
2879   return type;
2880 }
2881 
2882 /**
2883  * @brief Return the scanner associated with a config, if any.
2884  *
2885  * @param[in]  config   Config.
2886  *
2887  * @return Scanner ID if found, 0 otherwise.
2888  */
2889 static scanner_t
config_scanner(config_t config)2890 config_scanner (config_t config)
2891 {
2892   scanner_t scanner;
2893 
2894   switch (sql_int64 (&scanner,
2895                      "SELECT scanner FROM configs WHERE id = %llu;", config))
2896     {
2897       case 0:
2898         break;
2899       case 1:        /* Too few rows in result of query. */
2900         return 0;
2901       case -1:
2902         return 0;
2903       default:       /* Programming error. */
2904         assert (0);
2905     }
2906   return scanner;
2907 }
2908 
2909 /**
2910  * @brief Return whether a config is predefined.
2911  *
2912  * @param[in]  config  Config.
2913  *
2914  * @return 1 if predefined, else 0.
2915  */
2916 int
config_predefined(config_t config)2917 config_predefined (config_t config)
2918 {
2919   return sql_int ("SELECT predefined FROM configs"
2920                   " WHERE id = %llu;",
2921                   config);
2922 }
2923 
2924 /**
2925  * @brief Return whether a trash config is predefined.
2926  *
2927  * @param[in]  config  Config.
2928  *
2929  * @return 1 if predefined, else 0.
2930  */
2931 int
trash_config_predefined(config_t config)2932 trash_config_predefined (config_t config)
2933 {
2934   return sql_int ("SELECT predefined FROM configs_trash"
2935                   " WHERE id = %llu;",
2936                   config);
2937 }
2938 
2939 /**
2940  * @brief Get the timeout value for an NVT in a config.
2941  *
2942  * @param[in]  config  Config.
2943  * @param[in]  oid     ID of NVT.
2944  *
2945  * @return Newly allocated timeout if set for the NVT, else NULL.
2946  */
2947 char *
config_nvt_timeout(config_t config,const char * oid)2948 config_nvt_timeout (config_t config, const char *oid)
2949 {
2950   return sql_string ("SELECT value FROM config_preferences"
2951                      " WHERE config = %llu"
2952                      " AND type = 'SERVER_PREFS'"
2953                      " AND name = 'timeout.%s';",
2954                      config,
2955                      oid);
2956 }
2957 
2958 /**
2959  * @brief Check scanner and config values match for a task.
2960  *
2961  * @param[in]  config       Scan Config.
2962  * @param[in]  scanner      Scanner.
2963  *
2964  * @return 1 if config and scanner types match, 0 otherwise.
2965  */
2966 int
create_task_check_config_scanner(config_t config,scanner_t scanner)2967 create_task_check_config_scanner (config_t config, scanner_t scanner)
2968 {
2969   int ctype, stype;
2970 
2971   assert (config);
2972   assert (scanner);
2973 
2974   ctype = config_type (config);
2975   stype = scanner_type (scanner);
2976 
2977   if (ctype == 0 && stype == SCANNER_TYPE_OPENVAS)
2978     return 1;
2979   if (ctype == 0 && stype == SCANNER_TYPE_OSP_SENSOR)
2980     return 1;
2981   if (ctype == 1 && stype == SCANNER_TYPE_OSP)
2982     return 1;
2983 
2984   return 0;
2985 }
2986 
2987 /**
2988  * @brief Check scanner and config values match for a task.
2989  *
2990  * @param[in]  task         Task.
2991  * @param[in]  config_id    ID of config. "0" to use task's config.
2992  * @param[in]  scanner_id   ID of scanner.
2993  *
2994  * @return 0 if config and scanner types match, 1 do not match, 2 failed to
2995  *         find config, 3 failed to find scanner, -1 error.
2996  */
2997 int
modify_task_check_config_scanner(task_t task,const char * config_id,const char * scanner_id)2998 modify_task_check_config_scanner (task_t task, const char *config_id,
2999                                   const char *scanner_id)
3000 {
3001   config_t config = 0;
3002   scanner_t scanner = 0;
3003   int ctype, stype;
3004 
3005   if (config_id == NULL)
3006     config_id = "0";
3007   if (scanner_id == NULL)
3008     scanner_id = "0";
3009 
3010   if (!strcmp (config_id, "0") && !strcmp (scanner_id, "0"))
3011     return 0;
3012 
3013   if (strcmp (config_id, "0"))
3014     {
3015       if (find_config_with_permission (config_id, &config, "get_configs"))
3016         return -1;
3017       if (config == 0)
3018         return 2;
3019     }
3020   else
3021     config = task_config (task);
3022 
3023   if (strcmp (scanner_id, "0"))
3024     {
3025       if (find_scanner_with_permission (scanner_id, &scanner, "get_scanners"))
3026         return -1;
3027       if (scanner == 0)
3028         return 3;
3029     }
3030   else
3031     scanner = task_scanner (task);
3032 
3033   stype = scanner_type (scanner);
3034 
3035   /* CVE Scanner. */
3036   if (stype == SCANNER_TYPE_CVE)
3037     return strcmp (scanner_id, "0")
3038             /* Selecting the CVE Scanner will clear the config. */
3039             ? 0
3040             /* CVE Scanner is currently selected, so the only option is to
3041              * leave the config alone. */
3042             : (config ? 1 : 0);
3043 
3044   ctype = config_type (config);
3045   /* OSP Scanner with OSP config. */
3046   if (stype == SCANNER_TYPE_OSP && ctype == 1)
3047     return 0;
3048 
3049   /* OpenVAS Scanner with OpenVAS config. */
3050   if ((stype == SCANNER_TYPE_OPENVAS)
3051       && ctype == 0)
3052     return 0;
3053 
3054   /* OSP Sensor with OpenVAS config. */
3055   if (stype == SCANNER_TYPE_OSP_SENSOR && ctype == 0)
3056     return 0;
3057 
3058   /* Default Scanner with OpenVAS Config. */
3059   if (scanner == 0 && ctype == 0)
3060     return 0;
3061 
3062   return 1;
3063 }
3064 
3065 /**
3066  * @brief Create a config from an existing config.
3067  *
3068  * @param[in]  name        Name of new config and NVT selector.
3069  * @param[in]  comment     Comment on new config.
3070  * @param[in]  config_id   UUID of existing config.
3071  * @param[in]  usage_type  Optional new usage type for the new config.
3072  * @param[out] new_config  New config.
3073  *
3074  * @return 0 success, 1 config exists already, 2 failed to find existing
3075  *         config, 99 permission denied, -1 error.
3076  */
3077 int
copy_config(const char * name,const char * comment,const char * config_id,const char * usage_type,config_t * new_config)3078 copy_config (const char* name, const char* comment, const char *config_id,
3079              const char* usage_type, config_t* new_config)
3080 {
3081   int ret, type;
3082   char *config_selector;
3083   gchar *quoted_config_selector;
3084   config_t new, old;
3085 
3086   assert (current_credentials.uuid);
3087 
3088   sql_begin_immediate ();
3089 
3090   /* Copy the existing config. */
3091 
3092   ret = copy_resource_lock ("config", name, comment, config_id,
3093                             " family_count, nvt_count, families_growing,"
3094                             " nvts_growing, type, scanner, usage_type",
3095                             1, &new, &old);
3096   if (ret)
3097     {
3098       sql_rollback ();
3099       return ret;
3100     }
3101 
3102   sql ("UPDATE configs SET predefined = 0 WHERE id = %llu;", new);
3103 
3104   sql ("INSERT INTO config_preferences (config, type, name, value,"
3105        "                                default_value, hr_name)"
3106        " SELECT %llu, type, name, value, default_value, hr_name"
3107        " FROM config_preferences"
3108        " WHERE config = %llu;", new, old);
3109 
3110   type = config_type (new);
3111   if (type > 0)
3112     {
3113       /* Don't create nvt_selector etc,. for non-standard configs
3114        * (eg. OSP config.) Only config preferences are copied.
3115        */
3116       sql_commit ();
3117       if (new_config) *new_config = new;
3118       return 0;
3119     }
3120 
3121   sql ("UPDATE configs SET nvt_selector = make_uuid () WHERE id = %llu;",
3122        new);
3123 
3124   if (usage_type && strcmp (usage_type, ""))
3125     {
3126       const char *actual_usage_type;
3127 
3128       if (strcasecmp (usage_type, "policy") == 0)
3129         actual_usage_type = "policy";
3130       else
3131         actual_usage_type = "scan";
3132 
3133       sql ("UPDATE configs SET usage_type = '%s' WHERE id = %llu;",
3134            actual_usage_type,
3135            new);
3136     }
3137 
3138   config_selector = config_nvt_selector (old);
3139   if (config_selector == NULL)
3140     {
3141       sql_rollback ();
3142       return -1;
3143     }
3144   quoted_config_selector = sql_quote (config_selector);
3145   free (config_selector);
3146 
3147   sql ("INSERT INTO nvt_selectors (name, exclude, type, family_or_nvt, family)"
3148        " SELECT (SELECT nvt_selector FROM configs WHERE id = %llu),"
3149        "        exclude, type, family_or_nvt, family"
3150        " FROM nvt_selectors"
3151        " WHERE name = '%s';",
3152        new,
3153        quoted_config_selector);
3154   g_free (quoted_config_selector);
3155 
3156   sql_commit ();
3157   if (new_config) *new_config = new;
3158   return 0;
3159 }
3160 
3161 /**
3162  * @brief Delete a config.
3163  *
3164  * @param[in]  config_id  UUID of config.
3165  * @param[in]  ultimate   Whether to remove entirely, or to trashcan.
3166  *
3167  * @return 0 success, 1 fail because a task refers to the config, 2 failed to
3168  *         find config, 99 permission denied, -1 error.
3169  */
3170 int
delete_config(const char * config_id,int ultimate)3171 delete_config (const char *config_id, int ultimate)
3172 {
3173   config_t config = 0;
3174 
3175   sql_begin_immediate ();
3176 
3177   if (acl_user_may ("delete_config") == 0)
3178     {
3179       sql_rollback ();
3180       return 99;
3181     }
3182 
3183   if (find_config_with_permission (config_id, &config, "delete_config"))
3184     {
3185       sql_rollback ();
3186       return -1;
3187     }
3188 
3189   if (config == 0)
3190     {
3191       if (find_trash ("config", config_id, &config))
3192         {
3193           sql_rollback ();
3194           return -1;
3195         }
3196       if (config == 0)
3197         {
3198           sql_rollback ();
3199           return 2;
3200         }
3201       if (ultimate == 0)
3202         {
3203           /* It's already in the trashcan. */
3204           sql_commit ();
3205           return 0;
3206         }
3207 
3208       /* Check if it's in use by a task in the trashcan. */
3209       if (sql_int ("SELECT count(*) FROM tasks"
3210                    " WHERE config = %llu"
3211                    " AND config_location = " G_STRINGIFY (LOCATION_TRASH) ";",
3212                    config))
3213         {
3214           sql_rollback ();
3215           return 1;
3216         }
3217 
3218       permissions_set_orphans ("config", config, LOCATION_TRASH);
3219       tags_remove_resource ("config", config, LOCATION_TRASH);
3220 
3221       sql ("DELETE FROM nvt_selectors"
3222            " WHERE name != '" MANAGE_NVT_SELECTOR_UUID_ALL "'"
3223            " AND name = (SELECT nvt_selector FROM configs_trash"
3224            "             WHERE id = %llu);",
3225            config);
3226       sql ("DELETE FROM config_preferences_trash WHERE config = %llu;",
3227            config);
3228       sql ("DELETE FROM configs_trash WHERE id = %llu;",
3229            config);
3230       sql_commit ();
3231       return 0;
3232     }
3233 
3234   if (ultimate)
3235     {
3236       if (sql_int ("SELECT count(*) FROM tasks"
3237                    " WHERE config = %llu"
3238                    " AND config_location = " G_STRINGIFY (LOCATION_TABLE),
3239                    config))
3240         {
3241           sql_rollback ();
3242           return 1;
3243         }
3244 
3245       sql ("DELETE FROM nvt_selectors"
3246            " WHERE name != '" MANAGE_NVT_SELECTOR_UUID_ALL "'"
3247            " AND name = (SELECT nvt_selector FROM configs_trash"
3248            "             WHERE id = %llu);",
3249            config);
3250 
3251       permissions_set_orphans ("config", config, LOCATION_TABLE);
3252       tags_remove_resource ("config", config, LOCATION_TABLE);
3253     }
3254   else
3255     {
3256       config_t trash_config;
3257 
3258       if (sql_int ("SELECT count(*) FROM tasks"
3259                    " WHERE config = %llu"
3260                    " AND config_location = " G_STRINGIFY (LOCATION_TABLE)
3261                    " AND hidden = 0;",
3262                    config))
3263         {
3264           sql_rollback ();
3265           return 1;
3266         }
3267 
3268       sql ("INSERT INTO configs_trash"
3269            " (uuid, owner, name, nvt_selector, comment, family_count,"
3270            "  nvt_count, families_growing, nvts_growing, type, scanner,"
3271            "  predefined, creation_time, modification_time,"
3272            "  scanner_location, usage_type)"
3273            " SELECT uuid, owner, name, nvt_selector, comment, family_count,"
3274            "        nvt_count, families_growing, nvts_growing, type, scanner,"
3275            "        predefined, creation_time, modification_time,"
3276            "        " G_STRINGIFY (LOCATION_TABLE) ", usage_type"
3277            " FROM configs WHERE id = %llu;",
3278            config);
3279 
3280       trash_config = sql_last_insert_id ();
3281 
3282       sql ("INSERT INTO config_preferences_trash"
3283            " (config, type, name, value, default_value, hr_name)"
3284            " SELECT %llu, type, name, value, default_value, hr_name"
3285            " FROM config_preferences WHERE config = %llu;",
3286            trash_config,
3287            config);
3288 
3289       /* Update the location of the config in any trashcan tasks. */
3290       sql ("UPDATE tasks"
3291            " SET config = %llu,"
3292            "     config_location = " G_STRINGIFY (LOCATION_TRASH)
3293            " WHERE config = %llu"
3294            " AND config_location = " G_STRINGIFY (LOCATION_TABLE) ";",
3295            trash_config,
3296            config);
3297 
3298       permissions_set_locations ("config", config, trash_config,
3299                                  LOCATION_TRASH);
3300       tags_set_locations ("config", config, trash_config,
3301                           LOCATION_TRASH);
3302     }
3303 
3304   sql ("DELETE FROM config_preferences WHERE config = %llu;", config);
3305   sql ("DELETE FROM configs WHERE id = %llu;", config);
3306 
3307   sql_commit ();
3308   return 0;
3309 }
3310 
3311 /**
3312  * @brief Update a config with a list of parameters.
3313  *
3314  * @param[in]  config       Config ID.
3315  * @param[in]  config_id    Config UUID.
3316  * @param[in]  params       List of new config parameters.
3317  *
3318  */
3319 static void
update_config_params(config_t config,const char * config_id,GSList * params)3320 update_config_params (config_t config, const char *config_id, GSList *params)
3321 {
3322   GSList *element;
3323   iterator_t iterator;
3324 
3325   /* Remove parameters not used anymore. */
3326   init_iterator (&iterator,
3327                  "SELECT id, name, type, default_value, hr_name"
3328                  " FROM config_preferences"
3329                  " WHERE config = %llu;", config);
3330   while (next (&iterator))
3331     {
3332       int found = 0;
3333 
3334       element = params;
3335       while (element)
3336         {
3337           const char *name, *type, *def;
3338 
3339           name = osp_param_id (element->data);
3340           type = osp_param_type_str (element->data);
3341           def = osp_param_default (element->data);
3342           if (!strcmp (name,  iterator_string (&iterator, 1))
3343               && !strcmp (type, iterator_string (&iterator, 2)))
3344             {
3345               const char *iter_def = iterator_string (&iterator, 3);
3346 
3347               if (!strcmp (type, "selection")
3348                   && !strcmp (strchr (def, '|') + 1, iter_def))
3349                 found = 1;
3350               else if (strcmp (type, "selection") && !strcmp (def, iter_def))
3351                 found = 1;
3352               if (found)
3353                 break;
3354             }
3355           element = element->next;
3356         }
3357       if (!found)
3358         {
3359           g_message ("Removing config preference %s from config '%s'",
3360                      iterator_string (&iterator, 1), config_id);
3361           sql ("DELETE FROM config_preferences WHERE id = %llu;",
3362                iterator_int64 (&iterator, 0));
3363         }
3364       else if (strcmp (osp_param_name (element->data),
3365                        iterator_string (&iterator, 4)))
3366         {
3367           // Update hr_name (= OSP name)
3368           gchar *quoted_name;
3369           quoted_name = sql_quote (osp_param_name (element->data));
3370           g_message ("Updating name of config preference %s in config '%s'",
3371                      iterator_string (&iterator, 1), config_id);
3372           sql ("UPDATE config_preferences SET hr_name='%s' WHERE id = %llu;",
3373                quoted_name,
3374                iterator_int64 (&iterator, 0));
3375           g_free (quoted_name);
3376         }
3377     }
3378   cleanup_iterator (&iterator);
3379   /* Insert new parameters. */
3380   element = params;
3381   while (element)
3382     {
3383       if (insert_osp_parameter (element->data, config))
3384         g_message ("Adding config preference %s to config '%s'",
3385                    osp_param_id (element->data), config_id);
3386       element = element->next;
3387     }
3388 }
3389 
3390 /**
3391  * @brief Synchronize a config.
3392  *
3393  * @param[in]  config_id  UUID of config.
3394  *
3395  * @return 0 success, 1 failed to find config, 2 config not of OSP type,
3396  *         3 config has no scanner, 4 couldn't get params from scanner,
3397  *         99 permission denied, -1 error.
3398  */
3399 int
sync_config(const char * config_id)3400 sync_config (const char *config_id)
3401 {
3402   config_t config = 0;
3403   GSList *params;
3404   scanner_t scanner;
3405 
3406   assert (config_id);
3407   assert (current_credentials.uuid);
3408 
3409   sql_begin_immediate ();
3410 
3411   if (acl_user_may ("modify_config") == 0)
3412     {
3413       sql_rollback ();
3414       return 99;
3415     }
3416   if (find_config_with_permission (config_id, &config, "modify_config"))
3417     {
3418       sql_rollback ();
3419       return -1;
3420     }
3421   if (config == 0)
3422     {
3423       sql_rollback ();
3424       return 1;
3425     }
3426   if (config_type (config) != SCANNER_TYPE_OSP)
3427     {
3428       sql_rollback ();
3429       return 2;
3430     }
3431   scanner = config_scanner (config);
3432   if (!scanner)
3433     {
3434       sql_rollback ();
3435       return 3;
3436     }
3437   params = get_scanner_params (scanner);
3438   if (!params)
3439     {
3440       sql_rollback ();
3441       return 4;
3442     }
3443   update_config_params (config, config_id, params);
3444 
3445   sql_commit ();
3446   while (params)
3447     {
3448       osp_param_free (params->data);
3449       params = g_slist_remove_link (params, params);
3450     }
3451   return 0;
3452 }
3453 
3454 /**
3455  * @brief Count the number of scan configs.
3456  *
3457  * @param[in]  get  GET params.
3458  *
3459  * @return Total number of scan configs filtered set.
3460  */
3461 int
config_count(const get_data_t * get)3462 config_count (const get_data_t *get)
3463 {
3464   int rc;
3465   static const char *filter_columns[] = CONFIG_ITERATOR_FILTER_COLUMNS;
3466   static column_t columns[] = CONFIG_ITERATOR_COLUMNS;
3467   static column_t trash_columns[] = CONFIG_ITERATOR_TRASH_COLUMNS;
3468   const char *usage_type = get_data_get_extra (get, "usage_type");
3469   gchar *extra_where = configs_extra_where (usage_type);
3470 
3471   rc = count ("config", get, columns, trash_columns, filter_columns,
3472               0, 0, extra_where, TRUE);
3473 
3474   g_free (extra_where);
3475   return rc;
3476 }
3477 
3478 /**
3479  * @brief Initialise a config iterator, limited to user's configs.
3480  *
3481  * @param[in]  iterator    Iterator.
3482  * @param[in]  config      Config.  0 for all.
3483  * @param[in]  trash       Whether to iterate over trashcan configs.
3484  * @param[in]  ascending   Whether to sort ascending or descending.
3485  * @param[in]  sort_field  Field to sort on, or NULL for "id".
3486  */
3487 void
init_user_config_iterator(iterator_t * iterator,config_t config,int trash,int ascending,const char * sort_field)3488 init_user_config_iterator (iterator_t* iterator, config_t config, int trash,
3489                            int ascending, const char* sort_field)
3490 {
3491   static column_t select_columns[] = CONFIG_ITERATOR_COLUMNS;
3492   gchar *columns;
3493   gchar *sql;
3494 
3495   assert (current_credentials.uuid);
3496 
3497   columns = columns_build_select (select_columns);
3498   if (config)
3499     sql = g_strdup_printf ("SELECT %s"
3500                            " FROM configs%s"
3501                            " WHERE id = %llu"
3502                            " AND " ACL_USER_OWNS ()
3503                            " ORDER BY %s %s;",
3504                            columns,
3505                            trash ? "_trash" : "",
3506                            config,
3507                            current_credentials.uuid,
3508                            sort_field ? sort_field : "id",
3509                            ascending ? "ASC" : "DESC");
3510   else
3511     sql = g_strdup_printf ("SELECT %s"
3512                            " FROM configs%s"
3513                            " WHERE " ACL_USER_OWNS ()
3514                            " ORDER BY %s %s;",
3515                            columns,
3516                            trash ? "_trash" : "",
3517                            current_credentials.uuid,
3518                            sort_field ? sort_field : "id",
3519                            ascending ? "ASC" : "DESC");
3520   g_free (columns);
3521   init_iterator (iterator, "%s", sql);
3522   g_free (sql);
3523 }
3524 
3525 /**
3526  * @brief Initialise a scan config iterator.
3527  *
3528  * @param[in]  iterator  Iterator.
3529  * @param[in]  get         GET data.
3530  *
3531  * @return 0 success, 1 failed to find scan config, 2 failed to find filter,
3532  *         -1 error.
3533  */
3534 int
init_config_iterator(iterator_t * iterator,const get_data_t * get)3535 init_config_iterator (iterator_t* iterator, const get_data_t *get)
3536 {
3537   int rc;
3538   static const char *filter_columns[] = CONFIG_ITERATOR_FILTER_COLUMNS;
3539   static column_t columns[] = CONFIG_ITERATOR_COLUMNS;
3540   static column_t trash_columns[] = CONFIG_ITERATOR_TRASH_COLUMNS;
3541   const char *usage_type = get_data_get_extra (get, "usage_type");
3542   gchar *extra_where = configs_extra_where (usage_type);
3543 
3544   rc = init_get_iterator (iterator,
3545                           "config",
3546                           get,
3547                           columns,
3548                           trash_columns,
3549                           filter_columns,
3550                           0,
3551                           NULL,
3552                           extra_where,
3553                           TRUE);
3554   g_free (extra_where);
3555   return rc;
3556 }
3557 
3558 /**
3559  * @brief Get the nvt_selector from a config iterator.
3560  *
3561  * @param[in]  iterator  Iterator.
3562  *
3563  * @return The nvt_selector of the config, or NULL if iteration is complete.
3564  *         Freed by cleanup_iterator.
3565  */
3566 DEF_ACCESS (config_iterator_nvt_selector, GET_ITERATOR_COLUMN_COUNT);
3567 
3568 /**
3569  * @brief Get the family count from a config iterator.
3570  *
3571  * @param[in]  iterator  Iterator.
3572  *
3573  * @return Family count if known, -1 else.
3574  */
3575 int
config_iterator_family_count(iterator_t * iterator)3576 config_iterator_family_count (iterator_t* iterator)
3577 {
3578   int ret;
3579   if (iterator->done) return -1;
3580   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 1);
3581   return ret;
3582 }
3583 
3584 /**
3585  * @brief Get the nvt count from a config iterator.
3586  *
3587  * @param[in]  iterator  Iterator.
3588  *
3589  * @return Nvt count if known, -1 else.
3590  */
3591 int
config_iterator_nvt_count(iterator_t * iterator)3592 config_iterator_nvt_count (iterator_t* iterator)
3593 {
3594   int ret;
3595   if (iterator->done) return -1;
3596   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 2);
3597   return ret;
3598 }
3599 
3600 /**
3601  * @brief Get the families growing state from a config iterator.
3602  *
3603  * @param[in]  iterator  Iterator.
3604  *
3605  * @return Families growing flag.
3606  */
3607 int
config_iterator_families_growing(iterator_t * iterator)3608 config_iterator_families_growing (iterator_t* iterator)
3609 {
3610   int ret;
3611   if (iterator->done) return -1;
3612   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT +3);
3613   return ret;
3614 }
3615 
3616 /**
3617  * @brief Get the NVTs growing state from a config iterator.
3618  *
3619  * @param[in]  iterator  Iterator.
3620  *
3621  * @return NVTs growing flag.
3622  */
3623 int
config_iterator_nvts_growing(iterator_t * iterator)3624 config_iterator_nvts_growing (iterator_t* iterator)
3625 {
3626   int ret;
3627   if (iterator->done) return -1;
3628   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 4);
3629   return ret;
3630 }
3631 
3632 /**
3633  * @brief Get the type from a config iterator.
3634  *
3635  * @param[in]  iterator  Iterator.
3636  *
3637  * @return Config type.
3638  */
3639 int
config_iterator_type(iterator_t * iterator)3640 config_iterator_type (iterator_t* iterator)
3641 {
3642   int ret;
3643   if (iterator->done) return -1;
3644   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 5);
3645   return ret;
3646 }
3647 
3648 /**
3649  * @brief Get the scanner from a config iterator.
3650  *
3651  * @param[in]  iterator  Iterator.
3652  *
3653  * @return Scanner.
3654  */
3655 scanner_t
config_iterator_scanner(iterator_t * iterator)3656 config_iterator_scanner (iterator_t* iterator)
3657 {
3658   scanner_t ret = 0;
3659   if (iterator->done) return 0;
3660   ret = iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 6);
3661   return ret;
3662 }
3663 
3664 /**
3665  * @brief Get whether scanner is in trash from a config iterator.
3666  *
3667  * @param[in]  iterator  Iterator.
3668  *
3669  * @return Whether Scanner is in trash.
3670  */
3671 int
config_iterator_scanner_trash(iterator_t * iterator)3672 config_iterator_scanner_trash (iterator_t* iterator)
3673 {
3674   int ret = 0;
3675   if (iterator->done) return 0;
3676   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 7);
3677   return ret;
3678 }
3679 
3680 /**
3681  * @brief Get the usage type from a config iterator.
3682  *
3683  * @param[in]  iterator  Iterator.
3684  *
3685  * @return The usage type of the config, or NULL if iteration is complete.
3686  *         Freed by cleanup_iterator.
3687  */
3688 DEF_ACCESS (config_iterator_usage_type, GET_ITERATOR_COLUMN_COUNT + 8);
3689 
3690 /**
3691  * @brief Get predefined status from a config iterator.
3692  *
3693  * @param[in]  iterator  Iterator.
3694  *
3695  * @return 1 if predefined, else 0.
3696  */
3697 int
config_iterator_predefined(iterator_t * iterator)3698 config_iterator_predefined (iterator_t* iterator)
3699 {
3700   int ret = 0;
3701   if (iterator->done) return 0;
3702   ret = iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 9);
3703   return ret;
3704 }
3705 
3706 /**
3707  * @brief Return whether a config is referenced by a task.
3708  *
3709  * @param[in]  config  Config.
3710  *
3711  * @return 1 if in use, else 0.
3712  */
3713 int
config_in_use(config_t config)3714 config_in_use (config_t config)
3715 {
3716   return !!sql_int ("SELECT count(*) FROM tasks"
3717                     " WHERE config = %llu"
3718                     " AND config_location = " G_STRINGIFY (LOCATION_TABLE)
3719                     " AND hidden = 0;",
3720                     config);
3721 }
3722 
3723 /**
3724  * @brief Return whether a config can be modified.
3725  *
3726  * @param[in]  config  Config.
3727  *
3728  * @return 1.
3729  */
3730 int
config_writable(config_t config)3731 config_writable (config_t config)
3732 {
3733   return 1;
3734 }
3735 
3736 /**
3737  * @brief Return whether a trashcan config is referenced by a task.
3738  *
3739  * @param[in]  config  Config.
3740  *
3741  * @return 1 if in use, else 0.
3742  */
3743 int
trash_config_in_use(config_t config)3744 trash_config_in_use (config_t config)
3745 {
3746   return !!sql_int ("SELECT count(*) FROM tasks"
3747                     " WHERE config = %llu"
3748                     " AND config_location = " G_STRINGIFY (LOCATION_TRASH),
3749                     config);
3750 }
3751 
3752 /**
3753  * @brief Return whether a trashcan config is writable.
3754  *
3755  * @param[in]  config  Config.
3756  *
3757  * @return 1 if in use, else 0.
3758  */
3759 int
trash_config_writable(config_t config)3760 trash_config_writable (config_t config)
3761 {
3762   return !trash_config_in_use (config);
3763 }
3764 
3765 /**
3766  * @brief Return whether a trashcan config is readable.
3767  *
3768  * @param[in]  config_id  Config UUID.
3769  *
3770  * @return 1 if readable, else 0.
3771  */
3772 int
trash_config_readable_uuid(const gchar * config_id)3773 trash_config_readable_uuid (const gchar *config_id)
3774 {
3775   config_t found;
3776 
3777   found = 0;
3778   if (find_trash ("config", config_id, &found))
3779     return 0;
3780   return found > 0;
3781 }
3782 
3783 /**
3784  * @brief Initialise a preference iterator.
3785  *
3786  * Assume the caller has permission to access the config.
3787  *
3788  * @param[in]  iterator  Iterator.
3789  * @param[in]  config    Config.
3790  */
3791 void
init_config_preference_iterator(iterator_t * iterator,config_t config)3792 init_config_preference_iterator (iterator_t* iterator, config_t config)
3793 {
3794   gchar* sql;
3795 
3796   sql = g_strdup_printf ("SELECT name, value, type, default_value, hr_name"
3797                          " FROM config_preferences"
3798                          " WHERE config = %llu;",
3799                          config);
3800   init_iterator (iterator, "%s", sql);
3801   g_free (sql);
3802 }
3803 
3804 /**
3805  * @brief Get the name from a preference iterator.
3806  *
3807  * @param[in]  iterator  Iterator.
3808  *
3809  * Note: For OSP results this corresponds to the "id" field in OSP, not "name".
3810  *
3811  * @return The name of the preference iterator, or NULL if iteration is
3812  *         complete.  Freed by cleanup_iterator.
3813  */
3814 DEF_ACCESS (config_preference_iterator_name, 0);
3815 
3816 /**
3817  * @brief Get the value from a preference iterator.
3818  *
3819  * @param[in]  iterator  Iterator.
3820  *
3821  * @return The value of the preference iterator, or NULL if iteration is
3822  *         complete.  Freed by cleanup_iterator.
3823  */
3824 DEF_ACCESS (config_preference_iterator_value, 1);
3825 
3826 /**
3827  * @brief Get the type from a preference iterator.
3828  *
3829  * @param[in]  iterator  Iterator.
3830  *
3831  * @return The value of the preference iterator, or NULL if iteration is
3832  *         complete.  Freed by cleanup_iterator.
3833  */
3834 DEF_ACCESS (config_preference_iterator_type, 2);
3835 
3836 /**
3837  * @brief Get the default from a preference iterator.
3838  *
3839  * @param[in]  iterator  Iterator.
3840  *
3841  * @return The default of the preference iterator, or NULL if iteration is
3842  *         complete.  Freed by cleanup_iterator.
3843  */
3844 DEF_ACCESS (config_preference_iterator_default, 3);
3845 
3846 /**
3847  * @brief Get the hr_name from a preference iterator.
3848  *
3849  * Note: This corresponds to the "name" in OSP and is not defined for classic
3850  *  OpenVAS config preferences.
3851  *
3852  * @param[in]  iterator  Iterator.
3853  *
3854  * @return The hr_name of the preference iterator, or NULL if iteration is
3855  *         complete.  Freed by cleanup_iterator.
3856  */
3857 DEF_ACCESS (config_preference_iterator_hr_name, 4);
3858 
3859 /**
3860  * @brief Initialise a config preference iterator, with defaults.
3861  *
3862  * Assume the caller has permission to access the config.
3863  *
3864  * This version substitutes the NVT preference when the config preference
3865  * is missing.
3866  *
3867  * @param[in]  iterator  Iterator.
3868  * @param[in]  config    Config containing preferences.
3869  * @param[in]  section   Preference section.
3870  */
3871 void
init_preference_iterator(iterator_t * iterator,config_t config,const char * section)3872 init_preference_iterator (iterator_t* iterator,
3873                           config_t config,
3874                           const char* section)
3875 {
3876   gchar *quoted_section;
3877 
3878   assert (config);
3879   assert (section);
3880   assert ((strcmp (section, "PLUGINS_PREFS") == 0)
3881           || (strcmp (section, "SERVER_PREFS") == 0));
3882 
3883   quoted_section = sql_quote (section);
3884 
3885   init_iterator (iterator,
3886                  "SELECT config_preferences.name, config_preferences.value"
3887                  " FROM config_preferences, nvt_preferences"
3888                  " WHERE config_preferences.config = %llu"
3889                  " AND config_preferences.type = '%s'"
3890                  " AND (config_preferences.name = nvt_preferences.name"
3891                  "      OR config_preferences.name LIKE 'timeout.%%')"
3892                  " AND config_preferences.name != 'max_checks'"
3893                  " AND config_preferences.name != 'max_hosts'"
3894                  " UNION"
3895                  " SELECT nvt_preferences.name, nvt_preferences.value"
3896                  " FROM nvt_preferences"
3897                  " WHERE nvt_preferences.name %s"
3898                  " AND (SELECT COUNT(*) FROM config_preferences"
3899                  "      WHERE config = %llu"
3900                  "      AND config_preferences.name = nvt_preferences.name) = 0;",
3901                  config,
3902                  quoted_section,
3903                  strcmp (quoted_section, "SERVER_PREFS") == 0
3904                   ? "NOT LIKE '%:%:%:%'" : "LIKE '%:%:%:%'",
3905                  config);
3906   g_free (quoted_section);
3907 }
3908 
3909 /**
3910  * @brief Get the NAME from a preference iterator.
3911  *
3912  * @param[in]  iterator  Iterator.
3913  *
3914  * @return NAME, or NULL if iteration is complete.  Freed by
3915  *         cleanup_iterator.
3916  */
3917 DEF_ACCESS (preference_iterator_name, 0);
3918 
3919 /**
3920  * @brief Get the value from a preference iterator.
3921  *
3922  * @param[in]  iterator  Iterator.
3923  *
3924  * @return Value, or NULL if iteration is complete.  Freed by
3925  *         cleanup_iterator.
3926  */
3927 DEF_ACCESS (preference_iterator_value, 1);
3928 
3929 /**
3930  * @brief Return the NVT selector associated with a config.
3931  *
3932  * @param[in]  config  Config.
3933  *
3934  * @return Name of NVT selector if config exists and NVT selector is set, else
3935  *         NULL.
3936  */
3937 char*
config_nvt_selector(config_t config)3938 config_nvt_selector (config_t config)
3939 {
3940   return sql_string ("SELECT nvt_selector FROM configs WHERE id = %llu;",
3941                      config);
3942 }
3943 
3944 /**
3945  * @brief Update a preference of a config.
3946  *
3947  * @param[in]  config      Config.
3948  * @param[in]  nvt         UUID of NVT.  NULL for scanner preference.
3949  * @param[in]  name        Preference name, including NVT name and preference
3950  *                         type.
3951  * @param[in]  value_64    Preference value in base64.  NULL for an NVT
3952  *                         preference removes the preference from the config.
3953  *
3954  * @return 0 success, 1 config in use, 2 empty radio value, 3 failed to find
3955  *         config, -1 error.
3956  */
3957 static int
modify_config_preference(config_t config,const char * nvt,const char * name,const char * value_64)3958 modify_config_preference (config_t config, const char* nvt,
3959                           const char* name, const char* value_64)
3960 {
3961   gchar *quoted_name, *quoted_value, *value, **splits;
3962 
3963   quoted_name = sql_quote (name);
3964 
3965   if (strlen (value_64))
3966     {
3967       gsize value_len;
3968       value = (gchar*) g_base64_decode (value_64, &value_len);
3969     }
3970   else
3971     value = g_strdup ("");
3972 
3973   /* OID:PrefID:PrefType:PrefName value */
3974   splits = g_strsplit (name, ":", 4);
3975   if (splits && g_strv_length (splits) == 4)
3976     {
3977       if (strcmp (splits[2], "radio") == 0)
3978         {
3979           char *old_value;
3980           gchar **split, **point;
3981           GString *string;
3982 
3983           if (strlen (value) == 0)
3984             {
3985               g_free (quoted_name);
3986               g_free (value);
3987               return 2;
3988             }
3989 
3990           /* A radio.  Put the new value on the front of the list of options. */
3991 
3992           old_value = sql_string ("SELECT value FROM config_preferences"
3993                                   " WHERE config = %llu"
3994                                   " AND type %s"
3995                                   " AND name = '%s'",
3996                                   config,
3997                                   nvt ? "= 'PLUGINS_PREFS'" : "is NULL",
3998                                   quoted_name);
3999           if (old_value == NULL)
4000             old_value = sql_string ("SELECT value FROM nvt_preferences"
4001                                     " WHERE name = '%s'",
4002                                     quoted_name);
4003           if (old_value)
4004             {
4005               string = g_string_new (value);
4006               split = g_strsplit (old_value, ";", 0);
4007               free (old_value);
4008               point = split;
4009               while (*point)
4010                 {
4011                   if (strlen (*point) == 0)
4012                     {
4013                       g_free (quoted_name);
4014                       g_strfreev (split);
4015                       g_free (value);
4016                       g_string_free (string, TRUE);
4017                       return -1;
4018                     }
4019 
4020                   if (strcmp (*point, value))
4021                     {
4022                       g_string_append_c (string, ';');
4023                       g_string_append (string, *point);
4024                     }
4025                   point++;
4026                 }
4027               g_strfreev (split);
4028               g_free (value);
4029               value = g_string_free (string, FALSE);
4030             }
4031         }
4032       else if (strcmp (splits[2], "scanner") == 0)
4033         {
4034           /* A scanner preference.  Remove type decoration from name. */
4035 
4036           g_free (quoted_name);
4037           quoted_name = sql_quote (splits[3]);
4038         }
4039     }
4040   g_strfreev (splits);
4041 
4042   quoted_value = sql_quote ((gchar*) value);
4043   g_free (value);
4044 
4045   if (config_type (config) > 0)
4046     sql ("UPDATE config_preferences SET value = '%s'"
4047          " WHERE config = %llu AND name = '%s';",
4048          quoted_value, config, quoted_name);
4049   else
4050     {
4051       /* nvt prefs are not present on first modification. */
4052       sql ("DELETE FROM config_preferences"
4053            " WHERE config = %llu AND type %s AND name = '%s'",
4054            config,
4055            nvt ? "= 'PLUGINS_PREFS'" : "= 'SERVER_PREFS'",
4056            quoted_name);
4057       sql ("INSERT INTO config_preferences"
4058            " (config, type, name, value) VALUES (%llu, %s, '%s', '%s');",
4059            config, nvt ? "'PLUGINS_PREFS'" : "'SERVER_PREFS'", quoted_name,
4060            quoted_value);
4061     }
4062 
4063   return 0;
4064 }
4065 
4066 /**
4067  * @brief Set a preference of a config.
4068  *
4069  * @param[in]  config      Config to modify.
4070  * @param[in]  nvt         UUID of NVT.  NULL for scanner preference.
4071  * @param[in]  name        Preference name, including NVT name and preference
4072  *                         type.
4073  * @param[in]  value_64    Preference value in base64.  NULL for an NVT
4074  *                         preference removes the preference from the config.
4075  *
4076  * @return 0 success, 1 config in use, 2 empty radio value, -1 error.
4077  */
4078 int
manage_set_config_preference(config_t config,const char * nvt,const char * name,const char * value_64)4079 manage_set_config_preference (config_t config, const char* nvt,
4080                               const char* name, const char* value_64)
4081 {
4082   int ret;
4083 
4084   if (value_64 == NULL)
4085     {
4086       gchar *quoted_name, **splits;
4087 
4088       if (sql_int ("SELECT count(*) FROM tasks"
4089                    " WHERE config = %llu AND hidden = 0;",
4090                    config))
4091         {
4092           return 1;
4093         }
4094 
4095       quoted_name = sql_quote (name);
4096 
4097       /* OID:PrefID:scanner:PrefName */
4098       splits = g_strsplit (name, ":", 4);
4099       if (splits && g_strv_length (splits) == 4
4100           && strcmp (splits[2], "scanner") == 0)
4101         {
4102           /* A scanner preference.  Remove type decoration from name. */
4103           g_free (quoted_name);
4104           quoted_name = sql_quote (splits[3]);
4105         }
4106       g_strfreev (splits);
4107 
4108       sql ("DELETE FROM config_preferences"
4109            " WHERE config = %llu"
4110            " AND name = '%s';",
4111            config,
4112            quoted_name);
4113 
4114       g_free (quoted_name);
4115       return 0;
4116     }
4117 
4118   if (sql_int ("SELECT count(*) FROM tasks"
4119                " WHERE config = %llu AND hidden = 0;",
4120                config))
4121     {
4122       return 1;
4123     }
4124 
4125   ret = modify_config_preference (config, nvt, name, value_64);
4126   if (ret)
4127     {
4128       return ret;
4129     }
4130 
4131   return 0;
4132 }
4133 
4134 /**
4135  * @brief Set the name, comment and scanner of a config.
4136  *
4137  * @param[in]  config       Config to modify.
4138  * @param[in]  name         New name, not updated if NULL.
4139  * @param[in]  comment      New comment, not updated if NULL.
4140  * @param[in]  scanner_id   UUID of new scanner, not updated if NULL.
4141  *
4142  * @return 0 success, 1 config with new name exists already, 2 scanner doesn't
4143  *         exist, 3 modification not allowed while config is in use, -1 error.
4144  */
4145 int
manage_set_config(config_t config,const char * name,const char * comment,const char * scanner_id)4146 manage_set_config (config_t config, const char *name, const char *comment,
4147                    const char *scanner_id)
4148 {
4149   assert (current_credentials.uuid);
4150 
4151   if (name)
4152     {
4153       gchar *quoted_name;
4154       if (resource_with_name_exists (name, "config", config))
4155         {
4156           return 1;
4157         }
4158       quoted_name = sql_quote (name);
4159       sql ("UPDATE configs SET name = '%s', modification_time = m_now ()"
4160            " WHERE id = %llu;", quoted_name, config);
4161       g_free (quoted_name);
4162     }
4163   if (comment)
4164     {
4165       gchar *quoted_comment;
4166       quoted_comment = sql_quote (comment);
4167       sql ("UPDATE configs SET comment = '%s', modification_time = m_now ()"
4168            " WHERE id = %llu;", quoted_comment, config);
4169       g_free (quoted_comment);
4170     }
4171   if (scanner_id)
4172     {
4173       if (config_in_use (config))
4174         {
4175           return 3;
4176         }
4177       scanner_t scanner = 0;
4178 
4179       if (find_scanner_with_permission (scanner_id, &scanner, "get_scanners")
4180           || scanner == 0)
4181         {
4182           return 2;
4183         }
4184       sql ("UPDATE configs SET scanner = %llu, modification_time = m_now ()"
4185            " WHERE id = %llu;", scanner, config);
4186     }
4187   return 0;
4188 }
4189 
4190 /**
4191  * @brief Check whether a family is "whole-only".
4192  *
4193  * @param[in]  family         Family name.
4194  *
4195  * @return 1 if whole-only, else 0.
4196  */
4197 int
family_whole_only(const gchar * family)4198 family_whole_only (const gchar *family)
4199 {
4200   static const gchar *wholes[] = FAMILIES_WHOLE_ONLY;
4201 
4202   for (const gchar **whole = wholes; *whole; whole++)
4203     if (strcmp (*whole, family) == 0)
4204       return 1;
4205   return 0;
4206 }
4207 
4208 /**
4209  * @brief Get whether a config selects every NVT in a given family.
4210  *
4211  * @param[in]  config      Config.
4212  * @param[in]  family      Family name.
4213  *
4214  * @return 0 no, 1 yes, -1 error.
4215  */
4216 int
config_family_entire_and_growing(config_t config,const char * family)4217 config_family_entire_and_growing (config_t config, const char* family)
4218 {
4219   char *selector;
4220   int ret;
4221 
4222   if (config == 0)
4223     return 0;
4224 
4225   selector = config_nvt_selector (config);
4226   if (selector == NULL)
4227     {
4228       /* The config should always have a selector. */
4229       return -1;
4230     }
4231 
4232   ret = nvt_selector_entire_and_growing (selector,
4233                                          family,
4234                                          config_families_growing (config));
4235   free (selector);
4236 
4237   return ret;
4238 }
4239 
4240 /**
4241  * @brief Set the NVT's selected for a single family of a config.
4242  *
4243  * @param[in]  config         Config to modify.
4244  * @param[in]  family         Family name.
4245  * @param[in]  selected_nvts  NVT's.
4246  *
4247  * @return 0 success, 1 config in use, 2 whole-only family, -1 error.
4248  */
4249 int
manage_set_config_nvts(config_t config,const char * family,GPtrArray * selected_nvts)4250 manage_set_config_nvts (config_t config, const char* family,
4251                         GPtrArray* selected_nvts)
4252 {
4253   char *selector;
4254   gchar *quoted_family, *quoted_selector;
4255   int new_nvt_count = 0, old_nvt_count;
4256 
4257   if (family_whole_only (family))
4258     return 2;
4259 
4260   if (sql_int ("SELECT count(*) FROM tasks"
4261                " WHERE config = %llu AND hidden = 0;",
4262                config))
4263     {
4264       return 1;
4265     }
4266 
4267   quoted_family = sql_quote (family);
4268 
4269   selector = config_nvt_selector (config);
4270   if (selector == NULL)
4271     {
4272       /* The config should always have a selector. */
4273       g_free (quoted_family);
4274       return -1;
4275     }
4276 
4277   quoted_selector = sql_quote (selector);
4278 
4279   /* If the family is growing, then exclude all no's, otherwise the family
4280    * is static, so include all yes's. */
4281 
4282   if (nvt_selector_family_growing (selector,
4283                                    family,
4284                                    config_families_growing (config)))
4285     {
4286       iterator_t nvts;
4287 
4288       old_nvt_count = nvt_selector_nvt_count (selector, family, 1);
4289 
4290       free (selector);
4291 
4292       /* Clear any NVT selectors for this family from the config. */
4293 
4294       if (strcmp (quoted_selector, MANAGE_NVT_SELECTOR_UUID_ALL))
4295         sql ("DELETE FROM nvt_selectors"
4296              " WHERE name = '%s'"
4297              " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
4298              " AND family = '%s';",
4299              quoted_selector,
4300              quoted_family);
4301 
4302       /* Exclude all no's. */
4303 
4304       new_nvt_count = family_nvt_count (family);
4305 
4306       init_nvt_iterator (&nvts, (nvt_t) 0, config, family, NULL, 1, NULL);
4307       while (next (&nvts))
4308         {
4309           const char *oid = nvt_iterator_oid (&nvts);
4310           gchar *quoted_oid;
4311 
4312           if (member (selected_nvts, oid)) continue;
4313 
4314           quoted_oid = sql_quote (oid);
4315           sql ("INSERT INTO nvt_selectors"
4316                " (name, exclude, type, family_or_nvt, family)"
4317                " VALUES ('%s', 1, "
4318                G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
4319                ", '%s', '%s');",
4320                quoted_selector,
4321                quoted_oid,
4322                quoted_family);
4323           g_free (quoted_oid);
4324 
4325           new_nvt_count--;
4326         }
4327       cleanup_iterator (&nvts);
4328     }
4329   else
4330     {
4331       old_nvt_count = nvt_selector_nvt_count (selector, family, 0);
4332 
4333       free (selector);
4334 
4335       /* Clear any NVT selectors for this family from the config. */
4336 
4337       if (strcmp (quoted_selector, MANAGE_NVT_SELECTOR_UUID_ALL))
4338         sql ("DELETE FROM nvt_selectors"
4339              " WHERE name = '%s'"
4340              " AND type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
4341              " AND family = '%s';",
4342              quoted_selector,
4343              quoted_family);
4344 
4345       /* Include all yes's. */
4346 
4347       if (selected_nvts)
4348         {
4349           gchar *nvt;
4350           new_nvt_count = 0;
4351 
4352           while ((nvt = (gchar*) g_ptr_array_index (selected_nvts,
4353                                                     new_nvt_count)))
4354             {
4355               gchar *quoted_nvt = sql_quote (nvt);
4356               sql ("INSERT INTO nvt_selectors"
4357                    " (name, exclude, type, family_or_nvt, family)"
4358                    " VALUES ('%s', 0, "
4359                    G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
4360                    ", '%s', '%s');",
4361                    quoted_selector,
4362                    quoted_nvt,
4363                    quoted_family);
4364               g_free (quoted_nvt);
4365               new_nvt_count++;
4366             }
4367         }
4368     }
4369 
4370   /* Update the cached config info. */
4371 
4372   sql ("UPDATE configs SET family_count = family_count + %i,"
4373        " nvt_count = nvt_count - %i + %i,"
4374        " modification_time = m_now ()"
4375        " WHERE id = %llu;",
4376        old_nvt_count == 0
4377         ? (new_nvt_count == 0 ? 0 : 1)
4378         : (new_nvt_count == 0 ? -1 : 0),
4379        old_nvt_count,
4380        MAX (new_nvt_count, 0),
4381        config);
4382 
4383   g_free (quoted_family);
4384   g_free (quoted_selector);
4385   return 0;
4386 }
4387 
4388 /**
4389  * @brief Switch between constraining and generating representation.
4390  *
4391  * It's up to the caller to start and end a transaction.
4392  *
4393  * @param[in]  config        Config name.
4394  * @param[in]  constraining  1 families currently growing, 0 families currently
4395  *                           static.
4396  *
4397  * @return 0 success, -1 error.
4398  */
4399 static int
switch_representation(config_t config,int constraining)4400 switch_representation (config_t config, int constraining)
4401 {
4402   char* selector;
4403   gchar *quoted_selector;
4404 
4405   selector = config_nvt_selector (config);
4406   if (selector == NULL)
4407     return -1;
4408   quoted_selector = sql_quote (selector);
4409 
4410   if (constraining)
4411     {
4412       iterator_t families;
4413 
4414       /* Currently constraining the universe. */
4415 
4416       /* Remove the all selector. */
4417 
4418       nvt_selector_remove_selector (quoted_selector,
4419                                     NULL,
4420                                     NVT_SELECTOR_TYPE_ALL);
4421 
4422       /* Convert each family. */
4423 
4424       init_family_iterator (&families, 0, NULL, 1);
4425       while (next (&families))
4426         {
4427           const char *family = family_iterator_name (&families);
4428           if (family)
4429             {
4430               gchar *quoted_family = sql_quote (family);
4431               if (nvt_selector_family_growing (selector, family, 1))
4432                 /* Add a family include. */
4433                 nvt_selector_add (quoted_selector,
4434                                   quoted_family,
4435                                   NULL,
4436                                   0);
4437               else
4438                 /* Remove the family exclude. */
4439                 nvt_selector_remove_selector (quoted_selector,
4440                                               quoted_family,
4441                                               NVT_SELECTOR_TYPE_FAMILY);
4442               g_free (quoted_family);
4443             }
4444         }
4445       cleanup_iterator (&families);
4446 
4447       /* Update the cached config info. */
4448 
4449       sql ("UPDATE configs SET families_growing = 0 WHERE id = %llu;",
4450            config);
4451     }
4452   else
4453     {
4454       iterator_t families;
4455 
4456       /* Currently generating from empty. */
4457 
4458       /* Add the all selector. */
4459 
4460       sql ("INSERT INTO nvt_selectors"
4461            " (name, exclude, type, family_or_nvt)"
4462            " VALUES ('%s', 0, 0, 0);",
4463            quoted_selector);
4464 
4465       /* Convert each family. */
4466 
4467       init_family_iterator (&families, 0, NULL, 1);
4468       while (next (&families))
4469         {
4470           const char *family = family_iterator_name (&families);
4471           if (family)
4472             {
4473               gchar *quoted_family = sql_quote (family);
4474               if (nvt_selector_family_growing (selector, family, 0))
4475                 /* Remove the family include. */
4476                 nvt_selector_remove_selector (quoted_selector,
4477                                               quoted_family,
4478                                               NVT_SELECTOR_TYPE_FAMILY);
4479               else
4480                 /* Add a family exclude. */
4481                 nvt_selector_add (quoted_selector,
4482                                   quoted_family,
4483                                   NULL,
4484                                   1);
4485               g_free (quoted_family);
4486             }
4487         }
4488       cleanup_iterator (&families);
4489 
4490       /* Update the cached config info. */
4491 
4492       sql ("UPDATE configs SET families_growing = 1 WHERE id = %llu;",
4493            config);
4494     }
4495 
4496   free (selector);
4497   g_free (quoted_selector);
4498   return 0;
4499 }
4500 
4501 /**
4502  * @brief Initialise a config task iterator.
4503  *
4504  * Iterate over all tasks that use the config.
4505  *
4506  * @param[in]  iterator   Iterator.
4507  * @param[in]  config     Config.
4508  * @param[in]  ascending  Whether to sort ascending or descending.
4509  */
4510 void
init_config_task_iterator(iterator_t * iterator,config_t config,int ascending)4511 init_config_task_iterator (iterator_t* iterator, config_t config,
4512                            int ascending)
4513 {
4514   gchar *available, *with_clause;
4515   get_data_t get;
4516   array_t *permissions;
4517 
4518   assert (config);
4519 
4520   get.trash = 0;
4521   permissions = make_array ();
4522   array_add (permissions, g_strdup ("get_tasks"));
4523   available = acl_where_owned ("task", &get, 1, "any", 0, permissions, 0,
4524                                &with_clause);
4525   array_free (permissions);
4526 
4527   init_iterator (iterator,
4528                  "%s"
4529                  " SELECT name, uuid, %s FROM tasks"
4530                  " WHERE config = %llu"
4531                  " AND hidden = 0"
4532                  " ORDER BY name %s;",
4533                  with_clause ? with_clause : "",
4534                  available,
4535                  config,
4536                  ascending ? "ASC" : "DESC");
4537 
4538   g_free (with_clause);
4539   g_free (available);
4540 }
4541 
4542 /**
4543  * @brief Get the name from a config_task iterator.
4544  *
4545  * @param[in]  iterator  Iterator.
4546  *
4547  * @return Name, or NULL if iteration is complete.  Freed by
4548  *         cleanup_iterator.
4549  */
4550 DEF_ACCESS (config_task_iterator_name, 0);
4551 
4552 /**
4553  * @brief Get the UUID from a config_task iterator.
4554  *
4555  * @param[in]  iterator  Iterator.
4556  *
4557  * @return UUID, or NULL if iteration is complete.  Freed by
4558  *         cleanup_iterator.
4559  */
4560 DEF_ACCESS (config_task_iterator_uuid, 1);
4561 
4562 /**
4563  * @brief Get the read permission status from a GET iterator.
4564  *
4565  * @param[in]  iterator  Iterator.
4566  *
4567  * @return 1 if may read, else 0.
4568  */
4569 int
config_task_iterator_readable(iterator_t * iterator)4570 config_task_iterator_readable (iterator_t* iterator)
4571 {
4572   if (iterator->done) return 0;
4573   return iterator_int (iterator, 2);
4574 }
4575 
4576 /**
4577  * @brief Initialise a config timeout iterator.
4578  *
4579  * Iterate over all timeout preferences of NVTs that have timeouts.
4580  *
4581  * @param[in]  iterator   Iterator.
4582  * @param[in]  config     Config.
4583  */
4584 void
init_config_timeout_iterator(iterator_t * iterator,config_t config)4585 init_config_timeout_iterator (iterator_t* iterator, config_t config)
4586 {
4587   init_iterator (iterator,
4588                  "SELECT name, substr (name, 9),"
4589                  "       (SELECT name FROM nvts"
4590                  "        WHERE oid = substr (config_preferences.name, 9)),"
4591                  "       value"
4592                  " FROM config_preferences"
4593                  " WHERE config = %llu"
4594                  " AND substr (name, 1, 8) = 'timeout.'"
4595                  /* Ensure that the NVT pref comes first, in case an
4596                   * error in the GSA added the NVT pref as a Scanner
4597                   * pref. */
4598                  " ORDER BY type",
4599                  config);
4600 }
4601 
4602 /**
4603  * @brief Get the NVT OID from a config timeout iterator.
4604  *
4605  * @param[in]  iterator  Iterator.
4606  *
4607  * @return NVT OID, or NULL if iteration is complete.  Freed by
4608  *         cleanup_iterator.
4609  */
4610 DEF_ACCESS (config_timeout_iterator_oid, 1);
4611 
4612 /**
4613  * @brief Get the NVT OID from a config timeout iterator.
4614  *
4615  * @param[in]  iterator  Iterator.
4616  *
4617  * @return NVT OID, or NULL if iteration is complete.  Freed by
4618  *         cleanup_iterator.
4619  */
4620 DEF_ACCESS (config_timeout_iterator_nvt_name, 2);
4621 
4622 /**
4623  * @brief Get the value from a config timeout iterator.
4624  *
4625  * @param[in]  iterator  Iterator.
4626  *
4627  * @return Timeout value, or NULL if iteration is complete.  Freed by
4628  *         cleanup_iterator.
4629  */
4630 DEF_ACCESS (config_timeout_iterator_value, 3);
4631 
4632 /**
4633  * @brief Update or optionally insert a NVT preference.
4634  *
4635  * @param[in]  config_id        UUID of the config to set the preference in
4636  * @param[in]  type             Type of the preference, e.g. "PLUGINS_PREFS"
4637  * @param[in]  preference_name  Full name of the preference
4638  * @param[in]  new_value        The new value to set
4639  * @param[in]  insert           Whether to insert the preference if missing
4640  */
4641 void
update_config_preference(const char * config_id,const char * type,const char * preference_name,const char * new_value,gboolean insert)4642 update_config_preference (const char *config_id,
4643                           const char *type,
4644                           const char *preference_name,
4645                           const char *new_value,
4646                           gboolean insert)
4647 {
4648   gchar *quoted_config_id = sql_quote (config_id);
4649   gchar *quoted_type = sql_quote (type);
4650   gchar *quoted_name = sql_quote (preference_name);
4651   gchar *quoted_value = sql_quote (new_value);
4652 
4653   if (sql_int ("SELECT count (*) FROM config_preferences"
4654                " WHERE config = (SELECT id FROM configs WHERE uuid = '%s')"
4655                "   AND type = '%s'"
4656                "   AND name = '%s';",
4657                quoted_config_id, quoted_type, quoted_name) == 0)
4658     {
4659       if (insert)
4660         {
4661           sql ("INSERT INTO config_preferences (config, type, name, value)"
4662                " VALUES ((SELECT id FROM configs WHERE uuid = '%s'),"
4663                "         '%s', '%s', '%s');",
4664                quoted_config_id, quoted_type, quoted_name, quoted_value);
4665         }
4666     }
4667   else
4668     {
4669       sql ("UPDATE config_preferences SET value = '%s'"
4670            " WHERE config = (SELECT id FROM configs WHERE uuid = '%s')"
4671            "   AND type = '%s'"
4672            "   AND name = '%s';",
4673            quoted_value, quoted_config_id, quoted_type, quoted_name);
4674     }
4675 
4676   g_free (quoted_config_id);
4677   g_free (quoted_type);
4678   g_free (quoted_name);
4679   g_free (quoted_value);
4680 }
4681 
4682 /**
4683  * @brief Update the cached count and growing information in a config.
4684  *
4685  * It's up to the caller to organise a transaction.
4686  *
4687  * @param[in]  configs  Config to update.
4688  */
4689 static void
update_config_cache(iterator_t * configs)4690 update_config_cache (iterator_t *configs)
4691 {
4692   const char *selector;
4693   gchar *quoted_selector, *quoted_name;
4694   int families_growing;
4695 
4696   if (config_iterator_type (configs) > 0)
4697     return;
4698 
4699   quoted_name = sql_quote (get_iterator_name (configs));
4700   selector = config_iterator_nvt_selector (configs);
4701   families_growing = nvt_selector_families_growing (selector);
4702   quoted_selector = sql_quote (selector);
4703 
4704   sql ("UPDATE configs"
4705        " SET family_count = %i, nvt_count = %i,"
4706        " families_growing = %i, nvts_growing = %i"
4707        " WHERE name = '%s';",
4708        nvt_selector_family_count (quoted_selector, families_growing),
4709        nvt_selector_nvt_count (quoted_selector, NULL, families_growing),
4710        families_growing,
4711        nvt_selector_nvts_growing_2 (quoted_selector, families_growing),
4712        quoted_name);
4713 
4714   g_free (quoted_name);
4715   g_free (quoted_selector);
4716 }
4717 
4718 /**
4719  * @brief Update the cached count and growing information in every config.
4720  *
4721  * Only consider configs for the current user.
4722  *
4723  * It's up to the caller to organise a transaction.
4724  *
4725  * @param[in]  config  Config to update.  0 for all.
4726  */
4727 static void
update_config_caches(config_t config)4728 update_config_caches (config_t config)
4729 {
4730   iterator_t configs;
4731 
4732   init_user_config_iterator (&configs, config, 0, 1, NULL);
4733   while (next (&configs))
4734     update_config_cache (&configs);
4735   cleanup_iterator (&configs);
4736 }
4737 
4738 /**
4739  * @brief Update count and growing info in every config across all users.
4740  *
4741  * It's up to the caller to organise a transaction.
4742  */
4743 void
update_all_config_caches()4744 update_all_config_caches ()
4745 {
4746   static column_t select_columns[] = CONFIG_ITERATOR_COLUMNS;
4747   gchar *columns;
4748   iterator_t configs;
4749 
4750   columns = columns_build_select (select_columns);
4751   init_iterator (&configs, "SELECT %s FROM configs;", columns);
4752   g_free (columns);
4753   while (next (&configs))
4754     update_config_cache (&configs);
4755   cleanup_iterator (&configs);
4756 }
4757 
4758 /**
4759  * @brief Update count and growing info in config, without checking user.
4760  *
4761  * For use during initialisation.
4762  *
4763  * @param[in]  uuid  Config UUID.
4764  *
4765  * It's up to the caller to organise a transaction.
4766  */
4767 void
update_config_cache_init(const char * uuid)4768 update_config_cache_init (const char *uuid)
4769 {
4770   static column_t select_columns[] = CONFIG_ITERATOR_COLUMNS;
4771   gchar *columns;
4772   iterator_t configs;
4773 
4774   columns = columns_build_select (select_columns);
4775   init_iterator (&configs,
4776                  "SELECT %s FROM configs WHERE uuid = '%s';",
4777                  columns,
4778                  uuid);
4779   g_free (columns);
4780   while (next (&configs))
4781     update_config_cache (&configs);
4782   cleanup_iterator (&configs);
4783 }
4784 
4785 /**
4786  * @brief Migrate old ownerless configs to the Feed Owner.
4787  */
4788 void
migrate_predefined_configs()4789 migrate_predefined_configs ()
4790 {
4791   sql ("UPDATE configs"
4792        " SET owner = (SELECT id FROM users"
4793        "              WHERE uuid = (SELECT value FROM settings"
4794        "                            WHERE uuid = '%s'))"
4795        " WHERE owner is NULL;",
4796        SETTING_UUID_FEED_IMPORT_OWNER);
4797 }
4798 
4799 
4800 /* Startup. */
4801 
4802 /**
4803  * @brief Check if a config has been updated in the feed.
4804  *
4805  * @param[in]  path    Full path to config XML in feed.
4806  * @param[in]  config  Config.
4807  *
4808  * @return 1 if updated in feed, else 0.
4809  */
4810 int
config_updated_in_feed(config_t config,const gchar * path)4811 config_updated_in_feed (config_t config, const gchar *path)
4812 {
4813   GStatBuf state;
4814   int last_config_update;
4815 
4816   last_config_update = sql_int ("SELECT modification_time FROM configs"
4817                                 " WHERE id = %llu;",
4818                                 config);
4819 
4820   if (g_stat (path, &state))
4821     {
4822       g_warning ("%s: Failed to stat feed config file: %s",
4823                  __func__,
4824                  strerror (errno));
4825       return 0;
4826     }
4827 
4828   if (state.st_mtime <= last_config_update)
4829     return 0;
4830 
4831   return 1;
4832 }
4833 
4834 /**
4835  * @brief Update a config from an XML file.
4836  *
4837  * @param[in]  config       Existing config.
4838  * @param[in]  type         New config type.
4839  * @param[in]  name         New name.
4840  * @param[in]  comment      New comment.
4841  * @param[in]  usage_type   New usage type.
4842  * @param[in]  all_selector  Whether to use "all" selector instead of selectors.
4843  * @param[in]  selectors     New NVT selectors.
4844  * @param[in]  preferences   New preferences.
4845  */
4846 void
update_config(config_t config,const gchar * type,const gchar * name,const gchar * comment,const gchar * usage_type,int all_selector,const array_t * selectors,const array_t * preferences)4847 update_config (config_t config, const gchar *type, const gchar *name,
4848                const gchar *comment, const gchar *usage_type,
4849                int all_selector,
4850                const array_t* selectors /* nvt_selector_t. */,
4851                const array_t* preferences /* preference_t. */)
4852 {
4853   gchar *quoted_name, *quoted_comment, *quoted_type, *actual_usage_type;
4854 
4855   sql_begin_immediate ();
4856 
4857   if (usage_type && strcasecmp (usage_type, "policy") == 0)
4858     actual_usage_type = "policy";
4859   else
4860     actual_usage_type = "scan";
4861 
4862   quoted_name = sql_quote (name);
4863   quoted_comment = sql_quote (comment ? comment : "");
4864   quoted_type = sql_quote (type);
4865   sql ("UPDATE configs"
4866        " SET name = '%s', comment = '%s', type = '%s', usage_type = '%s',"
4867        " predefined = 1, modification_time = m_now ()"
4868        " WHERE id = %llu;",
4869        quoted_name,
4870        quoted_comment,
4871        quoted_type,
4872        actual_usage_type,
4873        config);
4874   g_free (quoted_name);
4875   g_free (quoted_comment);
4876   g_free (quoted_type);
4877 
4878   /* Replace the NVT selectors. */
4879 
4880   if (type == NULL || strcmp (type, "0") == 0)
4881     {
4882       char *selector_uuid;
4883 
4884       if (all_selector)
4885         selector_uuid = NULL;
4886       else
4887         {
4888           selector_uuid = gvm_uuid_make ();
4889           if (selector_uuid == NULL)
4890             {
4891               g_warning ("%s: failed to allocate UUID", __func__);
4892               sql_rollback ();
4893               return;
4894             }
4895         }
4896 
4897       sql ("DELETE FROM nvt_selectors"
4898            " WHERE name != '" MANAGE_NVT_SELECTOR_UUID_ALL "'"
4899            " AND name = (SELECT nvt_selector FROM configs"
4900            "             WHERE id = %llu);",
4901            config);
4902 
4903       sql ("UPDATE configs SET nvt_selector = '%s' WHERE id = %llu;",
4904            selector_uuid ? selector_uuid : MANAGE_NVT_SELECTOR_UUID_ALL,
4905            config);
4906 
4907       if (selector_uuid && insert_nvt_selectors (selector_uuid, selectors, 0))
4908         {
4909           g_warning ("%s: Error in feed config NVT selector", __func__);
4910           free (selector_uuid);
4911           sql_rollback ();
4912           return;
4913         }
4914 
4915       free (selector_uuid);
4916     }
4917 
4918   /* Replace the preferences. */
4919 
4920   sql ("DELETE FROM config_preferences WHERE config = %llu;", config);
4921   if (config_insert_preferences (config, preferences, type))
4922     {
4923       g_warning ("%s: Error in feed config preference", __func__);
4924       sql_rollback ();
4925       return;
4926     }
4927 
4928   sql_commit ();
4929 }
4930 
4931 /**
4932  * @brief Check configs, for startup.
4933  */
4934 void
check_db_configs()4935 check_db_configs ()
4936 {
4937   migrate_predefined_configs ();
4938 
4939   if (sync_configs_with_feed (FALSE) <= -1)
4940     g_warning ("%s: Failed to sync configs with feed", __func__);
4941 
4942   /* Warn about feed resources in the trash. */
4943   if (sql_int ("SELECT EXISTS (SELECT * FROM configs_trash"
4944                "               WHERE predefined = 1);"))
4945     {
4946       g_warning ("%s: There are feed configs/policies in the trash."
4947                  " These will be excluded from the sync.",
4948                  __func__);
4949     }
4950 }
4951 
4952 /**
4953  * @brief Check whole-only families.
4954  *
4955  * Called after NVT sync.
4956  */
4957 void
check_whole_only_in_configs()4958 check_whole_only_in_configs ()
4959 {
4960   static const gchar *wholes[] = FAMILIES_WHOLE_ONLY;
4961 
4962   for (const gchar **whole = wholes; *whole; whole++)
4963     {
4964       gchar *quoted_family;
4965 
4966       quoted_family = sql_quote (*whole);
4967 
4968       /* Delete any excluding NVT selectors. */
4969 
4970       sql ("DELETE FROM nvt_selectors"
4971            " WHERE type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
4972            " AND exclude = 1"
4973            " AND EXISTS (SELECT * FROM nvts"
4974            "             WHERE oid = family_or_nvt"
4975            "             AND family = '%s');",
4976            quoted_family);
4977 
4978       /* Convert any including NVT selectors to family selectors. */
4979 
4980       sql ("WITH sels AS (DELETE FROM nvt_selectors"
4981            "                     WHERE type = " G_STRINGIFY (NVT_SELECTOR_TYPE_NVT)
4982            "              AND EXISTS (SELECT * FROM nvts"
4983            "                          WHERE oid = family_or_nvt"
4984            "                          AND family = '%s')"
4985            "              RETURNING name),"
4986            "     names AS (SELECT distinct * FROM sels)"
4987            " INSERT INTO nvt_selectors"
4988            " (name, exclude, type, family_or_nvt, family)"
4989            " SELECT names.name, 0, " G_STRINGIFY (NVT_SELECTOR_TYPE_FAMILY) ","
4990            "        '%s', '%s'"
4991            " FROM names;",
4992            quoted_family,
4993            quoted_family,
4994            quoted_family);
4995 
4996       g_free (quoted_family);
4997     }
4998 }
4999