1 /* Copyright (C) 2018-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 gmp_configs.c
21 * @brief GVM GMP layer: Configs
22 *
23 * GMP configs.
24 */
25
26 #include "gmp_configs.h"
27 #include "gmp_base.h"
28 #include "gmp_get.h"
29 #include "manage_acl.h"
30 #include "manage_configs.h"
31
32 #include <assert.h>
33 #include <glib.h>
34 #include <stdlib.h>
35 #include <string.h>
36
37 #include <gvm/util/xmlutils.h>
38
39 #undef G_LOG_DOMAIN
40 /**
41 * @brief GLib log domain.
42 */
43 #define G_LOG_DOMAIN "md gmp"
44
45
46 /* Helpers. */
47
48 /**
49 * @brief Create a new NVT selector.
50 *
51 * @param[in] name Name of NVT selector.
52 * @param[in] type Type of NVT selector.
53 * @param[in] include Include/exclude flag.
54 * @param[in] family_or_nvt Family or NVT.
55 *
56 * @return Newly allocated NVT selector.
57 */
58 static gpointer
nvt_selector_new(char * name,char * type,int include,char * family_or_nvt)59 nvt_selector_new (char *name, char *type, int include, char *family_or_nvt)
60 {
61 nvt_selector_t *selector;
62
63 selector = (nvt_selector_t*) g_malloc0 (sizeof (nvt_selector_t));
64 selector->name = name;
65 selector->type = type;
66 selector->include = include;
67 selector->family_or_nvt = family_or_nvt;
68
69 return selector;
70 }
71
72
73 /* CREATE_CONFIG. */
74
75 /**
76 * @brief The create_config command.
77 */
78 typedef struct
79 {
80 context_data_t *context; ///< XML parser context.
81 } create_config_t;
82
83 /**
84 * @brief Parser callback data.
85 *
86 * This is initially 0 because it's a global variable.
87 */
88 static create_config_t create_config_data;
89
90 /**
91 * @brief Reset command data.
92 */
93 static void
create_config_reset()94 create_config_reset ()
95 {
96 if (create_config_data.context->first)
97 {
98 free_entity (create_config_data.context->first->data);
99 g_slist_free_1 (create_config_data.context->first);
100 }
101 g_free (create_config_data.context);
102 memset (&create_config_data, 0, sizeof (create_config_t));
103 }
104
105 /**
106 * @brief Start a command.
107 *
108 * @param[in] gmp_parser GMP parser.
109 * @param[in] attribute_names All attribute names.
110 * @param[in] attribute_values All attribute values.
111 */
112 void
create_config_start(gmp_parser_t * gmp_parser,const gchar ** attribute_names,const gchar ** attribute_values)113 create_config_start (gmp_parser_t *gmp_parser,
114 const gchar **attribute_names,
115 const gchar **attribute_values)
116 {
117 memset (&create_config_data, 0, sizeof (create_config_t));
118 create_config_data.context = g_malloc0 (sizeof (context_data_t));
119 create_config_element_start (gmp_parser, "create_config", attribute_names,
120 attribute_values);
121 }
122
123 /**
124 * @brief Start element.
125 *
126 * @param[in] gmp_parser GMP parser.
127 * @param[in] name Element name.
128 * @param[in] attribute_names All attribute names.
129 * @param[in] attribute_values All attribute values.
130 */
131 void
create_config_element_start(gmp_parser_t * gmp_parser,const gchar * name,const gchar ** attribute_names,const gchar ** attribute_values)132 create_config_element_start (gmp_parser_t *gmp_parser, const gchar *name,
133 const gchar **attribute_names,
134 const gchar **attribute_values)
135 {
136 xml_handle_start_element (create_config_data.context, name, attribute_names,
137 attribute_values);
138 }
139
140 /**
141 * @brief Get the text of entity.
142 *
143 * @param[in] entity Entity. Can be NULL.
144 *
145 * @return Entity text if there's an entity, else NULL.
146 */
147 static gchar*
text_or_null(entity_t entity)148 text_or_null (entity_t entity)
149 {
150 if (entity
151 && strlen (entity_text (entity)))
152 return entity_text (entity);
153 return NULL;
154 }
155
156 /**
157 * @brief Get the attribute of entity.
158 *
159 * @param[in] entity Entity. Can be NULL.
160 * @param[in] name Name of attribute.
161 *
162 * @return Entity attribute if there's an entity, else NULL.
163 */
164 static gchar *
attr_or_null(entity_t entity,const gchar * name)165 attr_or_null (entity_t entity, const gchar *name)
166 {
167 assert (name);
168
169 if (entity)
170 return (gchar*) entity_attribute (entity, name);
171 return NULL;
172 }
173
174 /**
175 * @brief Get creation data from a config entity.
176 *
177 * @param[in] config Config entity.
178 * @param[out] config_id Address for config ID, or NULL.
179 * @param[out] name Address for name.
180 * @param[out] comment Address for comment.
181 * @param[out] type Address for type.
182 * @param[out] usage_type Address for usage type.
183 * @param[out] all_selector True if ALL_SELECTOR was present.
184 * @param[out] import_nvt_selectors Address for selectors.
185 * @param[out] import_preferences Address for preferences.
186 *
187 * @return 0 success, 1 preference did no exist, -1 preference without ID.
188 */
189 int
parse_config_entity(entity_t config,const char ** config_id,char ** name,char ** comment,char ** type,char ** usage_type,int * all_selector,array_t ** import_nvt_selectors,array_t ** import_preferences)190 parse_config_entity (entity_t config, const char **config_id, char **name,
191 char **comment, char **type, char **usage_type,
192 int *all_selector,
193 array_t **import_nvt_selectors,
194 array_t **import_preferences)
195 {
196 entity_t entity, preferences, nvt_selectors;
197
198 *name = *comment = *type = NULL;
199 *all_selector = 0;
200
201 if (config_id)
202 *config_id = entity_attribute (config, "id");
203
204 entity = entity_child (config, "name");
205 if (entity)
206 *name = entity_text (entity);
207
208 entity = entity_child (config, "comment");
209 if (entity)
210 *comment = entity_text (entity);
211
212 entity = entity_child (config, "type");
213 if (entity)
214 *type = entity_text (entity);
215
216 if (usage_type)
217 {
218 entity = entity_child (config, "usage_type");
219 if (entity)
220 *usage_type = entity_text (entity);
221 else
222 *usage_type = NULL;
223 }
224
225 /* Collect NVT selectors. */
226
227 *import_nvt_selectors = NULL;
228 nvt_selectors = entity_child (config, "nvt_selectors");
229 if (nvt_selectors)
230 {
231 entity_t nvt_selector;
232 entities_t children;
233
234 *import_nvt_selectors = make_array ();
235 children = nvt_selectors->entities;
236 while ((nvt_selector = first_entity (children)))
237 {
238 entity_t include, selector_name, selector_type, selector_fam;
239 int import_include;
240
241 if (strcmp (entity_name (nvt_selector), "all_selector") == 0)
242 {
243 array_free (*import_nvt_selectors);
244 *import_nvt_selectors = NULL;
245 *all_selector = 1;
246 break;
247 }
248
249 include = entity_child (nvt_selector, "include");
250 if (include && strcmp (entity_text (include), "0") == 0)
251 import_include = 0;
252 else
253 import_include = 1;
254
255 selector_name = entity_child (nvt_selector, "name");
256 selector_type = entity_child (nvt_selector, "type");
257 selector_fam = entity_child (nvt_selector, "family_or_nvt");
258
259 array_add (*import_nvt_selectors,
260 nvt_selector_new (text_or_null (selector_name),
261 text_or_null (selector_type),
262 import_include,
263 text_or_null (selector_fam)));
264
265 children = next_entities (children);
266 }
267
268 if (*import_nvt_selectors)
269 array_terminate (*import_nvt_selectors);
270 }
271
272 /* Collect NVT preferences. */
273
274 *import_preferences = NULL;
275 preferences = entity_child (config, "preferences");
276 if (preferences)
277 {
278 entity_t preference;
279 entities_t children;
280
281 *import_preferences = make_array ();
282 children = preferences->entities;
283 while ((preference = first_entity (children)))
284 {
285 entity_t pref_name, pref_nvt_name, hr_name, nvt, alt;
286 char *preference_hr_name, *preference_nvt_oid;
287 array_t *import_alts;
288 entities_t alts;
289 preference_t *new_preference;
290
291 pref_name = entity_child (preference, "name");
292
293 pref_nvt_name = NULL;
294 nvt = entity_child (preference, "nvt");
295 if (nvt)
296 pref_nvt_name = entity_child (nvt, "name");
297
298 hr_name = entity_child (preference, "hr_name");
299 if (*type == NULL || strcmp (*type, "0") == 0)
300 /* Classic OpenVAS config preference. */
301 preference_hr_name = NULL;
302 else if (hr_name && strlen (entity_text (hr_name)))
303 /* OSP config preference with hr_name given. */
304 preference_hr_name = entity_text (hr_name);
305 else
306 /* Old OSP config without hr_name. */
307 preference_hr_name = text_or_null (pref_name);
308
309 import_alts = make_array ();
310 alts = preference->entities;
311 while ((alt = first_entity (alts)))
312 {
313 if (strcasecmp (entity_name (alt), "ALT") == 0)
314 array_add (import_alts, text_or_null (alt));
315 alts = next_entities (alts);
316 }
317 array_terminate (import_alts);
318
319 preference_nvt_oid = attr_or_null (nvt, "oid");
320
321 if ((*type == NULL || strcmp (*type, "0") == 0)
322 && preference_nvt_oid
323 && strcmp (preference_nvt_oid, ""))
324 {
325 /* Preference in an OpenVAS config:
326 * Get the preference from nvt_preferences */
327 char *preference_id, *preference_name, *preference_type;
328 char *preference_value;
329
330 preference_id
331 = text_or_null (entity_child (preference, "id"));
332 preference_name
333 = text_or_null (entity_child (preference, "name"));
334 preference_type
335 = text_or_null (entity_child (preference, "type"));
336 preference_value
337 = text_or_null (entity_child (preference, "value"));
338
339 if (preference_id && strcmp (preference_id, ""))
340 {
341 new_preference
342 = get_nvt_preference_by_id (preference_nvt_oid,
343 preference_id,
344 preference_name,
345 preference_type,
346 preference_value ?: "");
347 }
348 else
349 {
350 g_warning ("%s: Config contains a preference for NVT %s"
351 " without a preference id: %s",
352 __func__,
353 preference_nvt_oid,
354 preference_name);
355
356 cleanup_import_preferences (*import_preferences);
357 array_free (*import_nvt_selectors);
358
359 return -1;
360 }
361 }
362 else
363 {
364 /* Scanner preference (for OpenVAS or OSP configs):
365 * Use directly from imported config.
366 */
367 new_preference
368 = preference_new
369 (text_or_null (entity_child (preference, "id")),
370 text_or_null (pref_name),
371 text_or_null (entity_child (preference, "type")),
372 text_or_null (entity_child (preference, "value")),
373 text_or_null (pref_nvt_name),
374 preference_nvt_oid,
375 import_alts,
376 text_or_null (entity_child (preference, "default")),
377 preference_hr_name,
378 0 /* do not free strings */);
379 }
380
381 array_add (*import_preferences, new_preference);
382
383 children = next_entities (children);
384 }
385
386 array_terminate (*import_preferences);
387 }
388
389 return 0;
390 }
391
392 /**
393 * @brief Execute command.
394 *
395 * @param[in] gmp_parser GMP parser.
396 * @param[in] error Error parameter.
397 */
398 void
create_config_run(gmp_parser_t * gmp_parser,GError ** error)399 create_config_run (gmp_parser_t *gmp_parser, GError **error)
400 {
401 entity_t entity, get_configs_response, config, name, copy, scanner;
402
403 entity = (entity_t) create_config_data.context->first->data;
404
405 /* For now the import element, GET_CONFIGS_RESPONSE, overrides
406 * any other elements. */
407
408 get_configs_response = entity_child (entity, "get_configs_response");
409 if (get_configs_response
410 && (config = entity_child (get_configs_response, "config")))
411 {
412 config_t new_config;
413 const char *usage_type_text;
414 char *created_name, *comment, *type, *import_name;
415 entity_t usage_type;
416 array_t *import_nvt_selectors, *import_preferences;
417 int all_selector;
418
419 /* Allow user to overwrite usage type. */
420 usage_type = entity_child (entity, "usage_type");
421 if (usage_type && strcmp (entity_text (usage_type), ""))
422 usage_type_text = entity_text (usage_type);
423 else
424 {
425 usage_type = entity_child (config, "usage_type");
426 if (usage_type)
427 usage_type_text = entity_text (usage_type);
428 else
429 usage_type_text = NULL;
430 }
431
432 /* Get the config data from the XML. */
433
434 if (parse_config_entity (config, NULL, &import_name, &comment, &type,
435 NULL, &all_selector, &import_nvt_selectors,
436 &import_preferences))
437 {
438 SEND_TO_CLIENT_OR_FAIL
439 (XML_ERROR_SYNTAX ("create_config",
440 "Error in PREFERENCES element."));
441 log_event_fail ("config", "Scan config", NULL, "created");
442
443 /* Cleanup. */
444
445 create_config_reset ();
446 return;
447 }
448
449 /* Create config. */
450
451 switch (create_config (NULL, /* Generate a UUID. */
452 import_name,
453 1, /* Make name unique. */
454 comment,
455 all_selector,
456 import_nvt_selectors,
457 import_preferences,
458 type,
459 usage_type_text,
460 &new_config,
461 &created_name))
462 {
463 case 0:
464 {
465 gchar *uuid = config_uuid (new_config);
466 SENDF_TO_CLIENT_OR_FAIL
467 ("<create_config_response"
468 " status=\"" STATUS_OK_CREATED "\""
469 " status_text=\"" STATUS_OK_CREATED_TEXT "\""
470 " id=\"%s\">"
471 /* This is a hack for the GSA, which should really
472 * do a GET_CONFIG with the ID to get the name. */
473 "<config id=\"%s\"><name>%s</name></config>"
474 "</create_config_response>",
475 uuid,
476 uuid,
477 created_name);
478 log_event ("config", "Scan config", uuid, "created");
479 g_free (uuid);
480 free (created_name);
481 break;
482 }
483 case 1:
484 SEND_TO_CLIENT_OR_FAIL
485 (XML_ERROR_SYNTAX ("create_config",
486 "Config exists already"));
487 log_event_fail ("config", "Scan config", NULL, "created");
488 break;
489 case 99:
490 SEND_TO_CLIENT_OR_FAIL
491 (XML_ERROR_SYNTAX ("create_config",
492 "Permission denied"));
493 log_event_fail ("config", "Scan config", NULL, "created");
494 break;
495 case -1:
496 SEND_TO_CLIENT_OR_FAIL
497 (XML_INTERNAL_ERROR ("create_config"));
498 log_event_fail ("config", "Scan config", NULL, "created");
499 break;
500 case -2:
501 SEND_TO_CLIENT_OR_FAIL
502 (XML_ERROR_SYNTAX ("create_config",
503 "Import name must be at"
504 " least one character long"));
505 log_event_fail ("config", "Scan config", NULL, "created");
506 break;
507 case -3:
508 SEND_TO_CLIENT_OR_FAIL
509 (XML_ERROR_SYNTAX ("create_config",
510 "Error in NVT_SELECTORS element."));
511 log_event_fail ("config", "Scan config", NULL, "created");
512 break;
513 case -4:
514 SEND_TO_CLIENT_OR_FAIL
515 (XML_ERROR_SYNTAX ("create_config",
516 "Error in PREFERENCES element."));
517 log_event_fail ("config", "Scan config", NULL, "created");
518 break;
519 }
520
521 /* Cleanup. */
522
523 cleanup_import_preferences (import_preferences);
524 array_free (import_nvt_selectors);
525
526 create_config_reset ();
527 return;
528 }
529
530 /* Check for creation from scanner. */
531
532 scanner = entity_child (entity, "scanner");
533 if (scanner && strlen (entity_text (scanner)))
534 {
535 char *uuid;
536
537 uuid = NULL;
538
539 switch (create_config_from_scanner
540 (entity_text (scanner),
541 text_or_null (entity_child (entity, "name")),
542 text_or_null (entity_child (entity, "comment")),
543 text_or_null (entity_child (entity, "usage_type")),
544 &uuid))
545 {
546 case 0:
547 SENDF_TO_CLIENT_OR_FAIL (XML_OK_CREATED_ID
548 ("create_config"), uuid);
549 log_event ("config", "Scan config", uuid, "created");
550 break;
551 case 1:
552 SENDF_TO_CLIENT_OR_FAIL
553 (XML_ERROR_SYNTAX ("create_config",
554 "Failed to find scanner"));
555 break;
556 case 2:
557 SENDF_TO_CLIENT_OR_FAIL
558 (XML_ERROR_SYNTAX ("create_config",
559 "Scanner not of type OSP"));
560 break;
561 case 3:
562 SENDF_TO_CLIENT_OR_FAIL
563 (XML_ERROR_SYNTAX ("create_config",
564 "Config name exists already"));
565 break;
566 case 4:
567 SENDF_TO_CLIENT_OR_FAIL
568 (XML_ERROR_SYNTAX ("create_config",
569 "Failed to get params from scanner"
570 " - the scanner may be offline or not"
571 " configured correctly"));
572 break;
573 case 99:
574 SEND_TO_CLIENT_OR_FAIL
575 (XML_ERROR_SYNTAX ("create_config",
576 "Permission denied"));
577 log_event_fail ("config", "Scan config", NULL, "created");
578 break;
579 case -1:
580 default:
581 SEND_TO_CLIENT_OR_FAIL
582 (XML_INTERNAL_ERROR ("create_config"));
583 log_event_fail ("config", "Scan config", NULL, "created");
584 break;
585 }
586 g_free (uuid);
587
588 create_config_reset ();
589 return;
590 }
591
592 /* Try copy from an existing config. */
593
594 copy = entity_child (entity, "copy");
595 name = entity_child (entity, "name");
596
597 if (((name == NULL) || (strlen (entity_text (name)) == 0))
598 && ((copy == NULL) || (strlen (entity_text (copy)) == 0)))
599 {
600 log_event_fail ("config", "Scan config", NULL, "created");
601 SEND_TO_CLIENT_OR_FAIL
602 (XML_ERROR_SYNTAX ("create_config",
603 "Name and base config to copy"
604 " must be at least one character long"));
605 }
606 else if (copy == NULL)
607 {
608 log_event_fail ("config", "Scan config", NULL, "created");
609 SEND_TO_CLIENT_OR_FAIL
610 (XML_ERROR_SYNTAX ("create_config",
611 "A COPY element is required"));
612 }
613 else
614 {
615 config_t new_config;
616 entity_t comment, usage_type;
617
618 comment = entity_child (entity, "comment");
619 usage_type = entity_child (entity, "usage_type");
620
621 switch (copy_config (entity_text (name),
622 comment ? entity_text (comment) : "",
623 entity_text (copy),
624 usage_type ? entity_text (usage_type) : NULL,
625 &new_config))
626 {
627 case 0:
628 {
629 char *uuid = config_uuid (new_config);
630 SENDF_TO_CLIENT_OR_FAIL (XML_OK_CREATED_ID ("create_config"),
631 uuid);
632 log_event ("config", "Scan config", uuid, "created");
633 free (uuid);
634 break;
635 }
636 case 1:
637 SEND_TO_CLIENT_OR_FAIL
638 (XML_ERROR_SYNTAX ("create_config",
639 "Config exists already"));
640 log_event_fail ("config", "Scan config", NULL, "created");
641 break;
642 case 2:
643 if (send_find_error_to_client ("create_config", "config",
644 entity_text (copy),
645 gmp_parser))
646 {
647 error_send_to_client (error);
648 return;
649 }
650 log_event_fail ("config", "Config", NULL, "created");
651 break;
652 case 99:
653 SEND_TO_CLIENT_OR_FAIL
654 (XML_ERROR_SYNTAX ("create_config",
655 "Permission denied"));
656 log_event_fail ("config", "Scan config", NULL, "created");
657 break;
658 case -1:
659 default:
660 SEND_TO_CLIENT_OR_FAIL
661 (XML_INTERNAL_ERROR ("create_config"));
662 log_event_fail ("config", "Scan config", NULL, "created");
663 break;
664 }
665 }
666
667 create_config_reset ();
668 }
669
670 /**
671 * @brief End element.
672 *
673 * @param[in] gmp_parser GMP parser.
674 * @param[in] error Error parameter.
675 * @param[in] name Element name.
676 *
677 * @return 0 success, 1 command finished.
678 */
679 int
create_config_element_end(gmp_parser_t * gmp_parser,GError ** error,const gchar * name)680 create_config_element_end (gmp_parser_t *gmp_parser, GError **error,
681 const gchar *name)
682 {
683 xml_handle_end_element (create_config_data.context, name);
684 if (create_config_data.context->done)
685 {
686 create_config_run (gmp_parser, error);
687 return 1;
688 }
689 return 0;
690 }
691
692 /**
693 * @brief Add text to element.
694 *
695 * @param[in] text Text.
696 * @param[in] text_len Text length.
697 */
698 void
create_config_element_text(const gchar * text,gsize text_len)699 create_config_element_text (const gchar *text, gsize text_len)
700 {
701 xml_handle_text (create_config_data.context, text, text_len);
702 }
703
704
705 /* MODIFY_CONFIG. */
706
707 /**
708 * @brief The modify_config command.
709 */
710 typedef struct
711 {
712 context_data_t *context; ///< XML parser context.
713 } modify_config_t;
714
715 /**
716 * @brief Parser callback data.
717 *
718 * This is initially 0 because it's a global variable.
719 */
720 static modify_config_t modify_config_data;
721
722 /**
723 * @brief Reset command data.
724 */
725 static void
modify_config_reset()726 modify_config_reset ()
727 {
728 if (modify_config_data.context->first)
729 {
730 free_entity (modify_config_data.context->first->data);
731 g_slist_free_1 (modify_config_data.context->first);
732 }
733 g_free (modify_config_data.context);
734 memset (&modify_config_data, 0, sizeof (modify_config_t));
735 }
736
737 /**
738 * @brief Start a command.
739 *
740 * @param[in] gmp_parser GMP parser.
741 * @param[in] attribute_names All attribute names.
742 * @param[in] attribute_values All attribute values.
743 */
744 void
modify_config_start(gmp_parser_t * gmp_parser,const gchar ** attribute_names,const gchar ** attribute_values)745 modify_config_start (gmp_parser_t *gmp_parser,
746 const gchar **attribute_names,
747 const gchar **attribute_values)
748 {
749 memset (&modify_config_data, 0, sizeof (modify_config_t));
750 modify_config_data.context = g_malloc0 (sizeof (context_data_t));
751 modify_config_element_start (gmp_parser, "modify_config", attribute_names,
752 attribute_values);
753 }
754
755 /**
756 * @brief Start element.
757 *
758 * @param[in] gmp_parser GMP parser.
759 * @param[in] name Element name.
760 * @param[in] attribute_names All attribute names.
761 * @param[in] attribute_values All attribute values.
762 */
763 void
modify_config_element_start(gmp_parser_t * gmp_parser,const gchar * name,const gchar ** attribute_names,const gchar ** attribute_values)764 modify_config_element_start (gmp_parser_t *gmp_parser, const gchar *name,
765 const gchar **attribute_names,
766 const gchar **attribute_values)
767 {
768 xml_handle_start_element (modify_config_data.context, name, attribute_names,
769 attribute_values);
770 }
771
772 /**
773 * @brief Handle basic, single-value fields of modify_config.
774 *
775 * @param[in] config The config to modify.
776 * @param[in] name The name to set or NULL to keep old value.
777 * @param[in] comment The comment to set or NULL to keep old value.
778 * @param[in] scanner_id The scanner ID to set or NULL to keep old value.
779 * @param[in] gmp_parser GMP parser.
780 * @param[out] error GError output.
781 *
782 * @return 0 on success, -1 on error.
783 */
784 static int
modify_config_handle_basic_fields(config_t config,const char * name,const char * comment,const char * scanner_id,gmp_parser_t * gmp_parser,GError ** error)785 modify_config_handle_basic_fields (config_t config,
786 const char *name,
787 const char *comment,
788 const char *scanner_id,
789 gmp_parser_t *gmp_parser,
790 GError **error)
791 {
792 switch (manage_set_config (config, name, comment, scanner_id))
793 {
794 case 0:
795 return 0;
796 case 1:
797 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
798 (-1, XML_ERROR_SYNTAX ("modify_config", "Name must be unique"));
799 return -1;
800 case 2:
801 if (send_find_error_to_client ("modify_config",
802 "scanner",
803 scanner_id,
804 gmp_parser))
805 {
806 error_send_to_client (error);
807 return -1;
808 }
809 return -1;
810 case 3:
811 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
812 (-1, XML_ERROR_SYNTAX ("modify_config", "Config is in use"));
813 return -1;
814 case -1:
815 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
816 (-1, XML_INTERNAL_ERROR ("modify_config"));
817 return -1;
818 default:
819 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
820 (-1, XML_INTERNAL_ERROR ("modify_config"));
821 return -1;
822 }
823 }
824
825 /**
826 * @brief Collect VT families from parsed modify_config XML into arrays.
827 *
828 * Family name strings are to be freed with entity.
829 * VT families not collected are assumed to be static and empty.
830 *
831 * @param[in] entities The entities struct with family elems as children.
832 * @param[out] families_growing_all Array of growing families with all VTs.
833 * @param[out] families_growing_empty Array of growing, empty families.
834 * @param[out] families_static_all Array of static families with all VTs.
835 *
836 * @return 0 on success, -1 on error.
837 */
838 static int
modify_config_collect_selection_families(entities_t entities,array_t ** families_growing_all,array_t ** families_growing_empty,array_t ** families_static_all)839 modify_config_collect_selection_families (entities_t entities,
840 array_t **families_growing_all,
841 array_t **families_growing_empty,
842 array_t **families_static_all)
843 {
844 entities_t iter_entities;
845 entity_t entity;
846
847 assert (families_growing_all);
848 assert (families_growing_empty);
849 assert (families_static_all);
850
851 *families_growing_all = make_array ();
852 *families_growing_empty = make_array ();
853 *families_static_all = make_array ();
854
855 iter_entities = entities;
856 while ((entity = first_entity (iter_entities)))
857 {
858 if (strcmp (entity_name (entity), "family") == 0)
859 {
860 char *name, *growing_str, *all_str;
861 name = text_or_null (entity_child (entity, "name"));
862 all_str = text_or_null (entity_child (entity, "all"));
863 growing_str = text_or_null (entity_child (entity, "growing"));
864
865 if (growing_str && strcmp (growing_str, "0"))
866 {
867 if (all_str && strcmp (all_str, "0"))
868 array_add (*families_growing_all, name);
869 else
870 array_add (*families_growing_empty, name);
871 }
872 else if (all_str && strcmp (all_str, "0"))
873 array_add (*families_static_all, name);
874 }
875 iter_entities = next_entities (iter_entities);
876 }
877
878 array_terminate (*families_growing_all);
879 array_terminate (*families_growing_empty);
880 array_terminate (*families_static_all);
881
882 return 0;
883 }
884
885 /**
886 * @brief Handles a family selection inside a modify_config command.
887 *
888 * @param[in] config The config to modify.
889 * @param[in] families_growing_all Array of growing families with all VTs.
890 * @param[in] families_growing_empty Array of growing, empty families.
891 * @param[in] families_static_all Array of static families with all VTs.
892 * @param[in] family_selection_growing 1 if families should grow, else 0.
893 * @param[in] gmp_parser The GMP parser.
894 * @param[out] error GError output.
895 *
896 * @return 0 on success, -1 on error.
897 */
898 static int
modify_config_handle_family_selection(config_t config,array_t * families_growing_all,array_t * families_growing_empty,array_t * families_static_all,int family_selection_growing,gmp_parser_t * gmp_parser,GError ** error)899 modify_config_handle_family_selection (config_t config,
900 array_t *families_growing_all,
901 array_t *families_growing_empty,
902 array_t *families_static_all,
903 int family_selection_growing,
904 gmp_parser_t *gmp_parser,
905 GError **error)
906 {
907 gchar *rejected_family;
908
909 switch (manage_set_config_families
910 (config,
911 families_growing_all,
912 families_static_all,
913 families_growing_empty,
914 family_selection_growing,
915 &rejected_family))
916 {
917 case 0:
918 return 0;
919 case 1:
920 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
921 (-1, XML_ERROR_SYNTAX ("modify_config", "Config is in use"));
922 return -1;
923 case 2:
924 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
925 (-1,
926 XML_ERROR_SYNTAX ("modify_config",
927 "Family "%s" must be growing and"
928 " include all VTs or it must be static and"
929 " empty."),
930 rejected_family);
931 g_free (rejected_family);
932 return -1;
933 case -1:
934 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
935 (-1, XML_INTERNAL_ERROR ("modify_config"));
936 return -1;
937 default:
938 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
939 (-1, XML_INTERNAL_ERROR ("modify_config"));
940 return -1;
941 }
942 }
943
944 /**
945 * @brief Collect a list of VT OIDs for a particular family in modify_config.
946 *
947 * @param[in] entities The entities containing nvt elements as children.
948 * @param[out] nvt_oids The list of VT OIDs to select.
949 *
950 * @return 0 on success, -1 on error.
951 */
952 static int
modify_config_collect_selection_nvts(entities_t entities,array_t ** nvt_oids)953 modify_config_collect_selection_nvts (entities_t entities,
954 array_t **nvt_oids)
955 {
956 entities_t iter_entities;
957 entity_t entity;
958
959 assert (entities);
960 assert (nvt_oids);
961
962 *nvt_oids = make_array ();
963
964 iter_entities = entities;
965 while ((entity = first_entity (iter_entities)))
966 {
967 if (strcmp (entity_name (entity), "nvt") == 0)
968 {
969 char *oid;
970 oid = attr_or_null (entity, "oid");
971 if (oid)
972 array_add (*nvt_oids, oid);
973 }
974 iter_entities = next_entities (iter_entities);
975 }
976
977 array_terminate (*nvt_oids);
978
979 return 0;
980 }
981
982 /**
983 * @brief Changes the VT selection of a given family in modify_config.
984 *
985 * @param[in] config The config to modify.
986 * @param[in] nvt_selection_family The family to set the VT selection of.
987 * @param[in] nvt_selection Array of VT OIDs to select of the family.
988 * @param[in] gmp_parser The GMP parser.
989 * @param[out] error GError output.
990 *
991 * @return 0 on success, -1 on error.
992 */
993 static int
modify_config_handle_nvt_selection(config_t config,const char * nvt_selection_family,GPtrArray * nvt_selection,gmp_parser_t * gmp_parser,GError ** error)994 modify_config_handle_nvt_selection (config_t config,
995 const char *nvt_selection_family,
996 GPtrArray *nvt_selection,
997 gmp_parser_t *gmp_parser,
998 GError **error)
999 {
1000 switch (manage_set_config_nvts
1001 (config,
1002 nvt_selection_family,
1003 nvt_selection))
1004 {
1005 case 0:
1006 return 0;
1007 case 1:
1008 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1009 (-1, XML_ERROR_SYNTAX ("modify_config", "Config is in use"));
1010 return -1;
1011 case 2:
1012 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1013 (-1,
1014 XML_ERROR_SYNTAX ("modify_config",
1015 "Attempt to modify NVT in whole-only family %s"),
1016 nvt_selection_family);
1017 return -1;
1018 case -1:
1019 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1020 (-1, XML_INTERNAL_ERROR ("modify_config"));
1021 return -1;
1022 default:
1023 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1024 (-1, XML_INTERNAL_ERROR ("modify_config"));
1025 return -1;
1026 }
1027 }
1028
1029 /**
1030 * @brief Modifies a single preference inside a modify_config command.
1031 *
1032 * @param[in] config The config to modify
1033 * @param[in] nvt_oid VT OID of the preference or NULL for scanner pref.
1034 * @param[in] name Name of the preference to Changes
1035 * @param[in] value Value to set for the preference.
1036 * @param[in] gmp_parser The GMP parser.
1037 * @param[out] error GError output.
1038 *
1039 * @return 0 on success, -1 on error.
1040 */
1041 static int
modify_config_handle_preference(config_t config,const char * nvt_oid,const char * name,const char * value,gmp_parser_t * gmp_parser,GError ** error)1042 modify_config_handle_preference (config_t config,
1043 const char *nvt_oid,
1044 const char *name,
1045 const char *value,
1046 gmp_parser_t *gmp_parser,
1047 GError **error)
1048 {
1049 switch (manage_set_config_preference (config, nvt_oid, name, value))
1050 {
1051 case 0:
1052 return 0;
1053 case 1:
1054 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1055 (-1, XML_ERROR_SYNTAX ("modify_config", "Config is in use"));
1056 return -1;
1057 case 2:
1058 if (nvt_oid)
1059 {
1060 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1061 (-1,
1062 XML_ERROR_SYNTAX ("modify_config",
1063 "Empty radio value for preference %s"
1064 " of NVT %s"),
1065 name,
1066 nvt_oid);
1067 }
1068 else
1069 {
1070 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1071 (-1,
1072 XML_ERROR_SYNTAX ("modify_config",
1073 "Empty radio value for preference %s"),
1074 nvt_oid);
1075 }
1076 return -1;
1077 case -1:
1078 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1079 (-1, XML_INTERNAL_ERROR ("modify_config"));
1080 return -1;
1081 default:
1082 SENDF_TO_CLIENT_OR_FAIL_WITH_RETURN
1083 (-1, XML_INTERNAL_ERROR ("modify_config"));
1084 return -1;
1085 }
1086 }
1087
1088 /**
1089 * @brief Execute command.
1090 *
1091 * @param[in] gmp_parser GMP parser.
1092 * @param[out] error Error parameter.
1093 */
1094 static void
modify_config_run(gmp_parser_t * gmp_parser,GError ** error)1095 modify_config_run (gmp_parser_t *gmp_parser, GError **error)
1096 {
1097 entity_t entity, child;
1098 entities_t children;
1099 const char *config_id;
1100 config_t config;
1101
1102 entity = (entity_t) modify_config_data.context->first->data;
1103
1104 // Check command permission
1105 if (acl_user_may ("modify_config") == 0)
1106 {
1107 SEND_TO_CLIENT_OR_FAIL (XML_ERROR_SYNTAX ("modify_config",
1108 "Permission denied"));
1109 return;
1110 }
1111
1112 config_id = attr_or_null (entity, "config_id");
1113
1114 if (config_id == NULL)
1115 SEND_TO_CLIENT_OR_FAIL
1116 (XML_ERROR_SYNTAX ("modify_config",
1117 "A config_id attribute is required"));
1118 else if (config_predefined_uuid (config_id))
1119 SEND_TO_CLIENT_OR_FAIL (XML_ERROR_SYNTAX ("modify_config",
1120 "Permission denied"));
1121
1122 // Find the config
1123 switch (manage_modify_config_start (config_id, &config))
1124 {
1125 case 0:
1126 break;
1127 case 1:
1128 if (send_find_error_to_client ("modify_config",
1129 "config",
1130 config_id,
1131 gmp_parser))
1132 {
1133 error_send_to_client (error);
1134 return;
1135 }
1136 log_event_fail ("config", "Scan Config", config_id, "modified");
1137 return;
1138 default:
1139 SEND_TO_CLIENT_OR_FAIL
1140 (XML_INTERNAL_ERROR ("modify_config"));
1141 log_event_fail ("config", "Scan Config", config_id, "modified");
1142 }
1143
1144 // Handle basic attributes and elements
1145 if (modify_config_handle_basic_fields
1146 (config,
1147 text_or_null (entity_child (entity, "name")),
1148 text_or_null (entity_child (entity, "comment")),
1149 text_or_null (entity_child (entity, "scanner")),
1150 gmp_parser,
1151 error))
1152 {
1153 manage_modify_config_cancel ();
1154 log_event_fail ("config", "Scan config", config_id, "modified");
1155 return;
1156 }
1157
1158 // Preferences and NVT selections
1159 children = entity->entities;
1160 while ((child = first_entity (children)))
1161 {
1162 if (strcmp (child->name, "family_selection") == 0)
1163 {
1164 array_t *families_growing_all;
1165 array_t *families_growing_empty;
1166 array_t *families_static_all;
1167 const char *growing_str;
1168 int growing;
1169
1170 growing_str = text_or_null (entity_child (child, "growing"));
1171 growing = (growing_str && strcmp (growing_str, "0")) ? 1 : 0;
1172
1173 if (modify_config_collect_selection_families
1174 (child->entities,
1175 &families_growing_all,
1176 &families_growing_empty,
1177 &families_static_all)
1178 || modify_config_handle_family_selection
1179 (config,
1180 families_growing_all,
1181 families_growing_empty,
1182 families_static_all,
1183 growing,
1184 gmp_parser,
1185 error))
1186 {
1187 manage_modify_config_cancel ();
1188 log_event_fail ("config", "Scan config", config_id, "modified");
1189 g_ptr_array_free (families_growing_all, TRUE);
1190 g_ptr_array_free (families_growing_empty, TRUE);
1191 g_ptr_array_free (families_static_all, TRUE);
1192 return;
1193 }
1194 g_ptr_array_free (families_growing_all, TRUE);
1195 g_ptr_array_free (families_growing_empty, TRUE);
1196 g_ptr_array_free (families_static_all, TRUE);
1197 }
1198 else if (strcmp (child->name, "nvt_selection") == 0)
1199 {
1200 array_t *nvt_selection;
1201
1202 if (modify_config_collect_selection_nvts
1203 (child->entities,
1204 &nvt_selection)
1205 || modify_config_handle_nvt_selection
1206 (config,
1207 text_or_null (entity_child (child, "family")),
1208 nvt_selection,
1209 gmp_parser,
1210 error))
1211 {
1212 manage_modify_config_cancel ();
1213 log_event_fail ("config", "Scan config", config_id, "modified");
1214 g_ptr_array_free (nvt_selection, TRUE);
1215 return;
1216 }
1217 g_ptr_array_free (nvt_selection, TRUE);
1218 }
1219 else if (strcmp (child->name, "preference") == 0)
1220 {
1221 if (modify_config_handle_preference
1222 (config,
1223 attr_or_null (entity_child (child, "nvt"), "oid"),
1224 text_or_null (entity_child (child, "name")),
1225 text_or_null (entity_child (child, "value")),
1226 gmp_parser,
1227 error))
1228 {
1229 manage_modify_config_cancel ();
1230 log_event_fail ("config", "Scan config", config_id, "modified");
1231 return;
1232 }
1233 }
1234 children = next_entities (children);
1235 }
1236
1237 manage_modify_config_commit ();
1238 SEND_TO_CLIENT_OR_FAIL (XML_OK ("modify_config"));
1239 log_event ("config", "Scan Config", config_id, "modified");
1240
1241 // Cleanup
1242 modify_config_reset ();
1243 }
1244
1245 /**
1246 * @brief End element.
1247 *
1248 * @param[in] gmp_parser GMP parser.
1249 * @param[in] error Error parameter.
1250 * @param[in] name Element name.
1251 *
1252 * @return 0 success, 1 command finished.
1253 */
1254 int
modify_config_element_end(gmp_parser_t * gmp_parser,GError ** error,const gchar * name)1255 modify_config_element_end (gmp_parser_t *gmp_parser, GError **error,
1256 const gchar *name)
1257 {
1258 xml_handle_end_element (modify_config_data.context, name);
1259 if (modify_config_data.context->done)
1260 {
1261 modify_config_run (gmp_parser, error);
1262 return 1;
1263 }
1264 return 0;
1265 }
1266
1267 /**
1268 * @brief Add text to element.
1269 *
1270 * @param[in] text Text.
1271 * @param[in] text_len Text length.
1272 */
1273 void
modify_config_element_text(const gchar * text,gsize text_len)1274 modify_config_element_text (const gchar *text, gsize text_len)
1275 {
1276 xml_handle_text (modify_config_data.context, text, text_len);
1277 }
1278