1 /* Copyright (C) 2020-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_report_formats.c
21  * @brief GVM management layer: Report format SQL
22  *
23  * The report format SQL for the GVM management layer.
24  */
25 
26 #include "manage_sql_report_formats.h"
27 #include "manage_acl.h"
28 #include "manage_report_formats.h"
29 #include "sql.h"
30 #include "utils.h"
31 
32 #include <errno.h>
33 #include <glib.h>
34 #include <glib/gstdio.h>
35 #include <grp.h>
36 #include <libgen.h>
37 #include <limits.h>
38 #include <locale.h>
39 #include <pwd.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <sys/types.h>
43 #include <sys/wait.h>
44 #include <unistd.h>
45 
46 #include <gvm/base/proctitle.h>
47 #include <gvm/util/uuidutils.h>
48 #include <gvm/util/fileutils.h>
49 
50 #undef G_LOG_DOMAIN
51 /**
52  * @brief GLib log domain.
53  */
54 #define G_LOG_DOMAIN "md manage"
55 
56 
57 /* Non-SQL internals defined in manage_report_formats.c. */
58 
59 int
60 sync_report_formats_with_feed (gboolean);
61 
62 
63 /* Static headers. */
64 
65 static int
66 validate_param_value (report_format_t, report_format_param_t param, const char *,
67                       const char *);
68 
69 static void
70 set_report_format_name (report_format_t, const char *);
71 
72 static void
73 set_report_format_summary (report_format_t, const char *);
74 
75 static void
76 set_report_format_active (report_format_t, int);
77 
78 static int
79 set_report_format_param (report_format_t, const char *, const char *);
80 
81 
82 /* Helpers. */
83 
84 /**
85  * @brief Return the name of the sysconf GnuPG home directory
86  *
87  * Returns the name of the GnuPG home directory to use when checking
88  * signatures.  It is the directory openvas/gnupg under the sysconfdir
89  * that was set by configure (usually $prefix/etc).
90  *
91  * @return Static name of the Sysconf GnuPG home directory.
92  */
93 static const char *
get_sysconf_gpghome()94 get_sysconf_gpghome ()
95 {
96   static char *name;
97 
98   if (!name)
99     name = g_build_filename (GVM_SYSCONF_DIR, "gnupg", NULL);
100 
101   return name;
102 }
103 
104 /**
105  * @brief Return the name of the trusted keys file name.
106  *
107  * We currently use the name pubring.gpg to be compatible with
108  * previous installations.  That file should best be installed
109  * read-only so that it is not accidentally accessed while we are
110  * running a verification.  All files in that keyring are assumed to
111  * be fully trustworthy.
112  *
113  * @return Static file name.
114  */
115 static const char *
get_trustedkeys_name()116 get_trustedkeys_name ()
117 {
118   static char *name;
119 
120   if (!name)
121     name = g_build_filename (get_sysconf_gpghome (), "pubring.gpg", NULL);
122 
123   return name;
124 }
125 
126 
127 /* Predefined resources.
128  *
129  * These are only used by report formats, because report formats from the feed
130  * are automatically trusted, so we need to track them. */
131 
132 /**
133  * @brief Return whether a resource is predefined.
134  *
135  * @param[in]  type      Type of resource.
136  * @param[in]  resource  Resource.
137  *
138  * @return 1 if predefined, else 0.
139  */
140 int
resource_predefined(const gchar * type,resource_t resource)141 resource_predefined (const gchar *type, resource_t resource)
142 {
143   assert (valid_type (type));
144   return sql_int ("SELECT EXISTS (SELECT * FROM resources_predefined"
145                   "               WHERE resource_type = '%s'"
146                   "               AND resource = %llu);",
147                   type,
148                   resource);
149 }
150 
151 
152 /* Signature utils. */
153 
154 /**
155  * @brief Execute gpg to verify an installer signature.
156  *
157  * @param[in]  installer       Installer.
158  * @param[in]  installer_size  Size of installer.
159  * @param[in]  signature       Installer signature.
160  * @param[in]  signature_size  Size of installer signature.
161  * @param[out] trust           Trust value.
162  *
163  * @return 0 success, -1 error.
164  */
165 static int
verify_signature(const gchar * installer,gsize installer_size,const gchar * signature,gsize signature_size,int * trust)166 verify_signature (const gchar *installer, gsize installer_size,
167                   const gchar *signature, gsize signature_size,
168                   int *trust)
169 {
170   gchar **cmd;
171   gint exit_status;
172   int ret = 0, installer_fd, signature_fd;
173   gchar *standard_out = NULL;
174   gchar *standard_err = NULL;
175   char installer_file[] = "/tmp/gvmd-installer-XXXXXX";
176   char signature_file[] = "/tmp/gvmd-signature-XXXXXX";
177   GError *error = NULL;
178 
179   installer_fd = mkstemp (installer_file);
180   if (installer_fd == -1)
181     return -1;
182 
183   g_file_set_contents (installer_file, installer, installer_size, &error);
184   if (error)
185     {
186       g_warning ("%s", error->message);
187       g_error_free (error);
188       close (installer_fd);
189       return -1;
190     }
191 
192   signature_fd = mkstemp (signature_file);
193   if (signature_fd == -1)
194     {
195       close (installer_fd);
196       return -1;
197     }
198 
199   g_file_set_contents (signature_file, signature, signature_size, &error);
200   if (error)
201     {
202       g_warning ("%s", error->message);
203       g_error_free (error);
204       close (installer_fd);
205       close (signature_fd);
206       return -1;
207     }
208 
209   cmd = (gchar **) g_malloc (10 * sizeof (gchar *));
210 
211   cmd[0] = g_strdup ("gpgv");
212   cmd[1] = g_strdup ("--homedir");
213   cmd[2] = g_strdup (get_sysconf_gpghome ());
214   cmd[3] = g_strdup ("--quiet");
215   cmd[4] = g_strdup ("--keyring");
216   cmd[5] = g_strdup (get_trustedkeys_name ());
217   cmd[6] = g_strdup ("--");
218   cmd[7] = g_strdup (signature_file);
219   cmd[8] = g_strdup (installer_file);
220   cmd[9] = NULL;
221   g_debug ("%s: Spawning in /tmp/: %s %s %s %s %s %s %s %s %s",
222            __func__,
223            cmd[0], cmd[1], cmd[2], cmd[3], cmd[4], cmd[5],
224            cmd[6], cmd[7], cmd[8]);
225   if ((g_spawn_sync ("/tmp/",
226                      cmd,
227                      NULL,                 /* Environment. */
228                      G_SPAWN_SEARCH_PATH,
229                      NULL,                 /* Setup func. */
230                      NULL,
231                      &standard_out,
232                      &standard_err,
233                      &exit_status,
234                      NULL) == FALSE)
235       || (WIFEXITED (exit_status) == 0)
236       || WEXITSTATUS (exit_status))
237     {
238       if (WEXITSTATUS (exit_status) == 1)
239         *trust = TRUST_NO;
240       else
241         {
242           /* This can be caused by the contents of the signature file, so
243            * always return success. */
244           *trust = TRUST_UNKNOWN;
245         }
246     }
247   else
248     *trust = TRUST_YES;
249 
250   g_free (cmd[0]);
251   g_free (cmd[1]);
252   g_free (cmd[2]);
253   g_free (cmd[3]);
254   g_free (cmd[4]);
255   g_free (cmd[5]);
256   g_free (cmd[6]);
257   g_free (cmd[7]);
258   g_free (cmd[8]);
259   g_free (cmd);
260   g_free (standard_out);
261   g_free (standard_err);
262   close (installer_fd);
263   close (signature_fd);
264   g_remove (installer_file);
265   g_remove (signature_file);
266 
267   return ret;
268 }
269 
270 /**
271  * @brief Find a signature in a feed.
272  *
273  * @param[in]   location            Feed directory to search for signature.
274  * @param[in]   installer_filename  Installer filename.
275  * @param[out]  signature           Freshly allocated installer signature.
276  * @param[out]  signature_size      Size of installer signature.
277  * @param[out]  uuid                Address for basename of linked signature
278  *                                  when the signature was found in the private
279  *                                  directory, if desired, else NULL.  Private
280  *                                  directory is only checked if this is given.
281  *
282  * @return 0 success, -1 error.
283  */
284 static int
find_signature(const gchar * location,const gchar * installer_filename,gchar ** signature,gsize * signature_size,gchar ** uuid)285 find_signature (const gchar *location, const gchar *installer_filename,
286                 gchar **signature, gsize *signature_size, gchar **uuid)
287 {
288   gchar *installer_basename;
289 
290   installer_basename = g_path_get_basename (installer_filename);
291 
292   if (uuid)
293     *uuid = NULL;
294 
295   if (strlen (installer_basename))
296     {
297       gchar *signature_filename, *signature_basename;
298       GError *error = NULL;
299 
300       signature_basename  = g_strdup_printf ("%s.asc", installer_basename);
301       g_free (installer_basename);
302       signature_filename = g_build_filename (GVM_NVT_DIR,
303                                              location,
304                                              signature_basename,
305                                              NULL);
306       g_debug ("signature_filename: %s", signature_filename);
307 
308       g_file_get_contents (signature_filename, signature, signature_size,
309                            &error);
310       if (error)
311         {
312           if (uuid && (error->code == G_FILE_ERROR_NOENT))
313             {
314               char *real;
315               gchar *real_basename;
316               gchar **split;
317 
318               g_error_free (error);
319               error = NULL;
320               signature_filename = g_build_filename (GVMD_STATE_DIR,
321                                                      "signatures",
322                                                      location,
323                                                      signature_basename,
324                                                      NULL);
325               g_debug ("signature_filename (private): %s", signature_filename);
326               g_free (signature_basename);
327               g_file_get_contents (signature_filename, signature, signature_size,
328                                    &error);
329               if (error)
330                 {
331                   g_free (signature_filename);
332                   g_error_free (error);
333                   return -1;
334                 }
335 
336               real = realpath (signature_filename, NULL);
337               g_free (signature_filename);
338               g_debug ("real pathname: %s", real);
339               if (real == NULL)
340                 return -1;
341               real_basename = g_path_get_basename (real);
342               split = g_strsplit (real_basename, ".", 2);
343               if (*split)
344                 *uuid = g_strdup (*split);
345               else
346                 *uuid = g_strdup (real_basename);
347               g_debug ("*uuid: %s", *uuid);
348               g_free (real_basename);
349               g_strfreev (split);
350               free (real);
351               return 0;
352             }
353           else
354             {
355               g_debug ("%s: failed to read %s: %s", __func__,
356                        signature_filename, error->message);
357               g_free (signature_filename);
358             }
359 
360           g_free (signature_basename);
361           g_error_free (error);
362           return -1;
363         }
364       g_free (signature_basename);
365       return 0;
366     }
367 
368   g_free (installer_basename);
369   return -1;
370 }
371 
372 
373 /* Report formats. */
374 
375 /**
376  * @brief Possible port types.
377  */
378 typedef enum
379 {
380   REPORT_FORMAT_FLAG_ACTIVE = 1
381 } report_format_flag_t;
382 
383 /**
384  * @brief Get trash directory of a report format.
385  *
386  * @param[in]  report_format_id  UUID of report format.  NULL for the
387  *             base dir that holds the report format trash.
388  *
389  * @return Freshly allocated trash dir.
390  */
391 static gchar *
report_format_trash_dir(const gchar * report_format_id)392 report_format_trash_dir (const gchar *report_format_id)
393 {
394   if (report_format_id)
395     return g_build_filename (GVMD_STATE_DIR,
396                              "report_formats_trash",
397                              report_format_id,
398                              NULL);
399 
400   return g_build_filename (GVMD_STATE_DIR,
401                            "report_formats_trash",
402                            NULL);
403 }
404 
405 /**
406  * @brief Find a report format given a name.
407  *
408  * @param[in]   name           Name of report_format.
409  * @param[out]  report_format  Report format return, 0 if successfully failed to
410  *                             find report_format.
411  *
412  * @return FALSE on success (including if failed to find report format), TRUE
413  *         on error.
414  */
415 gboolean
lookup_report_format(const char * name,report_format_t * report_format)416 lookup_report_format (const char* name, report_format_t* report_format)
417 {
418   iterator_t report_formats;
419   gchar *quoted_name;
420 
421   assert (report_format);
422 
423   *report_format = 0;
424   quoted_name = sql_quote (name);
425   init_iterator (&report_formats,
426                  "SELECT id, uuid FROM report_formats"
427                  " WHERE name = '%s'"
428                  " AND CAST (flags & %llu AS boolean)"
429                  " ORDER BY (CASE WHEN " ACL_USER_OWNS () " THEN 0"
430                  "                WHEN owner is NULL THEN 1"
431                  "                ELSE 2"
432                  "           END);",
433                  quoted_name,
434                  (long long int) REPORT_FORMAT_FLAG_ACTIVE,
435                  current_credentials.uuid);
436   g_free (quoted_name);
437   while (next (&report_formats))
438     {
439       const char *uuid;
440 
441       uuid = iterator_string (&report_formats, 1);
442       if (uuid
443           && acl_user_has_access_uuid ("report_format",
444                                        uuid,
445                                        "get_report_formats",
446                                        0))
447         {
448           *report_format = iterator_int64 (&report_formats, 0);
449           break;
450         }
451     }
452   cleanup_iterator (&report_formats);
453 
454   return FALSE;
455 }
456 
457 /**
458  * @brief Find a report format given a UUID.
459  *
460  * This does not do any permission checks.
461  *
462  * @param[in]   uuid           UUID of resource.
463  * @param[out]  report_format  Report Format return, 0 if no such report format.
464  *
465  * @return FALSE on success (including if no such report format), TRUE on error.
466  */
467 gboolean
find_report_format_no_acl(const char * uuid,report_format_t * report_format)468 find_report_format_no_acl (const char *uuid, report_format_t *report_format)
469 {
470   gchar *quoted_uuid;
471 
472   quoted_uuid = sql_quote (uuid);
473   switch (sql_int64 (report_format,
474                      "SELECT id FROM report_formats WHERE uuid = '%s';",
475                      quoted_uuid))
476     {
477       case 0:
478         break;
479       case 1:        /* Too few rows in result of query. */
480         *report_format = 0;
481         break;
482       default:       /* Programming error. */
483         assert (0);
484       case -1:
485         g_free (quoted_uuid);
486         return TRUE;
487         break;
488     }
489 
490   g_free (quoted_uuid);
491   return FALSE;
492 }
493 
494 /**
495  * @brief Find a trash report format given a UUID.
496  *
497  * This does not do any permission checks.
498  *
499  * This considers the actual UUID of the report format, not the original_uuid.
500  *
501  * @param[in]   uuid           UUID of resource.
502  * @param[out]  report_format  Report Format return, 0 if no such report format.
503  *
504  * @return FALSE on success (including if no such report format), TRUE on error.
505  */
506 gboolean
find_trash_report_format_no_acl(const char * uuid,report_format_t * report_format)507 find_trash_report_format_no_acl (const char *uuid, report_format_t *report_format)
508 {
509   gchar *quoted_uuid;
510 
511   quoted_uuid = sql_quote (uuid);
512   switch (sql_int64 (report_format,
513                      "SELECT id FROM report_formats_trash WHERE uuid = '%s';",
514                      quoted_uuid))
515     {
516       case 0:
517         break;
518       case 1:        /* Too few rows in result of query. */
519         *report_format = 0;
520         break;
521       default:       /* Programming error. */
522         assert (0);
523       case -1:
524         g_free (quoted_uuid);
525         return TRUE;
526         break;
527     }
528 
529   g_free (quoted_uuid);
530   return FALSE;
531 }
532 
533 /**
534  * @brief Compare files for create_report_format.
535  *
536  * @param[in]  one  First.
537  * @param[in]  two  Second.
538  *
539  * @return Less than, equal to, or greater than zero if one is found to be
540  *         less than, to match, or be greater than two.
541  */
542 static gint
compare_files(gconstpointer one,gconstpointer two)543 compare_files (gconstpointer one, gconstpointer two)
544 {
545   gchar *file_one, *file_two;
546   file_one = *((gchar**) one);
547   file_two = *((gchar**) two);
548   if (file_one == NULL)
549     {
550       if (file_two == NULL)
551         return 0;
552       return 1;
553     }
554   else if (file_two == NULL)
555     return -1;
556   return strcoll (file_one, file_two);
557 }
558 
559 /**
560  * @brief Save files of a report format.
561  *
562  * @param[in]   report_id      UUID of format.
563  * @param[in]   files          Array of memory.  Each item is a file name
564  *                             string, a terminating NULL, the file contents
565  *                             in base64 and a terminating NULL.
566  * @param[out]  report_format_dir  Address for dir, or NULL.
567  *
568  * @return 0 success, 2 empty file name, -1 error.
569  */
570 static int
save_report_format_files(const gchar * report_id,array_t * files,gchar ** report_format_dir)571 save_report_format_files (const gchar *report_id, array_t *files,
572                           gchar **report_format_dir)
573 {
574   gchar *dir, *report_dir, *file_name;
575   int index;
576 
577   dir = g_build_filename (GVMD_STATE_DIR,
578                           "report_formats",
579                           current_credentials.uuid,
580                           report_id,
581                           NULL);
582 
583   if (gvm_file_exists (dir) && gvm_file_remove_recurse (dir))
584     {
585       g_warning ("%s: failed to remove dir %s", __func__, dir);
586       g_free (dir);
587       return -1;
588     }
589 
590   if (g_mkdir_with_parents (dir, 0755 /* "rwxr-xr-x" */))
591     {
592       g_warning ("%s: failed to create dir %s: %s",
593                  __func__, dir, strerror (errno));
594       g_free (dir);
595       return -1;
596     }
597 
598   /* glib seems to apply the mode to the first dir only. */
599 
600   report_dir = g_build_filename (GVMD_STATE_DIR,
601                                  "report_formats",
602                                  current_credentials.uuid,
603                                  NULL);
604 
605   if (chmod (report_dir, 0755 /* rwxr-xr-x */))
606     {
607       g_warning ("%s: chmod failed: %s",
608                  __func__,
609                  strerror (errno));
610       g_free (dir);
611       g_free (report_dir);
612       return -1;
613     }
614 
615   g_free (report_dir);
616 
617   /* glib seems to apply the mode to the first dir only. */
618   if (chmod (dir, 0755 /* rwxr-xr-x */))
619     {
620       g_warning ("%s: chmod failed: %s",
621                  __func__,
622                  strerror (errno));
623       g_free (dir);
624       return -1;
625     }
626 
627   index = 0;
628   while ((file_name = (gchar*) g_ptr_array_index (files, index++)))
629     {
630       gchar *contents, *file, *full_file_name;
631       gsize contents_size;
632       GError *error;
633       int ret;
634 
635       if (strlen (file_name) == 0)
636         {
637           gvm_file_remove_recurse (dir);
638           g_free (dir);
639           return 2;
640         }
641 
642       file = file_name + strlen (file_name) + 1;
643       if (strlen (file))
644         contents = (gchar*) g_base64_decode (file, &contents_size);
645       else
646         {
647           contents = g_strdup ("");
648           contents_size = 0;
649         }
650 
651       full_file_name = g_build_filename (dir, file_name, NULL);
652 
653       error = NULL;
654       g_file_set_contents (full_file_name, contents, contents_size, &error);
655       g_free (contents);
656       if (error)
657         {
658           g_warning ("%s: %s", __func__, error->message);
659           g_error_free (error);
660           gvm_file_remove_recurse (dir);
661           g_free (full_file_name);
662           g_free (dir);
663           return -1;
664         }
665 
666       if (strcmp (file_name, "generate") == 0)
667         ret = chmod (full_file_name, 0755 /* rwxr-xr-x */);
668       else
669         ret = chmod (full_file_name, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
670       if (ret)
671         {
672           g_warning ("%s: chmod failed: %s",
673                      __func__,
674                      strerror (errno));
675           gvm_file_remove_recurse (dir);
676           g_free (full_file_name);
677           g_free (dir);
678           return -1;
679         }
680 
681       g_free (full_file_name);
682     }
683 
684   if (report_format_dir)
685     *report_format_dir = dir;
686 
687   return 0;
688 }
689 
690 /**
691  * @brief Add params to a report format.
692  *
693  * @param[in]  report_format   Report format.
694  * @param[in]  params          Array of params.
695  * @param[in]  params_options  Array.  Each item is an array corresponding to
696  *                             params.  Each item of an inner array is a string,
697  *                             the text of an option in a selection.
698  *
699  * @return 0 success, 3 param value validation failed, 4 param value
700  *         validation failed, 5 param default missing, 6 param min or max
701  *         out of range, 7 param type missing, 8 duplicate param name,
702  *         9 bogus param type name, 99 permission denied, -1 error.
703  */
704 static int
add_report_format_params(report_format_t report_format,array_t * params,array_t * params_options)705 add_report_format_params (report_format_t report_format, array_t *params,
706                           array_t *params_options)
707 {
708   int index;
709   create_report_format_param_t *param;
710 
711   index = 0;
712   while ((param = (create_report_format_param_t*) g_ptr_array_index (params,
713                                                                      index++)))
714     {
715       gchar *quoted_param_name, *quoted_param_value, *quoted_param_fallback;
716       rowid_t param_rowid;
717       long long int min, max;
718 
719       if (param->type == NULL)
720         return 7;
721 
722       if (report_format_param_type_from_name (param->type)
723           == REPORT_FORMAT_PARAM_TYPE_ERROR)
724         return 9;
725 
726       /* Param min and max are optional.  LLONG_MIN and LLONG_MAX mark in the db
727        * that they were missing, so if the user gives LLONG_MIN or LLONG_MAX it
728        * is an error.  This ensures that GPG verification works, because the
729        * verification knows when to leave out min and max. */
730 
731       if (param->type_min)
732         {
733           min = strtoll (param->type_min, NULL, 0);
734           if (min == LLONG_MIN)
735             return 6;
736         }
737       else
738         min = LLONG_MIN;
739 
740       if (param->type_max)
741         {
742           max = strtoll (param->type_max, NULL, 0);
743           if (max == LLONG_MAX)
744             return 6;
745         }
746       else
747         max = LLONG_MAX;
748 
749       if (param->fallback == NULL)
750         return 5;
751 
752       quoted_param_name = sql_quote (param->name);
753 
754       if (sql_int ("SELECT count(*) FROM report_format_params"
755                    " WHERE name = '%s' AND report_format = %llu;",
756                    quoted_param_name,
757                    report_format))
758         {
759           g_free (quoted_param_name);
760           return 8;
761         }
762 
763       quoted_param_value = sql_quote (param->value);
764       quoted_param_fallback = sql_quote (param->fallback);
765 
766       sql ("INSERT INTO report_format_params"
767            " (report_format, name, type, value, type_min, type_max, type_regex,"
768            "  fallback)"
769            " VALUES (%llu, '%s', %u, '%s', %lli, %lli, '', '%s');",
770            report_format,
771            quoted_param_name,
772            report_format_param_type_from_name (param->type),
773            quoted_param_value,
774            min,
775            max,
776            quoted_param_fallback);
777 
778       g_free (quoted_param_name);
779       g_free (quoted_param_value);
780       g_free (quoted_param_fallback);
781 
782       param_rowid = sql_last_insert_id ();
783 
784       {
785         array_t *options;
786         int option_index;
787         gchar *option_value;
788 
789         options = (array_t*) g_ptr_array_index (params_options, index - 1);
790         if (options == NULL)
791           {
792             g_warning ("%s: options was NULL", __func__);
793             return -1;
794           }
795         option_index = 0;
796         while ((option_value = (gchar*) g_ptr_array_index (options,
797                                                            option_index++)))
798           {
799             gchar *quoted_option_value = sql_quote (option_value);
800             sql ("INSERT INTO report_format_param_options"
801                  " (report_format_param, value)"
802                  " VALUES (%llu, '%s');",
803                  param_rowid,
804                  quoted_option_value);
805             g_free (quoted_option_value);
806           }
807       }
808 
809       if (validate_param_value (report_format, param_rowid, param->name,
810                                 param->value))
811         return 3;
812 
813       if (validate_param_value (report_format, param_rowid, param->name,
814                                 param->fallback))
815         return 4;
816     }
817 
818   return 0;
819 }
820 
821 
822 /**
823  * @brief Create a report format.
824  *
825  * @param[in]   check_access   Whether to check for permission.
826  * @param[in]   may_exist      Whether it is OK if there is already a report
827  *                             format with this UUID.
828  * @param[in]   active         Whether report format is active.
829  * @param[in]   trusted        Whether to assumed report format is trusted.
830  * @param[in]   uuid           UUID of format.
831  * @param[in]   name           Name of format.
832  * @param[in]   content_type   Content type of format.
833  * @param[in]   extension      File extension of format.
834  * @param[in]   summary        Summary of format.
835  * @param[in]   description    Description of format.
836  * @param[in]   files          Array of memory.  Each item is a file name
837  *                             string, a terminating NULL, the file contents
838  *                             in base64 and a terminating NULL.
839  * @param[in]   params         Array of params.
840  * @param[in]   params_options Array.  Each item is an array corresponding to
841  *                             params.  Each item of an inner array is a string,
842  *                             the text of an option in a selection.
843  * @param[in]   predefined     Whether report format is from the feed.
844  * @param[in]   signature      Signature.
845  * @param[out]  report_format  Created report format.
846  *
847  * @return 0 success, 1 report format exists, 2 empty file name, 3 param value
848  *         validation failed, 4 param value validation failed, 5 param default
849  *         missing, 6 param min or max out of range, 7 param type missing,
850  *         8 duplicate param name, 9 bogus param type name, 99 permission
851  *         denied, -1 error.
852  */
853 static int
create_report_format_internal(int check_access,int may_exist,int active,int trusted,const char * uuid,const char * name,const char * content_type,const char * extension,const char * summary,const char * description,array_t * files,array_t * params,array_t * params_options,const char * signature,int predefined,report_format_t * report_format)854 create_report_format_internal (int check_access, int may_exist, int active,
855                                int trusted, const char *uuid, const char *name,
856                                const char *content_type, const char *extension,
857                                const char *summary, const char *description,
858                                array_t *files, array_t *params,
859                                array_t *params_options, const char *signature,
860                                int predefined,
861                                report_format_t *report_format)
862 {
863   gchar *quoted_name, *quoted_summary, *quoted_description, *quoted_extension;
864   gchar *quoted_content_type, *quoted_signature, *file_name, *dir;
865   gchar *candidate_name, *new_uuid, *uuid_actual;
866   report_format_t report_format_rowid;
867   int index, num, ret;
868   gchar *format_signature = NULL;
869   gsize format_signature_size;
870   int format_trust = TRUST_UNKNOWN;
871   create_report_format_param_t *param;
872 
873   assert (current_credentials.uuid);
874   assert (uuid);
875   assert (name);
876   assert (files);
877   assert (params);
878 
879   if (trusted)
880     format_trust = TRUST_YES;
881 
882   /* Verify the signature. */
883 
884   if (trusted == 0
885       && ((find_signature ("report_formats", uuid, &format_signature,
886                        &format_signature_size, &uuid_actual)
887           == 0)
888           || signature))
889     {
890       char *locale;
891       GString *format;
892 
893       format = g_string_new ("");
894 
895       g_string_append_printf (format,
896                               "%s%s%s%i",
897                               uuid_actual ? uuid_actual : uuid,
898                               extension,
899                               content_type,
900                               0); /* Old global flag. */
901 
902       index = 0;
903       locale = setlocale (LC_ALL, "C");
904       g_ptr_array_sort (files, compare_files);
905       setlocale (LC_ALL, locale);
906       while ((file_name = (gchar*) g_ptr_array_index (files, index++)))
907         g_string_append_printf (format,
908                                 "%s%s",
909                                 file_name,
910                                 file_name + strlen (file_name) + 1);
911 
912       index = 0;
913       while ((param
914                = (create_report_format_param_t*) g_ptr_array_index (params,
915                                                                     index++)))
916         {
917           g_string_append_printf (format,
918                                   "%s%s",
919                                   param->name,
920                                   param->type);
921 
922           if (param->type_min)
923             {
924               long long int min;
925               min = strtoll (param->type_min, NULL, 0);
926               if (min == LLONG_MIN)
927                 return 6;
928               g_string_append_printf (format, "%lli", min);
929             }
930 
931           if (param->type_max)
932             {
933               long long int max;
934               max = strtoll (param->type_max, NULL, 0);
935               if (max == LLONG_MAX)
936                 return 6;
937               g_string_append_printf (format, "%lli", max);
938             }
939 
940           g_string_append_printf (format,
941                                   "%s",
942                                   param->fallback);
943 
944           {
945             array_t *options;
946             int option_index;
947             gchar *option_value;
948 
949             options = (array_t*) g_ptr_array_index (params_options, index - 1);
950             if (options == NULL)
951               return -1;
952             option_index = 0;
953             while ((option_value = (gchar*) g_ptr_array_index (options,
954                                                                option_index++)))
955               g_string_append_printf (format, "%s", option_value);
956           }
957         }
958 
959       g_string_append_printf (format, "\n");
960 
961       if (format_signature)
962         signature = (const char*) format_signature;
963 
964       if (verify_signature (format->str, format->len, signature,
965                             strlen (signature), &format_trust))
966         {
967           g_free (format_signature);
968           g_string_free (format, TRUE);
969           return -1;
970         }
971       g_string_free (format, TRUE);
972     }
973 
974   sql_begin_immediate ();
975 
976   if (check_access && (acl_user_may ("create_report_format") == 0))
977     {
978       sql_rollback ();
979       return 99;
980     }
981 
982   if (sql_int ("SELECT COUNT(*) FROM report_formats WHERE uuid = '%s';",
983                uuid)
984       || sql_int ("SELECT COUNT(*) FROM report_formats_trash"
985                   " WHERE original_uuid = '%s';",
986                   uuid))
987     {
988       gchar *base, *new, *old, *path;
989       char *real_old;
990 
991       if (may_exist == 0)
992         {
993           sql_rollback ();
994           return 10;
995         }
996 
997       /* Make a new UUID, because a report format exists with the given UUID. */
998 
999       new_uuid = gvm_uuid_make ();
1000       if (new_uuid == NULL)
1001         {
1002           sql_rollback ();
1003           return -1;
1004         }
1005 
1006       /* Setup a private/report_formats/ link to the signature of the existing
1007        * report format in the feed.  This allows the signature to be shared. */
1008 
1009       base = g_strdup_printf ("%s.asc", uuid);
1010       old = g_build_filename (GVM_NVT_DIR, "report_formats", base, NULL);
1011       real_old = realpath (old, NULL);
1012       if (real_old)
1013         {
1014           /* Signature exists in regular directory. */
1015 
1016           g_free (old);
1017           old = g_strdup (real_old);
1018           free (real_old);
1019         }
1020       else
1021         {
1022           struct stat state;
1023 
1024           /* Signature may be in private directory. */
1025 
1026           g_free (old);
1027           old = g_build_filename (GVMD_STATE_DIR,
1028                                   "signatures",
1029                                   "report_formats",
1030                                   base,
1031                                   NULL);
1032           if (lstat (old, &state))
1033             {
1034               /* No.  Signature may not exist in the feed yet. */
1035               g_free (old);
1036               old = g_build_filename (GVM_NVT_DIR, "report_formats", base,
1037                                       NULL);
1038               g_debug ("using standard old: %s", old);
1039             }
1040           else
1041             {
1042               int count;
1043 
1044               /* Yes.  Use the path it links to. */
1045 
1046               real_old = g_malloc (state.st_size + 1);
1047               count = readlink (old, real_old, state.st_size + 1);
1048               if (count < 0 || count > state.st_size)
1049                 {
1050                   g_free (real_old);
1051                   g_free (old);
1052                   g_warning ("%s: readlink failed", __func__);
1053                   sql_rollback ();
1054                   return -1;
1055                 }
1056 
1057               real_old[state.st_size] = '\0';
1058               g_free (old);
1059               old = real_old;
1060               g_debug ("using linked old: %s", old);
1061             }
1062         }
1063       g_free (base);
1064 
1065       path = g_build_filename (GVMD_STATE_DIR,
1066                                "signatures", "report_formats", NULL);
1067 
1068       if (g_mkdir_with_parents (path, 0755 /* "rwxr-xr-x" */))
1069         {
1070           g_warning ("%s: failed to create dir %s: %s",
1071                      __func__, path, strerror (errno));
1072           g_free (old);
1073           g_free (path);
1074           sql_rollback ();
1075           return -1;
1076         }
1077 
1078       base = g_strdup_printf ("%s.asc", new_uuid);
1079       new = g_build_filename (path, base, NULL);
1080       g_free (path);
1081       g_free (base);
1082       if (symlink (old, new))
1083         {
1084           g_free (old);
1085           g_free (new);
1086           g_warning ("%s: symlink failed: %s", __func__, strerror (errno));
1087           sql_rollback ();
1088           return -1;
1089         }
1090     }
1091   else
1092     new_uuid = NULL;
1093 
1094   candidate_name = g_strdup (name);
1095   quoted_name = sql_quote (candidate_name);
1096 
1097   num = 1;
1098   while (1)
1099     {
1100       if (!resource_with_name_exists (quoted_name, "report_format", 0))
1101         break;
1102       g_free (candidate_name);
1103       g_free (quoted_name);
1104       candidate_name = g_strdup_printf ("%s %u", name, ++num);
1105       quoted_name = sql_quote (candidate_name);
1106     }
1107   g_free (candidate_name);
1108 
1109   /* Write files to disk. */
1110 
1111   ret = save_report_format_files (new_uuid ? new_uuid : uuid, files, &dir);
1112   if (ret)
1113     {
1114       g_free (quoted_name);
1115       g_free (new_uuid);
1116       sql_rollback ();
1117       return ret;
1118     }
1119 
1120   /* Add format to database. */
1121 
1122   quoted_summary = summary ? sql_quote (summary) : NULL;
1123   quoted_description = description ? sql_quote (description) : NULL;
1124   quoted_extension = extension ? sql_quote (extension) : NULL;
1125   quoted_content_type = content_type ? sql_quote (content_type) : NULL;
1126   quoted_signature = signature ? sql_quote (signature) : NULL;
1127   g_free (format_signature);
1128 
1129   sql ("INSERT INTO report_formats"
1130        " (uuid, name, owner, summary, description, extension, content_type,"
1131        "  signature, trust, trust_time, flags, predefined, creation_time,"
1132        "  modification_time)"
1133        " VALUES ('%s', '%s',"
1134        " (SELECT id FROM users WHERE users.uuid = '%s'),"
1135        " '%s', '%s', '%s', '%s', '%s', %i, %i, %i, %i, m_now (), m_now ());",
1136        new_uuid ? new_uuid : uuid,
1137        quoted_name,
1138        current_credentials.uuid,
1139        quoted_summary ? quoted_summary : "",
1140        quoted_description ? quoted_description : "",
1141        quoted_extension ? quoted_extension : "",
1142        quoted_content_type ? quoted_content_type : "",
1143        quoted_signature ? quoted_signature : "",
1144        format_trust,
1145        time (NULL),
1146        active ? REPORT_FORMAT_FLAG_ACTIVE : 0,
1147        predefined ? 1 : 0);
1148 
1149   g_free (new_uuid);
1150   g_free (quoted_summary);
1151   g_free (quoted_description);
1152   g_free (quoted_extension);
1153   g_free (quoted_content_type);
1154   g_free (quoted_signature);
1155   g_free (quoted_name);
1156 
1157   /* Add params to database. */
1158 
1159   report_format_rowid = sql_last_insert_id ();
1160   ret = add_report_format_params (report_format_rowid, params, params_options);
1161   if (ret)
1162     {
1163       gvm_file_remove_recurse (dir);
1164       g_free (dir);
1165       sql_rollback ();
1166       return ret;
1167     }
1168 
1169   if (report_format)
1170     *report_format = report_format_rowid;
1171 
1172   g_free (dir);
1173 
1174   sql_commit ();
1175 
1176   return 0;
1177 }
1178 
1179 /**
1180  * @brief Create a report format.
1181  *
1182  * @param[in]   uuid           UUID of format.
1183  * @param[in]   name           Name of format.
1184  * @param[in]   content_type   Content type of format.
1185  * @param[in]   extension      File extension of format.
1186  * @param[in]   summary        Summary of format.
1187  * @param[in]   description    Description of format.
1188  * @param[in]   files          Array of memory.  Each item is a file name
1189  *                             string, a terminating NULL, the file contents
1190  *                             in base64 and a terminating NULL.
1191  * @param[in]   params         Array of params.
1192  * @param[in]   params_options Array.  Each item is an array corresponding to
1193  *                             params.  Each item of an inner array is a string,
1194  *                             the text of an option in a selection.
1195  * @param[in]   signature      Signature.
1196  * @param[out]  report_format  Created report format.
1197  *
1198  * @return 0 success, 2 empty file name, 3 param value
1199  *         validation failed, 4 param value validation failed, 5 param default
1200  *         missing, 6 param min or max out of range, 7 param type missing,
1201  *         8 duplicate param name, 9 bogus param type name, 99 permission
1202  *         denied, -1 error.
1203  */
1204 int
create_report_format(const char * uuid,const char * name,const char * content_type,const char * extension,const char * summary,const char * description,array_t * files,array_t * params,array_t * params_options,const char * signature,report_format_t * report_format)1205 create_report_format (const char *uuid, const char *name,
1206                       const char *content_type, const char *extension,
1207                       const char *summary, const char *description,
1208                       array_t *files, array_t *params, array_t *params_options,
1209                       const char *signature, report_format_t *report_format)
1210 {
1211   return create_report_format_internal (1, /* Check permission. */
1212                                         1, /* Allow existing report format. */
1213                                         0, /* Active. */
1214                                         0, /* Assume trusted. */
1215                                         uuid, name, content_type, extension,
1216                                         summary, description, files, params,
1217                                         params_options, signature,
1218                                         0, /* Predefined. */
1219                                         report_format);
1220 }
1221 
1222 /**
1223  * @brief Create a report format.
1224  *
1225  * @param[in]   uuid           UUID of format.
1226  * @param[in]   name           Name of format.
1227  * @param[in]   content_type   Content type of format.
1228  * @param[in]   extension      File extension of format.
1229  * @param[in]   summary        Summary of format.
1230  * @param[in]   description    Description of format.
1231  * @param[in]   files          Array of memory.  Each item is a file name
1232  *                             string, a terminating NULL, the file contents
1233  *                             in base64 and a terminating NULL.
1234  * @param[in]   params         Array of params.
1235  * @param[in]   params_options Array.  Each item is an array corresponding to
1236  *                             params.  Each item of an inner array is a string,
1237  *                             the text of an option in a selection.
1238  * @param[in]   signature      Signature.
1239  * @param[in]   predefined     Whether report format is from the feed.
1240  * @param[out]  report_format  Created report format.
1241  *
1242  * @return 0 success, 1 report format exists, 2 empty file name, 3 param value
1243  *         validation failed, 4 param value validation failed, 5 param default
1244  *         missing, 6 param min or max out of range, 7 param type missing,
1245  *         8 duplicate param name, 9 bogus param type name, 99 permission
1246  *         denied, -1 error.
1247  */
1248 int
create_report_format_no_acl(const char * uuid,const char * name,const char * content_type,const char * extension,const char * summary,const char * description,array_t * files,array_t * params,array_t * params_options,const char * signature,int predefined,report_format_t * report_format)1249 create_report_format_no_acl (const char *uuid, const char *name,
1250                              const char *content_type, const char *extension,
1251                              const char *summary, const char *description,
1252                              array_t *files, array_t *params,
1253                              array_t *params_options, const char *signature,
1254                              int predefined, report_format_t *report_format)
1255 {
1256   return create_report_format_internal (0, /* Check permission. */
1257                                         0, /* Allow existing report format. */
1258                                         1, /* Active. */
1259                                         1, /* Assume trusted. */
1260                                         uuid, name, content_type, extension,
1261                                         summary, description, files, params,
1262                                         params_options, signature,
1263                                         predefined, report_format);
1264 }
1265 
1266 /**
1267  * @brief Create a report format dir.
1268  *
1269  * @param[in]  source_dir        Full path of source directory, including UUID.
1270  * @param[in]  copy_parent       Path of destination directory, excluding UUID.
1271  * @param[in]  copy_uuid         UUID (dirname) of destination directory.
1272  *
1273  * @return 0 success, -1 error.
1274  */
1275 static int
copy_report_format_dir(const gchar * source_dir,const gchar * copy_parent,const gchar * copy_uuid)1276 copy_report_format_dir (const gchar *source_dir, const gchar *copy_parent,
1277                         const gchar *copy_uuid)
1278 {
1279   gchar *copy_dir;
1280 
1281   g_debug ("%s: copy %s to %s/%s", __func__, source_dir, copy_parent,
1282            copy_uuid);
1283 
1284   /* Check that the source directory exists. */
1285 
1286   if (!gvm_file_is_readable (source_dir))
1287     {
1288       g_warning ("%s: report format directory %s not found",
1289                  __func__, source_dir);
1290       return -1;
1291     }
1292 
1293   /* Prepare directory to copy into. */
1294 
1295   copy_dir = g_build_filename (copy_parent, copy_uuid, NULL);
1296 
1297   if (gvm_file_exists (copy_dir)
1298       && gvm_file_remove_recurse (copy_dir))
1299     {
1300       g_warning ("%s: failed to remove dir %s", __func__, copy_dir);
1301       g_free (copy_dir);
1302       return -1;
1303     }
1304 
1305   if (g_mkdir_with_parents (copy_dir, 0755 /* "rwxr-xr-x" */))
1306     {
1307       g_warning ("%s: failed to create dir %s", __func__, copy_dir);
1308       g_free (copy_dir);
1309       return -1;
1310     }
1311 
1312   /* Correct permissions as glib doesn't seem to do so. */
1313 
1314   if (chmod (copy_parent, 0755 /* rwxr-xr-x */))
1315     {
1316       g_warning ("%s: chmod %s failed: %s",
1317                  __func__,
1318                  copy_parent,
1319                  strerror (errno));
1320       g_free (copy_dir);
1321       return -1;
1322     }
1323 
1324   if (chmod (copy_dir, 0755 /* rwxr-xr-x */))
1325     {
1326       g_warning ("%s: chmod %s failed: %s",
1327                  __func__,
1328                  copy_dir,
1329                  strerror (errno));
1330       g_free (copy_dir);
1331       return -1;
1332     }
1333 
1334   /* Copy files into new directory. */
1335   {
1336     GDir *directory;
1337     GError *error;
1338 
1339     error = NULL;
1340     directory = g_dir_open (source_dir, 0, &error);
1341     if (directory == NULL)
1342       {
1343         if (error)
1344           {
1345             g_warning ("g_dir_open(%s) failed - %s",
1346                        source_dir, error->message);
1347             g_error_free (error);
1348           }
1349         g_free (copy_dir);
1350         return -1;
1351       }
1352     else
1353       {
1354         gchar *source_file, *copy_file;
1355         const gchar *filename;
1356 
1357         filename = g_dir_read_name (directory);
1358         while (filename)
1359           {
1360             source_file = g_build_filename (source_dir, filename, NULL);
1361             copy_file = g_build_filename (copy_dir, filename, NULL);
1362 
1363             if (gvm_file_copy (source_file, copy_file) == FALSE)
1364               {
1365                 g_warning ("%s: copy of %s to %s failed",
1366                            __func__, source_file, copy_file);
1367                 g_free (source_file);
1368                 g_free (copy_file);
1369                 g_free (copy_dir);
1370                 return -1;
1371               }
1372             g_free (source_file);
1373             g_free (copy_file);
1374             filename = g_dir_read_name (directory);
1375           }
1376       }
1377   }
1378 
1379   g_free (copy_dir);
1380   return 0;
1381 }
1382 
1383 /**
1384  * @brief Create Report Format from an existing Report Format.
1385  *
1386  * @param[in]  name                 Name of new Report Format. NULL to copy
1387  *                                  from existing.
1388  * @param[in]  source_uuid          UUID of existing Report Format.
1389  * @param[out] new_report_format    New Report Format.
1390  *
1391  * @return 0 success, 1 Report Format exists already, 2 failed to find existing
1392  *         Report Format, 99 permission denied, -1 error.
1393  */
1394 int
copy_report_format(const char * name,const char * source_uuid,report_format_t * new_report_format)1395 copy_report_format (const char* name, const char* source_uuid,
1396                     report_format_t* new_report_format)
1397 {
1398   report_format_t new, old;
1399   gchar *copy_uuid, *source_dir, *copy_dir, *owner_uuid;
1400   int ret;
1401 
1402   assert (current_credentials.uuid);
1403 
1404   sql_begin_immediate ();
1405 
1406   ret = copy_resource_lock ("report_format", name, NULL, source_uuid,
1407                             "extension, content_type, summary, description,"
1408                             " signature, trust, trust_time, flags",
1409                             1, &new, &old);
1410   if (ret)
1411     {
1412       sql_rollback ();
1413       return ret;
1414     }
1415 
1416   sql ("UPDATE report_formats SET predefined = 0 WHERE id = %llu;", new);
1417 
1418   if (report_format_predefined (old))
1419     sql ("UPDATE report_formats SET trust = %i, trust_time = %i"
1420          " WHERE id = %llu;",
1421          TRUST_YES,
1422          time (NULL),
1423          new);
1424 
1425   /* Copy report format parameters. */
1426 
1427   sql ("INSERT INTO report_format_params "
1428        " (report_format, name, type, value, type_min, type_max,"
1429        "  type_regex, fallback)"
1430        " SELECT %llu, name, type, value, type_min, type_max,"
1431        "  type_regex, fallback"
1432        "  FROM report_format_params WHERE report_format = %llu;",
1433        new,
1434        old);
1435 
1436   /* Copy files on disk. */
1437 
1438   owner_uuid = report_format_owner_uuid (old);
1439   assert (owner_uuid);
1440   source_dir = g_build_filename (GVMD_STATE_DIR,
1441                                  "report_formats",
1442                                  owner_uuid,
1443                                  source_uuid,
1444                                  NULL);
1445   g_free (owner_uuid);
1446 
1447   copy_uuid = report_format_uuid (new);
1448   if (copy_uuid == NULL)
1449     {
1450       sql_rollback ();
1451       return -1;
1452     }
1453 
1454   copy_dir = g_build_filename (GVMD_STATE_DIR,
1455                                "report_formats",
1456                                current_credentials.uuid,
1457                                NULL);
1458 
1459   if (copy_report_format_dir (source_dir, copy_dir, copy_uuid))
1460     {
1461       sql_rollback ();
1462       g_free (source_dir);
1463       g_free (copy_dir);
1464       return -1;
1465     }
1466 
1467   sql_commit ();
1468   g_free (source_dir);
1469   g_free (copy_dir);
1470   if (new_report_format) *new_report_format = new;
1471   return 0;
1472 }
1473 
1474 /**
1475  * @brief Return whether a report format is predefined.
1476  *
1477  * @param[in]  report_format_id  UUID of report format.
1478  *
1479  * @return 1 if predefined, else 0.
1480  */
1481 static int
report_format_predefined_uuid(const gchar * report_format_id)1482 report_format_predefined_uuid (const gchar *report_format_id)
1483 {
1484   report_format_t report_format;
1485 
1486   if (find_report_format_no_acl (report_format_id, &report_format)
1487       || report_format == 0)
1488     return 0;
1489 
1490   return report_format_predefined (report_format);
1491 }
1492 
1493 /**
1494  * @brief Modify a report format.
1495  *
1496  * @param[in]  report_format_id  UUID of report format.
1497  * @param[in]  name              Name of report format.
1498  * @param[in]  summary           Summary of report format.
1499  * @param[in]  active            Active flag.
1500  * @param[in]  param_name        Parameter to modify.
1501  * @param[in]  param_value       Value of parameter.
1502  *
1503  * @return 0 success, 1 failed to find report format, 2 report_format_id
1504  * required, 3 failed to find report format parameter, 4 parameter value
1505  * validation failed, 99 permission denied, -1 internal error.
1506  */
1507 int
modify_report_format(const char * report_format_id,const char * name,const char * summary,const char * active,const char * param_name,const char * param_value)1508 modify_report_format (const char *report_format_id, const char *name,
1509                       const char *summary, const char *active,
1510                       const char *param_name, const char *param_value)
1511 {
1512   report_format_t report_format;
1513   int ret = 0;
1514 
1515   if (report_format_id == NULL)
1516     return 2;
1517 
1518   sql_begin_immediate ();
1519 
1520   assert (current_credentials.uuid);
1521 
1522   if (acl_user_may ("modify_report_format") == 0)
1523     {
1524       sql_rollback ();
1525       return 99;
1526     }
1527 
1528   if (report_format_predefined_uuid (report_format_id))
1529     {
1530       sql_rollback ();
1531       return 99;
1532     }
1533 
1534   report_format = 0;
1535   if (find_report_format_with_permission (report_format_id, &report_format,
1536                                           "modify_report_format"))
1537     {
1538       sql_rollback ();
1539       return -1;
1540     }
1541 
1542   if (report_format == 0)
1543     {
1544       sql_rollback ();
1545       return 1;
1546     }
1547 
1548   /* Update values */
1549   if (name)
1550     set_report_format_name (report_format, name);
1551 
1552   if (summary)
1553     set_report_format_summary (report_format, summary);
1554 
1555   if (active)
1556     set_report_format_active (report_format, strcmp (active, "0"));
1557 
1558   sql_commit ();
1559 
1560   /* Update format params if set */
1561   if (param_name)
1562     {
1563       ret = set_report_format_param (report_format, param_name, param_value);
1564       if (ret == 1)
1565         ret = 3;
1566       if (ret == 2)
1567         ret = 4;
1568     }
1569 
1570   return ret;
1571 }
1572 
1573 /**
1574  * @brief Move a report format directory.
1575  *
1576  * @param[in]  dir      Old dir.
1577  * @param[in]  new_dir  New dir.
1578  *
1579  * @return 0 success, -1 error.
1580  */
1581 static int
move_report_format_dir(const char * dir,const char * new_dir)1582 move_report_format_dir (const char *dir, const char *new_dir)
1583 {
1584   if (gvm_file_is_readable (dir)
1585       && gvm_file_check_is_dir (dir))
1586     {
1587       gchar *new_dir_parent;
1588 
1589       g_warning ("%s: rename %s to %s", __func__, dir, new_dir);
1590 
1591       /* Ensure parent of new_dir exists. */
1592       new_dir_parent = g_path_get_dirname (new_dir);
1593       if (g_mkdir_with_parents (new_dir_parent, 0755 /* "rwxr-xr-x" */))
1594         {
1595           g_warning ("%s: failed to create parent %s", __func__,
1596                      new_dir_parent);
1597           g_free (new_dir_parent);
1598           return -1;
1599         }
1600       g_free (new_dir_parent);
1601 
1602       if (rename (dir, new_dir))
1603         {
1604           GError *error;
1605           GDir *directory;
1606           const gchar *entry;
1607 
1608           if (errno == EXDEV)
1609             {
1610               /* Across devices, move by hand. */
1611 
1612               if (g_mkdir_with_parents (new_dir, 0755 /* "rwxr-xr-x" */))
1613                 {
1614                   g_warning ("%s: failed to create dir %s", __func__,
1615                              new_dir);
1616                   return -1;
1617                 }
1618 
1619               error = NULL;
1620               directory = g_dir_open (dir, 0, &error);
1621 
1622               if (directory == NULL)
1623                 {
1624                   g_warning ("%s: failed to g_dir_open %s: %s",
1625                              __func__, dir, error->message);
1626                   g_error_free (error);
1627                   return -1;
1628                 }
1629 
1630               entry = NULL;
1631               while ((entry = g_dir_read_name (directory)))
1632                 {
1633                   gchar *entry_path, *new_path;
1634                   entry_path = g_build_filename (dir, entry, NULL);
1635                   new_path = g_build_filename (new_dir, entry, NULL);
1636                   if (gvm_file_move (entry_path, new_path) == FALSE)
1637                     {
1638                       g_warning ("%s: failed to move %s to %s",
1639                                  __func__, entry_path, new_path);
1640                       g_free (entry_path);
1641                       g_free (new_path);
1642                       g_dir_close (directory);
1643                       return -1;
1644                     }
1645                   g_free (entry_path);
1646                   g_free (new_path);
1647                 }
1648 
1649               g_dir_close (directory);
1650 
1651               gvm_file_remove_recurse (dir);
1652             }
1653           else
1654             {
1655               g_warning ("%s: rename %s to %s: %s",
1656                          __func__, dir, new_dir, strerror (errno));
1657               return -1;
1658             }
1659         }
1660     }
1661   else
1662     {
1663       g_warning ("%s: report dir missing: %s",
1664                  __func__, dir);
1665       return -1;
1666     }
1667   return 0;
1668 }
1669 
1670 /**
1671  * @brief Delete a report format from the db.
1672  *
1673  * @param[in]  report_format  Report format.
1674  */
1675 static void
delete_report_format_rows(report_format_t report_format)1676 delete_report_format_rows (report_format_t report_format)
1677 {
1678   sql ("DELETE FROM report_format_param_options WHERE report_format_param"
1679        " IN (SELECT id from report_format_params WHERE report_format = %llu);",
1680        report_format);
1681   sql ("DELETE FROM report_format_params WHERE report_format = %llu;",
1682        report_format);
1683   sql ("DELETE FROM report_formats WHERE id = %llu;", report_format);
1684 }
1685 
1686 /**
1687  * @brief Delete a report format.
1688  *
1689  * @param[in]  report_format_id  UUID of Report format.
1690  * @param[in]  ultimate          Whether to remove entirely, or to trashcan.
1691  *
1692  * @return 0 success, 1 report format in use, 2 failed to find report format,
1693  *         99 permission denied, -1 error.
1694  */
1695 int
delete_report_format(const char * report_format_id,int ultimate)1696 delete_report_format (const char *report_format_id, int ultimate)
1697 {
1698   gchar *dir;
1699   char *owner_uuid;
1700   report_format_t report_format, trash_report_format;
1701 
1702   /* This is complicated in two ways
1703    *
1704    *   - the UUID of a report format is the same every time it is
1705    *     imported, so to prevent multiple deletes from producing
1706    *     duplicate UUIDs in the trashcan, each report format in the
1707    *     trashcan gets a new UUID (except feed report formats),
1708    *
1709    *   - the report format has information on disk on top of the
1710    *     info in the db, so the disk information has to be held
1711    *     in a special trashcan directory. */
1712 
1713   sql_begin_immediate ();
1714 
1715   if (acl_user_may ("delete_report_format") == 0)
1716     {
1717       sql_rollback ();
1718       return 99;
1719     }
1720 
1721   /* Look in the "real" table. */
1722 
1723   if (find_report_format_with_permission (report_format_id, &report_format,
1724                                           "delete_report_format"))
1725     {
1726       sql_rollback ();
1727       return -1;
1728     }
1729 
1730   if (report_format == 0)
1731     {
1732       gchar *report_format_string, *base;
1733 
1734       /* Look in the trashcan. */
1735 
1736       if (find_trash ("report_format", report_format_id, &report_format))
1737         {
1738           sql_rollback ();
1739           return -1;
1740         }
1741       if (report_format == 0)
1742         {
1743           sql_rollback ();
1744           return 2;
1745         }
1746       if (ultimate == 0)
1747         {
1748           /* It's already in the trashcan. */
1749           sql_commit ();
1750           return 0;
1751         }
1752 
1753       /* Check if it's in use by a trash alert. */
1754 
1755       if (trash_report_format_in_use (report_format))
1756         {
1757           sql_rollback ();
1758           return 1;
1759         }
1760 
1761       /* Remove entirely. */
1762 
1763       permissions_set_orphans ("report_format", report_format, LOCATION_TRASH);
1764       tags_remove_resource ("report_format", report_format, LOCATION_TRASH);
1765 
1766       base = sql_string ("SELECT original_uuid || '.asc'"
1767                          " FROM report_formats_trash"
1768                          " WHERE id = %llu;",
1769                          report_format);
1770       sql ("DELETE FROM report_format_param_options_trash"
1771            " WHERE report_format_param"
1772            " IN (SELECT id from report_format_params_trash"
1773            "     WHERE report_format = %llu);",
1774            report_format);
1775       sql ("DELETE FROM report_format_params_trash WHERE report_format = %llu;",
1776            report_format);
1777       sql ("DELETE FROM report_formats_trash WHERE id = %llu;",
1778            report_format);
1779 
1780       /* Remove the dirs last, in case any SQL rolls back. */
1781 
1782       /* Trash files. */
1783       report_format_string = g_strdup_printf ("%llu", report_format);
1784       dir = report_format_trash_dir (report_format_string);
1785       g_free (report_format_string);
1786       if (gvm_file_exists (dir) && gvm_file_remove_recurse (dir))
1787         {
1788           g_free (dir);
1789           g_free (base);
1790           sql_rollback ();
1791           return -1;
1792         }
1793       g_free (dir);
1794 
1795       /* Links to the feed signatures. */
1796       dir = g_build_filename (GVMD_STATE_DIR, "signatures",
1797                               "report_formats", base, NULL);
1798       g_free (base);
1799       unlink (dir);
1800       g_free (dir);
1801       sql_commit ();
1802 
1803       return 0;
1804     }
1805 
1806   owner_uuid = report_format_owner_uuid (report_format);
1807   dir = g_build_filename (GVMD_STATE_DIR,
1808                           "report_formats",
1809                           owner_uuid,
1810                           report_format_id,
1811                           NULL);
1812   free (owner_uuid);
1813 
1814   if (ultimate)
1815     {
1816       permissions_set_orphans ("report_format", report_format, LOCATION_TABLE);
1817       tags_remove_resource ("report_format", report_format, LOCATION_TABLE);
1818 
1819       /* Check if it's in use by a trash or regular alert. */
1820 
1821       if (sql_int ("SELECT count(*) FROM alert_method_data_trash"
1822                    " WHERE data = (SELECT uuid FROM report_formats"
1823                    "               WHERE id = %llu)"
1824                    " AND (name = 'notice_attach_format'"
1825                    "      OR name = 'notice_report_format');",
1826                    report_format))
1827         {
1828           g_free (dir);
1829           sql_rollback ();
1830           return 1;
1831         }
1832 
1833       if (report_format_in_use (report_format))
1834         {
1835           g_free (dir);
1836           sql_rollback ();
1837           return 1;
1838         }
1839 
1840       /* Remove directory. */
1841 
1842       if (gvm_file_exists (dir) && gvm_file_remove_recurse (dir))
1843         {
1844           g_free (dir);
1845           sql_rollback ();
1846           return -1;
1847         }
1848 
1849       /* Remove from "real" tables. */
1850 
1851       delete_report_format_rows (report_format);
1852     }
1853   else
1854     {
1855       iterator_t params;
1856       gchar *trash_dir, *new_dir, *report_format_string;
1857 
1858       /* Check if it's in use by a regular alert. */
1859 
1860       if (report_format_in_use (report_format))
1861         {
1862           g_free (dir);
1863           sql_rollback ();
1864           return 1;
1865         }
1866 
1867       /* Move to trash. */
1868 
1869       trash_dir = report_format_trash_dir (NULL);
1870       if (g_mkdir_with_parents (trash_dir, 0755 /* "rwxr-xr-x" */))
1871         {
1872           g_warning ("%s: failed to create dir %s", __func__, trash_dir);
1873           g_free (trash_dir);
1874           sql_rollback ();
1875           return -1;
1876         }
1877       g_free (trash_dir);
1878 
1879       sql ("INSERT INTO report_formats_trash"
1880            " (uuid, owner, name, extension, content_type, summary,"
1881            "  description, signature, trust, trust_time, flags, original_uuid,"
1882            "  predefined, creation_time, modification_time)"
1883            " SELECT"
1884            "  %s, owner, name, extension, content_type, summary,"
1885            "  description, signature, trust, trust_time, flags, uuid,"
1886            "  predefined, creation_time, modification_time"
1887            " FROM report_formats"
1888            " WHERE id = %llu;",
1889            report_format_predefined (report_format) ? "uuid" : "make_uuid ()",
1890            report_format);
1891 
1892       trash_report_format = sql_last_insert_id ();
1893 
1894       init_report_format_param_iterator (&params, report_format, 0, 1, NULL);
1895       while (next (&params))
1896         {
1897           report_format_param_t param, trash_param;
1898 
1899           param = report_format_param_iterator_param (&params);
1900 
1901           sql ("INSERT INTO report_format_params_trash"
1902                " (report_format, name, type, value, type_min, type_max,"
1903                "  type_regex, fallback)"
1904                " SELECT"
1905                "  %llu, name, type, value, type_min, type_max,"
1906                "  type_regex, fallback"
1907                " FROM report_format_params"
1908                " WHERE id = %llu;",
1909                trash_report_format,
1910                param);
1911 
1912           trash_param = sql_last_insert_id ();
1913 
1914           sql ("INSERT INTO report_format_param_options_trash"
1915                " (report_format_param, value)"
1916                " SELECT %llu, value"
1917                " FROM report_format_param_options"
1918                " WHERE report_format_param = %llu;",
1919                trash_param,
1920                param);
1921         }
1922       cleanup_iterator (&params);
1923 
1924       permissions_set_locations ("report_format", report_format,
1925                                  trash_report_format, LOCATION_TRASH);
1926       tags_set_locations ("report_format", report_format,
1927                           trash_report_format, LOCATION_TRASH);
1928 
1929       /* Remove from "real" tables. */
1930 
1931       delete_report_format_rows (report_format);
1932 
1933       /* Move the dir last, in case any SQL rolls back. */
1934 
1935       report_format_string = g_strdup_printf ("%llu", trash_report_format);
1936       new_dir = report_format_trash_dir (report_format_string);
1937       g_free (report_format_string);
1938       if (move_report_format_dir (dir, new_dir))
1939         {
1940           g_free (dir);
1941           g_free (new_dir);
1942           sql_rollback ();
1943           return -1;
1944         }
1945       g_free (new_dir);
1946     }
1947 
1948   g_free (dir);
1949 
1950   sql_commit ();
1951 
1952   return 0;
1953 }
1954 
1955 /**
1956  * @brief Try restore a report format.
1957  *
1958  * If success, ends transaction for caller before exiting.
1959  *
1960  * @param[in]  report_format_id  UUID of resource.
1961  *
1962  * @return 0 success, 1 fail because resource is in use, 2 failed to find
1963  *         resource, 4 fail because resource with UUID exists, -1 error.
1964  */
1965 int
restore_report_format(const char * report_format_id)1966 restore_report_format (const char *report_format_id)
1967 {
1968   report_format_t resource, report_format;
1969   iterator_t params;
1970   gchar *dir, *trash_dir, *resource_string;
1971   char *trash_uuid, *owner_uuid;
1972 
1973   if (find_trash ("report_format", report_format_id, &resource))
1974     {
1975       sql_rollback ();
1976       return -1;
1977     }
1978 
1979   if (resource == 0)
1980     return 2;
1981 
1982   if (sql_int ("SELECT count(*) FROM report_formats"
1983                " WHERE name ="
1984                " (SELECT name FROM report_formats_trash WHERE id = %llu)"
1985                " AND " ACL_USER_OWNS () ";",
1986                resource,
1987                current_credentials.uuid))
1988     {
1989       sql_rollback ();
1990       return 3;
1991     }
1992 
1993   if (sql_int ("SELECT count(*) FROM report_formats"
1994                " WHERE uuid = (SELECT original_uuid"
1995                "               FROM report_formats_trash"
1996                "               WHERE id = %llu);",
1997                resource))
1998     {
1999       sql_rollback ();
2000       return 4;
2001     }
2002 
2003   /* Move to "real" tables. */
2004 
2005   sql ("INSERT INTO report_formats"
2006        " (uuid, owner, name, extension, content_type, summary,"
2007        "  description, signature, trust, trust_time, flags,"
2008        "  predefined, creation_time, modification_time)"
2009        " SELECT"
2010        "  original_uuid, owner, name, extension, content_type, summary,"
2011        "  description, signature, trust, trust_time, flags,"
2012        "  predefined, creation_time, modification_time"
2013        " FROM report_formats_trash"
2014        " WHERE id = %llu;",
2015        resource);
2016 
2017   report_format = sql_last_insert_id ();
2018 
2019   init_report_format_param_iterator (&params, resource, 1, 1, NULL);
2020   while (next (&params))
2021     {
2022       report_format_param_t param, trash_param;
2023 
2024       trash_param = report_format_param_iterator_param (&params);
2025 
2026       sql ("INSERT INTO report_format_params"
2027            " (report_format, name, type, value, type_min, type_max,"
2028            "  type_regex, fallback)"
2029            " SELECT"
2030            "  %llu, name, type, value, type_min, type_max,"
2031            "  type_regex, fallback"
2032            " FROM report_format_params_trash"
2033            " WHERE id = %llu;",
2034            report_format,
2035            trash_param);
2036 
2037       param = sql_last_insert_id ();
2038 
2039       sql ("INSERT INTO report_format_param_options"
2040            " (report_format_param, value)"
2041            " SELECT %llu, value"
2042            " FROM report_format_param_options_trash"
2043            " WHERE report_format_param = %llu;",
2044            param,
2045            trash_param);
2046     }
2047   cleanup_iterator (&params);
2048 
2049   trash_uuid = sql_string ("SELECT original_uuid FROM report_formats_trash"
2050                            " WHERE id = %llu;",
2051                            resource);
2052   if (trash_uuid == NULL)
2053     abort ();
2054 
2055   permissions_set_locations ("report_format", resource, report_format,
2056                              LOCATION_TABLE);
2057   tags_set_locations ("report_format", resource, report_format,
2058                       LOCATION_TABLE);
2059 
2060   /* Remove from trash tables. */
2061 
2062   sql ("DELETE FROM report_format_param_options_trash"
2063        " WHERE report_format_param"
2064        " IN (SELECT id from report_format_params_trash"
2065        "     WHERE report_format = %llu);",
2066        resource);
2067   sql ("DELETE FROM report_format_params_trash WHERE report_format = %llu;",
2068        resource);
2069   sql ("DELETE FROM report_formats_trash WHERE id = %llu;",
2070        resource);
2071 
2072   /* Move the dir last, in case any SQL rolls back. */
2073 
2074   owner_uuid = report_format_owner_uuid (report_format);
2075   dir = g_build_filename (GVMD_STATE_DIR,
2076                           "report_formats",
2077                           owner_uuid,
2078                           trash_uuid,
2079                           NULL);
2080   free (trash_uuid);
2081   free (owner_uuid);
2082 
2083   resource_string = g_strdup_printf ("%llu", resource);
2084   trash_dir = report_format_trash_dir (resource_string);
2085   g_free (resource_string);
2086   if (move_report_format_dir (trash_dir, dir))
2087     {
2088       g_free (dir);
2089       g_free (trash_dir);
2090       sql_rollback ();
2091       return -1;
2092     }
2093   g_free (dir);
2094   g_free (trash_dir);
2095 
2096   sql_commit ();
2097   return 0;
2098 }
2099 
2100 /**
2101  * @brief Return the UUID of a report format.
2102  *
2103  * @param[in]  report_format  Report format.
2104  *
2105  * @return Newly allocated UUID.
2106  */
2107 char *
report_format_uuid(report_format_t report_format)2108 report_format_uuid (report_format_t report_format)
2109 {
2110   return sql_string ("SELECT uuid FROM report_formats WHERE id = %llu;",
2111                      report_format);
2112 }
2113 
2114 /**
2115  * @brief Return the UUID of the owner of a report format.
2116  *
2117  * @param[in]  report_format  Report format.
2118  *
2119  * @return Newly allocated owner UUID if there is an owner, else NULL.
2120  */
2121 char *
report_format_owner_uuid(report_format_t report_format)2122 report_format_owner_uuid (report_format_t report_format)
2123 {
2124   if (sql_int ("SELECT " ACL_IS_GLOBAL () " FROM report_formats"
2125                " WHERE id = %llu;",
2126                report_format))
2127     return NULL;
2128   return sql_string ("SELECT uuid FROM users"
2129                      " WHERE id = (SELECT owner FROM report_formats"
2130                      "             WHERE id = %llu);",
2131                      report_format);
2132 }
2133 
2134 /**
2135  * @brief Set the active flag of a report format.
2136  *
2137  * @param[in]  report_format  The report format.
2138  * @param[in]  active         Active flag.
2139  */
2140 static void
set_report_format_active(report_format_t report_format,int active)2141 set_report_format_active (report_format_t report_format, int active)
2142 {
2143   if (active)
2144     sql ("UPDATE report_formats SET flags = (flags | %llu), "
2145          "                          modification_time = m_now ()"
2146          " WHERE id = %llu;",
2147          (long long int) REPORT_FORMAT_FLAG_ACTIVE,
2148          report_format);
2149   else
2150     sql ("UPDATE report_formats SET flags = (flags & ~ %llu), "
2151          "                          modification_time = m_now ()"
2152          " WHERE id = %llu;",
2153          (long long int) REPORT_FORMAT_FLAG_ACTIVE,
2154          report_format);
2155 }
2156 
2157 /**
2158  * @brief Return the name of a report format.
2159  *
2160  * @param[in]  report_format  Report format.
2161  *
2162  * @return Newly allocated name.
2163  */
2164 char *
report_format_name(report_format_t report_format)2165 report_format_name (report_format_t report_format)
2166 {
2167   return sql_string ("SELECT name FROM report_formats WHERE id = %llu;",
2168                      report_format);
2169 }
2170 
2171 /**
2172  * @brief Return the content type of a report format.
2173  *
2174  * @param[in]  report_format  Report format.
2175  *
2176  * @return Newly allocated content type.
2177  */
2178 char *
report_format_content_type(report_format_t report_format)2179 report_format_content_type (report_format_t report_format)
2180 {
2181   return sql_string ("SELECT content_type FROM report_formats"
2182                      " WHERE id = %llu;",
2183                      report_format);
2184 }
2185 
2186 /**
2187  * @brief Return whether a report format is referenced by an alert.
2188  *
2189  * @param[in]  report_format  Report Format.
2190  *
2191  * @return 1 if in use, else 0.
2192  */
2193 int
report_format_in_use(report_format_t report_format)2194 report_format_in_use (report_format_t report_format)
2195 {
2196   return !!sql_int ("SELECT count(*) FROM alert_method_data"
2197                     " WHERE data = (SELECT uuid FROM report_formats"
2198                     "               WHERE id = %llu)"
2199                     " AND (name = 'notice_attach_format'"
2200                     "      OR name = 'notice_report_format'"
2201                     "      OR name = 'scp_report_format'"
2202                     "      OR name = 'send_report_format'"
2203                     "      OR name = 'smb_report_format'"
2204                     "      OR name = 'verinice_server_report_format');",
2205                     report_format);
2206 }
2207 
2208 /**
2209  * @brief Return whether a report format in trash is referenced by an alert.
2210  *
2211  * @param[in]  report_format  Report Format.
2212  *
2213  * @return 1 if in use, else 0.
2214  */
2215 int
trash_report_format_in_use(report_format_t report_format)2216 trash_report_format_in_use (report_format_t report_format)
2217 {
2218   return !!sql_int ("SELECT count(*) FROM alert_method_data_trash"
2219                     " WHERE data = (SELECT original_uuid"
2220                     "               FROM report_formats_trash"
2221                     "               WHERE id = %llu)"
2222                     " AND (name = 'notice_attach_format'"
2223                     "      OR name = 'notice_report_format'"
2224                     "      OR name = 'scp_report_format'"
2225                     "      OR name = 'send_report_format'"
2226                     "      OR name = 'smb_report_format'"
2227                     "      OR name = 'verinice_server_report_format');",
2228                     report_format);
2229 }
2230 
2231 /**
2232  * @brief Return whether a report format is predefined.
2233  *
2234  * @param[in]  report_format  Report format.
2235  *
2236  * @return 1 if predefined, else 0.
2237  */
2238 int
report_format_predefined(report_format_t report_format)2239 report_format_predefined (report_format_t report_format)
2240 {
2241   return sql_int ("SELECT predefined FROM report_formats"
2242                   " WHERE id = %llu;",
2243                   report_format);
2244 }
2245 
2246 /**
2247  * @brief Return whether a trash report format is predefined.
2248  *
2249  * @param[in]  report_format  Report format.
2250  *
2251  * @return 1 if predefined, else 0.
2252  */
2253 int
trash_report_format_predefined(report_format_t report_format)2254 trash_report_format_predefined (report_format_t report_format)
2255 {
2256   return sql_int ("SELECT predefined FROM report_formats_trash"
2257                   " WHERE id = %llu;",
2258                   report_format);
2259 }
2260 
2261 /**
2262  * @brief Return the extension of a report format.
2263  *
2264  * @param[in]  report_format  Report format.
2265  *
2266  * @return Newly allocated extension.
2267  */
2268 char *
report_format_extension(report_format_t report_format)2269 report_format_extension (report_format_t report_format)
2270 {
2271   return sql_string ("SELECT extension FROM report_formats WHERE id = %llu;",
2272                      report_format);
2273 }
2274 
2275 /**
2276  * @brief Set the name of the report format.
2277  *
2278  * @param[in]  report_format  The report format.
2279  * @param[in]  name           Name.
2280  */
2281 static void
set_report_format_name(report_format_t report_format,const char * name)2282 set_report_format_name (report_format_t report_format, const char *name)
2283 {
2284   gchar *quoted_name = sql_quote (name);
2285   sql ("UPDATE report_formats SET name = '%s', modification_time = m_now ()"
2286        " WHERE id = %llu;",
2287        quoted_name,
2288        report_format);
2289   g_free (quoted_name);
2290 }
2291 
2292 /**
2293  * @brief Return whether a report format is active.
2294  *
2295  * @param[in]  report_format  Report format.
2296  *
2297  * @return -1 on error, 1 if active, else 0.
2298  */
2299 int
report_format_active(report_format_t report_format)2300 report_format_active (report_format_t report_format)
2301 {
2302   long long int flag;
2303   switch (sql_int64 (&flag,
2304                      "SELECT flags & %llu FROM report_formats"
2305                      " WHERE id = %llu;",
2306                      (long long int) REPORT_FORMAT_FLAG_ACTIVE,
2307                      report_format))
2308     {
2309       case 0:
2310         break;
2311       case 1:        /* Too few rows in result of query. */
2312         return 0;
2313         break;
2314       default:       /* Programming error. */
2315         assert (0);
2316       case -1:
2317         return -1;
2318         break;
2319     }
2320   return flag ? 1 : 0;
2321 }
2322 
2323 /**
2324  * @brief Set the summary of the report format.
2325  *
2326  * @param[in]  report_format  The report format.
2327  * @param[in]  summary        Summary.
2328  */
2329 static void
set_report_format_summary(report_format_t report_format,const char * summary)2330 set_report_format_summary (report_format_t report_format, const char *summary)
2331 {
2332   gchar *quoted_summary = sql_quote (summary);
2333   sql ("UPDATE report_formats SET summary = '%s', modification_time = m_now ()"
2334        " WHERE id = %llu;",
2335        quoted_summary,
2336        report_format);
2337   g_free (quoted_summary);
2338 }
2339 
2340 /**
2341  * @brief Return the type max of a report format param.
2342  *
2343  * @param[in]  report_format  Report format.
2344  * @param[in]  name           Name of param.
2345  *
2346  * @return Param type.
2347  */
2348 static report_format_param_type_t
report_format_param_type(report_format_t report_format,const char * name)2349 report_format_param_type (report_format_t report_format, const char *name)
2350 {
2351   report_format_param_type_t type;
2352   gchar *quoted_name = sql_quote (name);
2353   type = (report_format_param_type_t)
2354          sql_int ("SELECT type FROM report_format_params"
2355                   " WHERE report_format = %llu AND name = '%s';",
2356                   report_format,
2357                   quoted_name);
2358   g_free (quoted_name);
2359   return type;
2360 }
2361 
2362 /**
2363  * @brief Return the type max of a report format param.
2364  *
2365  * @param[in]  report_format  Report format.
2366  * @param[in]  name           Name of param.
2367  *
2368  * @return Max.
2369  */
2370 static long long int
report_format_param_type_max(report_format_t report_format,const char * name)2371 report_format_param_type_max (report_format_t report_format, const char *name)
2372 {
2373   long long int max = 0;
2374   gchar *quoted_name = sql_quote (name);
2375   /* Assume it's there. */
2376   sql_int64 (&max,
2377              "SELECT type_max FROM report_format_params"
2378              " WHERE report_format = %llu AND name = '%s';",
2379              report_format,
2380              quoted_name);
2381   g_free (quoted_name);
2382   return max;
2383 }
2384 
2385 /**
2386  * @brief Return the type min of a report format param.
2387  *
2388  * @param[in]  report_format  Report format.
2389  * @param[in]  name           Name of param.
2390  *
2391  * @return Min.
2392  */
2393 static long long int
report_format_param_type_min(report_format_t report_format,const char * name)2394 report_format_param_type_min (report_format_t report_format, const char *name)
2395 {
2396   long long int min = 0;
2397   gchar *quoted_name = sql_quote (name);
2398   /* Assume it's there. */
2399   sql_int64 (&min,
2400              "SELECT type_min FROM report_format_params"
2401              " WHERE report_format = %llu AND name = '%s';",
2402              report_format,
2403              quoted_name);
2404   g_free (quoted_name);
2405   return min;
2406 }
2407 
2408 /**
2409  * @brief Validate a value for a report format param.
2410  *
2411  * @param[in]  report_format  Report format.
2412  * @param[in]  param          Param.
2413  * @param[in]  name           Name of param.
2414  * @param[in]  value          Potential value of param.
2415  *
2416  * @return 0 success, 1 fail.
2417  */
2418 static int
validate_param_value(report_format_t report_format,report_format_param_t param,const char * name,const char * value)2419 validate_param_value (report_format_t report_format,
2420                       report_format_param_t param, const char *name,
2421                       const char *value)
2422 {
2423   switch (report_format_param_type (report_format, name))
2424     {
2425       case REPORT_FORMAT_PARAM_TYPE_INTEGER:
2426         {
2427           long long int min, max, actual;
2428           min = report_format_param_type_min (report_format, name);
2429           /* Simply truncate out of range values. */
2430           actual = strtoll (value, NULL, 0);
2431           if (actual < min)
2432             return 1;
2433           max = report_format_param_type_max (report_format, name);
2434           if (actual > max)
2435             return 1;
2436         }
2437         break;
2438       case REPORT_FORMAT_PARAM_TYPE_SELECTION:
2439         {
2440           iterator_t options;
2441           int found = 0;
2442 
2443           init_param_option_iterator (&options, param, 1, NULL);
2444           while (next (&options))
2445             if (param_option_iterator_value (&options)
2446                 && (strcmp (param_option_iterator_value (&options), value)
2447                     == 0))
2448               {
2449                 found = 1;
2450                 break;
2451               }
2452           cleanup_iterator (&options);
2453           if (found)
2454             break;
2455           return 1;
2456         }
2457       case REPORT_FORMAT_PARAM_TYPE_STRING:
2458       case REPORT_FORMAT_PARAM_TYPE_TEXT:
2459         {
2460           long long int min, max, actual;
2461           min = report_format_param_type_min (report_format, name);
2462           actual = strlen (value);
2463           if (actual < min)
2464             return 1;
2465           max = report_format_param_type_max (report_format, name);
2466           if (actual > max)
2467             return 1;
2468         }
2469         break;
2470       case REPORT_FORMAT_PARAM_TYPE_REPORT_FORMAT_LIST:
2471         {
2472           if (g_regex_match_simple
2473                 ("^(?:[[:alnum:]-_]+)?(?:,(?:[[:alnum:]-_])+)*$", value, 0, 0)
2474               == FALSE)
2475             return 1;
2476           else
2477             return 0;
2478         }
2479         break;
2480       default:
2481         break;
2482     }
2483   return 0;
2484 }
2485 
2486 /**
2487  * @brief Set the value of the report format param.
2488  *
2489  * @param[in]  report_format  The report format.
2490  * @param[in]  name           Param name.
2491  * @param[in]  value_64       Param value in base64.
2492  *
2493  * @return 0 success, 1 failed to find param, 2 validation of value failed,
2494  *         -1 error.
2495  */
2496 static int
set_report_format_param(report_format_t report_format,const char * name,const char * value_64)2497 set_report_format_param (report_format_t report_format, const char *name,
2498                          const char *value_64)
2499 {
2500   gchar *quoted_name, *quoted_value, *value;
2501   gsize value_size;
2502   report_format_param_t param;
2503 
2504   quoted_name = sql_quote (name);
2505 
2506   sql_begin_immediate ();
2507 
2508   /* Ensure the param exists. */
2509 
2510   switch (sql_int64 (&param,
2511                      "SELECT id FROM report_format_params"
2512                      " WHERE name = '%s';",
2513                      quoted_name))
2514     {
2515       case 0:
2516         break;
2517       case 1:        /* Too few rows in result of query. */
2518         g_free (quoted_name);
2519         sql_rollback ();
2520         return 1;
2521         break;
2522       default:       /* Programming error. */
2523         assert (0);
2524       case -1:
2525         g_free (quoted_name);
2526         sql_rollback ();
2527         return -1;
2528         break;
2529     }
2530 
2531   /* Translate the value. */
2532 
2533   if (value_64 && strlen (value_64))
2534     value = (gchar*) g_base64_decode (value_64, &value_size);
2535   else
2536     {
2537       value = g_strdup ("");
2538       value_size = 0;
2539     }
2540 
2541   /* Validate the value. */
2542 
2543   if (validate_param_value (report_format, param, name, value))
2544     {
2545       sql_rollback ();
2546       g_free (quoted_name);
2547       return 2;
2548     }
2549 
2550   quoted_value = sql_quote (value);
2551   g_free (value);
2552 
2553   /* Update the database. */
2554 
2555   sql ("UPDATE report_format_params SET value = '%s'"
2556        " WHERE report_format = %llu AND name = '%s';",
2557        quoted_value,
2558        report_format,
2559        quoted_name);
2560 
2561   g_free (quoted_name);
2562   g_free (quoted_value);
2563 
2564   sql_commit ();
2565 
2566   return 0;
2567 }
2568 
2569 /**
2570  * @brief Return the trust of a report format.
2571  *
2572  * @param[in]  report_format  Report format.
2573  *
2574  * @return Trust: 1 yes, 2 no, 3 unknown.
2575  */
2576 int
report_format_trust(report_format_t report_format)2577 report_format_trust (report_format_t report_format)
2578 {
2579   return sql_int ("SELECT trust FROM report_formats WHERE id = %llu;",
2580                   report_format);
2581 }
2582 
2583 /**
2584  * @brief Filter columns for Report Format iterator.
2585  */
2586 #define REPORT_FORMAT_ITERATOR_FILTER_COLUMNS                                 \
2587  { ANON_GET_ITERATOR_FILTER_COLUMNS, "name", "extension", "content_type",     \
2588    "summary", "description", "trust", "trust_time", "active", "predefined",   \
2589    NULL }
2590 
2591 /**
2592  * @brief Report Format iterator columns.
2593  */
2594 #define REPORT_FORMAT_ITERATOR_COLUMNS                                  \
2595  {                                                                      \
2596    { "id", NULL, KEYWORD_TYPE_INTEGER },                                \
2597    { "uuid", NULL, KEYWORD_TYPE_STRING },                               \
2598    { "name", NULL, KEYWORD_TYPE_STRING },                               \
2599    { "''", NULL, KEYWORD_TYPE_STRING },                                 \
2600    { "iso_time (creation_time)", NULL, KEYWORD_TYPE_STRING },           \
2601    { "iso_time (modification_time)", NULL, KEYWORD_TYPE_STRING },       \
2602    { "creation_time", "created", KEYWORD_TYPE_INTEGER },                \
2603    { "modification_time", "modified", KEYWORD_TYPE_INTEGER },           \
2604    {                                                                    \
2605      "(SELECT name FROM users WHERE users.id = report_formats.owner)",  \
2606      "_owner",                                                          \
2607      KEYWORD_TYPE_STRING                                                \
2608    },                                                                   \
2609    { "owner", NULL, KEYWORD_TYPE_INTEGER },                             \
2610    { "extension", NULL, KEYWORD_TYPE_STRING },                          \
2611    { "content_type", NULL, KEYWORD_TYPE_STRING },                       \
2612    { "summary", NULL, KEYWORD_TYPE_STRING },                            \
2613    { "description", NULL, KEYWORD_TYPE_STRING },                        \
2614    { "signature", NULL, KEYWORD_TYPE_STRING },                          \
2615    { "trust", NULL, KEYWORD_TYPE_INTEGER },                             \
2616    { "trust_time", NULL, KEYWORD_TYPE_INTEGER },                        \
2617    { "flags & 1", "active", KEYWORD_TYPE_INTEGER },                     \
2618    { "predefined", NULL, KEYWORD_TYPE_INTEGER },                        \
2619    { NULL, NULL, KEYWORD_TYPE_UNKNOWN }                                 \
2620  }
2621 
2622 /**
2623  * @brief Report Format iterator columns for trash case.
2624  */
2625 #define REPORT_FORMAT_ITERATOR_TRASH_COLUMNS                            \
2626  {                                                                      \
2627    { "id", NULL, KEYWORD_TYPE_INTEGER },                                \
2628    { "uuid", NULL, KEYWORD_TYPE_STRING },                               \
2629    { "name", NULL, KEYWORD_TYPE_STRING },                               \
2630    { "''", NULL, KEYWORD_TYPE_STRING },                                 \
2631    { "iso_time (creation_time)", NULL, KEYWORD_TYPE_STRING },           \
2632    { "iso_time (modification_time)", NULL, KEYWORD_TYPE_STRING },       \
2633    { "creation_time", "created", KEYWORD_TYPE_INTEGER },                \
2634    { "modification_time", "modified", KEYWORD_TYPE_INTEGER },           \
2635    {                                                                    \
2636      "(SELECT name FROM users"                                          \
2637      " WHERE users.id = report_formats_trash.owner)",                   \
2638      "_owner",                                                          \
2639      KEYWORD_TYPE_STRING                                                \
2640    },                                                                   \
2641    { "owner", NULL, KEYWORD_TYPE_INTEGER },                             \
2642    { "extension", NULL, KEYWORD_TYPE_STRING },                          \
2643    { "content_type", NULL, KEYWORD_TYPE_STRING },                       \
2644    { "summary", NULL, KEYWORD_TYPE_STRING },                            \
2645    { "description", NULL, KEYWORD_TYPE_STRING },                        \
2646    { "signature", NULL, KEYWORD_TYPE_STRING },                          \
2647    { "trust", NULL, KEYWORD_TYPE_INTEGER },                             \
2648    { "trust_time", NULL, KEYWORD_TYPE_INTEGER },                        \
2649    { "flags & 1", "active", KEYWORD_TYPE_INTEGER },                     \
2650    { "predefined", NULL, KEYWORD_TYPE_INTEGER },                        \
2651    { NULL, NULL, KEYWORD_TYPE_UNKNOWN }                                 \
2652  }
2653 
2654 /**
2655  * @brief Get filter columns.
2656  *
2657  * @return Constant array of filter columns.
2658  */
2659 const char**
report_format_filter_columns()2660 report_format_filter_columns ()
2661 {
2662   static const char *columns[] = REPORT_FORMAT_ITERATOR_FILTER_COLUMNS;
2663   return columns;
2664 }
2665 
2666 /**
2667  * @brief Get select columns.
2668  *
2669  * @return Constant array of select columns.
2670  */
2671 column_t*
report_format_select_columns()2672 report_format_select_columns ()
2673 {
2674   static column_t columns[] = REPORT_FORMAT_ITERATOR_COLUMNS;
2675   return columns;
2676 }
2677 
2678 /**
2679  * @brief Count the number of Report Formats.
2680  *
2681  * @param[in]  get  GET params.
2682  *
2683  * @return Total number of Report Formats filtered set.
2684  */
2685 int
report_format_count(const get_data_t * get)2686 report_format_count (const get_data_t *get)
2687 {
2688   static const char *filter_columns[] = REPORT_FORMAT_ITERATOR_FILTER_COLUMNS;
2689   static column_t columns[] = REPORT_FORMAT_ITERATOR_COLUMNS;
2690   static column_t trash_columns[] = REPORT_FORMAT_ITERATOR_TRASH_COLUMNS;
2691   return count ("report_format", get, columns, trash_columns, filter_columns,
2692                 0, 0, 0, TRUE);
2693 }
2694 
2695 /**
2696  * @brief Initialise a Report Format iterator, including observed Report
2697  *        Formats.
2698  *
2699  * @param[in]  iterator    Iterator.
2700  * @param[in]  get         GET data.
2701  *
2702  * @return 0 success, 1 failed to find Report Format, 2 failed to find filter,
2703  *         -1 error.
2704  */
2705 int
init_report_format_iterator(iterator_t * iterator,const get_data_t * get)2706 init_report_format_iterator (iterator_t* iterator, const get_data_t *get)
2707 {
2708   static const char *filter_columns[] = REPORT_FORMAT_ITERATOR_FILTER_COLUMNS;
2709   static column_t columns[] = REPORT_FORMAT_ITERATOR_COLUMNS;
2710   static column_t trash_columns[] = REPORT_FORMAT_ITERATOR_TRASH_COLUMNS;
2711 
2712   return init_get_iterator (iterator,
2713                             "report_format",
2714                             get,
2715                             columns,
2716                             trash_columns,
2717                             filter_columns,
2718                             0,
2719                             NULL,
2720                             NULL,
2721                             TRUE);
2722 }
2723 
2724 /**
2725  * @brief Get the extension from a report format iterator.
2726  *
2727  * @param[in]  iterator  Iterator.
2728  *
2729  * @return Extension, or NULL if iteration is complete.  Freed by
2730  *         cleanup_iterator.
2731  */
2732 DEF_ACCESS (report_format_iterator_extension, GET_ITERATOR_COLUMN_COUNT);
2733 
2734 /**
2735  * @brief Get the content type from a report format iterator.
2736  *
2737  * @param[in]  iterator  Iterator.
2738  *
2739  * @return Content type, or NULL if iteration is complete.  Freed by
2740  *         cleanup_iterator.
2741  */
2742 DEF_ACCESS (report_format_iterator_content_type, GET_ITERATOR_COLUMN_COUNT + 1);
2743 
2744 /**
2745  * @brief Get the summary from a report format iterator.
2746  *
2747  * @param[in]  iterator  Iterator.
2748  *
2749  * @return Summary, or NULL if iteration is complete.  Freed by
2750  *         cleanup_iterator.
2751  */
2752 DEF_ACCESS (report_format_iterator_summary, GET_ITERATOR_COLUMN_COUNT + 2);
2753 
2754 /**
2755  * @brief Get the description from a report format iterator.
2756  *
2757  * @param[in]  iterator  Iterator.
2758  *
2759  * @return Description, or NULL if iteration is complete.  Freed by
2760  *         cleanup_iterator.
2761  */
2762 DEF_ACCESS (report_format_iterator_description, GET_ITERATOR_COLUMN_COUNT + 3);
2763 
2764 /**
2765  * @brief Get the signature from a report format iterator.
2766  *
2767  * @param[in]  iterator  Iterator.
2768  *
2769  * @return Signature, or NULL if iteration is complete.  Freed by
2770  *         cleanup_iterator.
2771  */
2772 DEF_ACCESS (report_format_iterator_signature, GET_ITERATOR_COLUMN_COUNT + 4);
2773 
2774 /**
2775  * @brief Get the trust value from a report format iterator.
2776  *
2777  * @param[in]  iterator  Iterator.
2778  *
2779  * @return Trust value.
2780  */
2781 const char*
report_format_iterator_trust(iterator_t * iterator)2782 report_format_iterator_trust (iterator_t* iterator)
2783 {
2784   if (iterator->done) return NULL;
2785   switch (iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 5))
2786     {
2787       case 1:  return "yes";
2788       case 2:  return "no";
2789       case 3:  return "unknown";
2790       default: return NULL;
2791     }
2792 }
2793 
2794 /**
2795  * @brief Get the trust time from a report format iterator.
2796  *
2797  * @param[in]  iterator  Iterator.
2798  *
2799  * @return Time report format was verified.
2800  */
2801 time_t
report_format_iterator_trust_time(iterator_t * iterator)2802 report_format_iterator_trust_time (iterator_t* iterator)
2803 {
2804   int ret;
2805   if (iterator->done) return -1;
2806   ret = (time_t) iterator_int (iterator, GET_ITERATOR_COLUMN_COUNT + 6);
2807   return ret;
2808 }
2809 
2810 /**
2811  * @brief Get the active flag from a report format iterator.
2812  *
2813  * @param[in]  iterator  Iterator.
2814  *
2815  * @return Active flag, or -1 if iteration is complete.
2816  */
2817 int
report_format_iterator_active(iterator_t * iterator)2818 report_format_iterator_active (iterator_t* iterator)
2819 {
2820   if (iterator->done) return -1;
2821   return (iterator_int64 (iterator, GET_ITERATOR_COLUMN_COUNT + 7)
2822           & REPORT_FORMAT_FLAG_ACTIVE) ? 1 : 0;
2823 }
2824 
2825 /**
2826  * @brief Initialise a Report Format alert iterator.
2827  *
2828  * Iterates over all alerts that use the Report Format.
2829  *
2830  * @param[in]  iterator          Iterator.
2831  * @param[in]  report_format     Report Format.
2832  */
2833 void
init_report_format_alert_iterator(iterator_t * iterator,report_format_t report_format)2834 init_report_format_alert_iterator (iterator_t* iterator,
2835                                    report_format_t report_format)
2836 {
2837   gchar *available, *with_clause;
2838   get_data_t get;
2839   array_t *permissions;
2840 
2841   assert (report_format);
2842 
2843   get.trash = 0;
2844   permissions = make_array ();
2845   array_add (permissions, g_strdup ("get_alerts"));
2846   available = acl_where_owned ("alert", &get, 1, "any", 0, permissions, 0,
2847                                &with_clause);
2848   array_free (permissions);
2849 
2850   init_iterator (iterator,
2851                  "%s"
2852                  " SELECT DISTINCT alerts.name, alerts.uuid, %s"
2853                  " FROM alerts, alert_method_data"
2854                  " WHERE alert_method_data.data = '%s'"
2855                  " AND alert_method_data.alert = alerts.id"
2856                  " ORDER BY alerts.name ASC;",
2857                  with_clause ? with_clause : "",
2858                  available,
2859                  report_format_uuid (report_format));
2860 
2861   g_free (with_clause);
2862   g_free (available);
2863 }
2864 
2865 /**
2866  * @brief Get the name from a report_format_alert iterator.
2867  *
2868  * @param[in]  iterator  Iterator.
2869  *
2870  * @return The name of the Report Format, or NULL if iteration is complete.
2871  *         Freed by cleanup_iterator.
2872  */
2873 DEF_ACCESS (report_format_alert_iterator_name, 0);
2874 
2875 /**
2876  * @brief Get the UUID from a report_format_alert iterator.
2877  *
2878  * @param[in]  iterator  Iterator.
2879  *
2880  * @return The UUID of the Report Format, or NULL if iteration is complete.
2881  *         Freed by cleanup_iterator.
2882  */
2883 DEF_ACCESS (report_format_alert_iterator_uuid, 1);
2884 
2885 /**
2886  * @brief Get the read permission status from a GET iterator.
2887  *
2888  * @param[in]  iterator  Iterator.
2889  *
2890  * @return 1 if may read, else 0.
2891  */
2892 int
report_format_alert_iterator_readable(iterator_t * iterator)2893 report_format_alert_iterator_readable (iterator_t* iterator)
2894 {
2895   if (iterator->done) return 0;
2896   return iterator_int (iterator, 2);
2897 }
2898 
2899 /**
2900  * @brief Initialise a report format iterator.
2901  *
2902  * @param[in]  iterator       Iterator.
2903  * @param[in]  report_format  Single report_format to iterate over, or 0 for all.
2904  * @param[in]  trash          Whether to iterate over trashcan report formats.
2905  * @param[in]  ascending      Whether to sort ascending or descending.
2906  * @param[in]  sort_field     Field to sort on, or NULL for "id".
2907  */
2908 void
init_report_format_param_iterator(iterator_t * iterator,report_format_t report_format,int trash,int ascending,const char * sort_field)2909 init_report_format_param_iterator (iterator_t* iterator,
2910                                    report_format_t report_format,
2911                                    int trash,
2912                                    int ascending,
2913                                    const char* sort_field)
2914 {
2915   if (report_format)
2916     init_iterator (iterator,
2917                    "SELECT id, name, value, type, type_min, type_max,"
2918                    " type_regex, fallback"
2919                    " FROM report_format_params%s"
2920                    " WHERE report_format = %llu"
2921                    " ORDER BY %s %s;",
2922                    trash ? "_trash" : "",
2923                    report_format,
2924                    sort_field ? sort_field : "id",
2925                    ascending ? "ASC" : "DESC");
2926   else
2927     init_iterator (iterator,
2928                    "SELECT id, name, value, type, type_min, type_max,"
2929                    " type_regex, fallback"
2930                    " FROM report_format_params%s"
2931                    " ORDER BY %s %s;",
2932                    trash ? "_trash" : "",
2933                    sort_field ? sort_field : "id",
2934                    ascending ? "ASC" : "DESC");
2935 }
2936 
2937 /**
2938  * @brief Get the report format param from a report format param iterator.
2939  *
2940  * @param[in]  iterator  Iterator.
2941  *
2942  * @return Report format param.
2943  */
2944 report_format_param_t
report_format_param_iterator_param(iterator_t * iterator)2945 report_format_param_iterator_param (iterator_t* iterator)
2946 {
2947   if (iterator->done) return 0;
2948   return (report_format_param_t) iterator_int64 (iterator, 0);
2949 }
2950 
2951 /**
2952  * @brief Get the name from a report format param iterator.
2953  *
2954  * @param[in]  iterator  Iterator.
2955  *
2956  * @return Name, or NULL if iteration is complete.  Freed by
2957  *         cleanup_iterator.
2958  */
2959 DEF_ACCESS (report_format_param_iterator_name, 1);
2960 
2961 /**
2962  * @brief Get the value from a report format param iterator.
2963  *
2964  * @param[in]  iterator  Iterator.
2965  *
2966  * @return Value, or NULL if iteration is complete.  Freed by
2967  *         cleanup_iterator.
2968  */
2969 DEF_ACCESS (report_format_param_iterator_value, 2);
2970 
2971 /**
2972  * @brief Get the name of the type of a report format param iterator.
2973  *
2974  * @param[in]  iterator  Iterator.
2975  *
2976  * @return Static string naming type, or NULL if iteration is complete.
2977  */
2978 const char *
report_format_param_iterator_type_name(iterator_t * iterator)2979 report_format_param_iterator_type_name (iterator_t* iterator)
2980 {
2981   if (iterator->done) return NULL;
2982   return report_format_param_type_name (iterator_int (iterator, 3));
2983 }
2984 
2985 /**
2986  * @brief Get the type from a report format param iterator.
2987  *
2988  * @param[in]  iterator  Iterator.
2989  *
2990  * @return Type.
2991  */
2992 report_format_param_type_t
report_format_param_iterator_type(iterator_t * iterator)2993 report_format_param_iterator_type (iterator_t* iterator)
2994 {
2995   if (iterator->done) return -1;
2996   return iterator_int (iterator, 3);
2997 }
2998 
2999 /**
3000  * @brief Get the type min from a report format param iterator.
3001  *
3002  * @param[in]  iterator  Iterator.
3003  *
3004  * @return Type min.
3005  */
3006 long long int
report_format_param_iterator_type_min(iterator_t * iterator)3007 report_format_param_iterator_type_min (iterator_t* iterator)
3008 {
3009   if (iterator->done) return -1;
3010   return iterator_int64 (iterator, 4);
3011 }
3012 
3013 /**
3014  * @brief Get the type max from a report format param iterator.
3015  *
3016  * @param[in]  iterator  Iterator.
3017  *
3018  * @return Type max.
3019  */
3020 long long int
report_format_param_iterator_type_max(iterator_t * iterator)3021 report_format_param_iterator_type_max (iterator_t* iterator)
3022 {
3023   if (iterator->done) return -1;
3024   return iterator_int64 (iterator, 5);
3025 }
3026 
3027 /**
3028  * @brief Get the type regex from a report format param iterator.
3029  *
3030  * @param[in]  iterator  Iterator.
3031  *
3032  * @return Type regex, or NULL if iteration is complete.  Freed by
3033  *         cleanup_iterator.
3034  */
3035 static
3036 DEF_ACCESS (report_format_param_iterator_type_regex, 6);
3037 
3038 /**
3039  * @brief Get the default from a report format param iterator.
3040  *
3041  * @param[in]  iterator  Iterator.
3042  *
3043  * @return Default, or NULL if iteration is complete.  Freed by
3044  *         cleanup_iterator.
3045  */
3046 DEF_ACCESS (report_format_param_iterator_fallback, 7);
3047 
3048 /**
3049  * @brief Initialise a report format param option iterator.
3050  *
3051  * @param[in]  iterator             Iterator.
3052  * @param[in]  report_format_param  Param whose options to iterate over.
3053  * @param[in]  ascending            Whether to sort ascending or descending.
3054  * @param[in]  sort_field           Field to sort on, or NULL for "id".
3055  */
3056 void
init_param_option_iterator(iterator_t * iterator,report_format_param_t report_format_param,int ascending,const char * sort_field)3057 init_param_option_iterator (iterator_t* iterator,
3058                             report_format_param_t report_format_param,
3059                             int ascending, const char *sort_field)
3060 {
3061   init_iterator (iterator,
3062                  "SELECT id, value"
3063                  " FROM report_format_param_options"
3064                  " WHERE report_format_param = %llu"
3065                  " ORDER BY %s %s;",
3066                  report_format_param,
3067                  sort_field ? sort_field : "id",
3068                  ascending ? "ASC" : "DESC");
3069 }
3070 
3071 /**
3072  * @brief Get the value from a report format param option iterator.
3073  *
3074  * @param[in]  iterator  Iterator.
3075  *
3076  * @return Value, or NULL if iteration is complete.  Freed by
3077  *         cleanup_iterator.
3078  */
3079 DEF_ACCESS (param_option_iterator_value, 1);
3080 
3081 /**
3082  * @brief Verify a report format.
3083  *
3084  * @param[in]  report_format  Report format.
3085  *
3086  * @return 0 success, -1 error.
3087  */
3088 static int
verify_report_format_internal(report_format_t report_format)3089 verify_report_format_internal (report_format_t report_format)
3090 {
3091   int format_trust = TRUST_UNKNOWN;
3092   iterator_t formats;
3093   get_data_t get;
3094   gchar *uuid;
3095 
3096   memset(&get, '\0', sizeof (get));
3097   get.id = report_format_uuid (report_format);
3098   init_report_format_iterator (&formats, &get);
3099   if (next (&formats))
3100     {
3101       const char *signature;
3102       gchar *format_signature = NULL;
3103       gsize format_signature_size;
3104 
3105       signature = report_format_iterator_signature (&formats);
3106 
3107       find_signature ("report_formats", get_iterator_uuid (&formats),
3108                       &format_signature, &format_signature_size, &uuid);
3109 
3110       if ((signature && strlen (signature))
3111           || format_signature)
3112         {
3113           GString *format;
3114           file_iterator_t files;
3115           iterator_t params;
3116 
3117           format = g_string_new ("");
3118 
3119           g_string_append_printf
3120            (format, "%s%s%s%i", uuid ? uuid : get_iterator_uuid (&formats),
3121             report_format_iterator_extension (&formats),
3122             report_format_iterator_content_type (&formats),
3123             report_format_predefined (report_format) & 1);
3124           g_free (uuid);
3125 
3126           init_report_format_file_iterator (&files, report_format);
3127           while (next_file (&files))
3128             {
3129               gchar *content = file_iterator_content_64 (&files);
3130               g_string_append_printf (format,
3131                                       "%s%s",
3132                                       file_iterator_name (&files),
3133                                       content);
3134               g_free (content);
3135             }
3136           cleanup_file_iterator (&files);
3137 
3138           init_report_format_param_iterator (&params,
3139                                              report_format,
3140                                              0,
3141                                              1,
3142                                              NULL);
3143           while (next (&params))
3144             {
3145               g_string_append_printf
3146                (format,
3147                 "%s%s",
3148                 report_format_param_iterator_name (&params),
3149                 report_format_param_iterator_type_name (&params));
3150 
3151               if (report_format_param_iterator_type_min (&params) > LLONG_MIN)
3152                 g_string_append_printf
3153                  (format,
3154                   "%lli",
3155                   report_format_param_iterator_type_min (&params));
3156 
3157               if (report_format_param_iterator_type_max (&params) < LLONG_MAX)
3158                 g_string_append_printf
3159                  (format,
3160                   "%lli",
3161                   report_format_param_iterator_type_max (&params));
3162 
3163               g_string_append_printf
3164                (format,
3165                 "%s%s",
3166                 report_format_param_iterator_type_regex (&params),
3167                 report_format_param_iterator_fallback (&params));
3168 
3169               {
3170                 iterator_t options;
3171                 init_param_option_iterator
3172                  (&options,
3173                   report_format_param_iterator_param (&params),
3174                   1,
3175                   NULL);
3176                 while (next (&options))
3177                   if (param_option_iterator_value (&options))
3178                     g_string_append_printf
3179                      (format,
3180                       "%s",
3181                       param_option_iterator_value (&options));
3182               }
3183             }
3184           cleanup_iterator (&params);
3185 
3186           g_string_append_printf (format, "\n");
3187 
3188           if (format_signature)
3189             {
3190               /* Try the feed signature. */
3191               if (verify_signature (format->str, format->len, format_signature,
3192                                     strlen (format_signature), &format_trust))
3193                 {
3194                   cleanup_iterator (&formats);
3195                   g_free (format_signature);
3196                   g_string_free (format, TRUE);
3197                   return -1;
3198                 }
3199             }
3200           else if (signature && strlen (signature))
3201             {
3202               /* Try the signature from the database. */
3203               if (verify_signature (format->str, format->len, signature,
3204                                     strlen (signature), &format_trust))
3205                 {
3206                   cleanup_iterator (&formats);
3207                   g_free (format_signature);
3208                   g_string_free (format, TRUE);
3209                   return -1;
3210                 }
3211             }
3212 
3213           g_free (format_signature);
3214           g_string_free (format, TRUE);
3215         }
3216     }
3217   else
3218     {
3219       return -1;
3220     }
3221   cleanup_iterator (&formats);
3222 
3223   sql ("UPDATE report_formats SET trust = %i, trust_time = %i,"
3224        "                          modification_time = m_now ()"
3225        " WHERE id = %llu;",
3226        format_trust,
3227        time (NULL),
3228        report_format);
3229 
3230   return 0;
3231 }
3232 
3233 /**
3234  * @brief Verify a report format.
3235  *
3236  * @param[in]  report_format_id  Report format UUID.
3237  *
3238  * @return 0 success, 1 failed to find report format, 99 permission denied,
3239  *         -1 error.
3240  */
3241 int
verify_report_format(const char * report_format_id)3242 verify_report_format (const char *report_format_id)
3243 {
3244   int ret;
3245   report_format_t report_format;
3246 
3247   sql_begin_immediate ();
3248 
3249   if (acl_user_may ("verify_report_format") == 0)
3250     {
3251       sql_rollback ();
3252       return 99;
3253     }
3254 
3255   report_format = 0;
3256   if (find_report_format_with_permission (report_format_id, &report_format,
3257                                           "verify_report_format"))
3258     {
3259       sql_rollback ();
3260       return -1;
3261     }
3262   if (report_format == 0)
3263     {
3264       sql_rollback ();
3265       return 1;
3266     }
3267 
3268   ret = verify_report_format_internal (report_format);
3269   if (ret)
3270     {
3271       sql_rollback ();
3272       return ret;
3273     }
3274   sql_commit ();
3275   return 0;
3276 }
3277 
3278 /**
3279  * @brief Runs the script of a report format.
3280  *
3281  * @param[in]   report_format_id    UUID of the report format.
3282  * @param[in]   xml_file            Path to main part of the report XML.
3283  * @param[in]   xml_dir             Path of the dir with XML and subreports.
3284  * @param[in]   report_format_extra Extra data for report format.
3285  * @param[in]   output_file         Path to write report to.
3286  *
3287  * @return 0 success, -1 error.
3288  */
3289 static int
run_report_format_script(gchar * report_format_id,gchar * xml_file,gchar * xml_dir,gchar * report_format_extra,gchar * output_file)3290 run_report_format_script (gchar *report_format_id,
3291                           gchar *xml_file,
3292                           gchar *xml_dir,
3293                           gchar *report_format_extra,
3294                           gchar *output_file)
3295 {
3296   iterator_t formats;
3297   report_format_t report_format;
3298   gchar *script, *script_dir, *owner;
3299   get_data_t report_format_get;
3300 
3301   gchar *command;
3302   char *previous_dir;
3303   int ret;
3304 
3305   /* Setup file names and complete report. */
3306 
3307   memset (&report_format_get, '\0', sizeof (report_format_get));
3308   report_format_get.id = report_format_id;
3309 
3310   init_report_format_iterator (&formats, &report_format_get);
3311   if (next (&formats) == FALSE)
3312     {
3313       cleanup_iterator (&formats);
3314       return -1;
3315     }
3316 
3317   report_format = get_iterator_resource (&formats);
3318 
3319   owner = sql_string ("SELECT uuid FROM users"
3320                       " WHERE id = (SELECT owner FROM"
3321                       "             report_formats WHERE id = %llu);",
3322                       report_format);
3323   script_dir = g_build_filename (GVMD_STATE_DIR,
3324                                  "report_formats",
3325                                  owner,
3326                                  report_format_id,
3327                                  NULL);
3328   g_free (owner);
3329 
3330   cleanup_iterator (&formats);
3331 
3332   script = g_build_filename (script_dir, "generate", NULL);
3333 
3334   if (!gvm_file_is_readable (script))
3335     {
3336       g_warning ("%s: No generate script found at %s",
3337                  __func__, script);
3338       g_free (script);
3339       g_free (script_dir);
3340       return -1;
3341     }
3342   else if (!gvm_file_is_executable (script))
3343     {
3344       g_warning ("%s: script %s is not executable",
3345                  __func__, script);
3346       g_free (script);
3347       g_free (script_dir);
3348       return -1;
3349     }
3350 
3351   /* Change into the script directory. */
3352 
3353   previous_dir = getcwd (NULL, 0);
3354   if (previous_dir == NULL)
3355     {
3356       g_warning ("%s: Failed to getcwd: %s",
3357                   __func__,
3358                   strerror (errno));
3359       g_free (previous_dir);
3360       g_free (script);
3361       g_free (script_dir);
3362       return -1;
3363     }
3364 
3365   if (chdir (script_dir))
3366     {
3367       g_warning ("%s: Failed to chdir: %s",
3368                   __func__,
3369                   strerror (errno));
3370       g_free (previous_dir);
3371       g_free (script);
3372       g_free (script_dir);
3373       return -1;
3374     }
3375   g_free (script_dir);
3376 
3377   /* Call the script. */
3378 
3379   command = g_strdup_printf ("%s %s '%s' > %s"
3380                              " 2> /dev/null",
3381                              script,
3382                              xml_file,
3383                              report_format_extra,
3384                              output_file);
3385   g_free (script);
3386 
3387   g_debug ("   command: %s", command);
3388 
3389   if (geteuid () == 0)
3390     {
3391       pid_t pid;
3392       struct passwd *nobody;
3393 
3394       /* Run the command with lower privileges in a fork. */
3395 
3396       nobody = getpwnam ("nobody");
3397       if ((nobody == NULL)
3398           || chown (xml_dir, nobody->pw_uid, nobody->pw_gid)
3399           || chown (xml_file, nobody->pw_uid, nobody->pw_gid)
3400           || chown (output_file, nobody->pw_uid, nobody->pw_gid))
3401         {
3402           g_warning ("%s: Failed to set dir permissions: %s",
3403                       __func__,
3404                       strerror (errno));
3405           g_free (previous_dir);
3406           return -1;
3407         }
3408 
3409       pid = fork ();
3410       switch (pid)
3411         {
3412           case 0:
3413             {
3414               /* Child.  Drop privileges, run command, exit. */
3415 
3416               proctitle_set ("gvmd: Generating report");
3417 
3418               cleanup_manage_process (FALSE);
3419 
3420               if (setgroups (0,NULL))
3421                 {
3422                   g_warning ("%s (child): setgroups: %s",
3423                               __func__, strerror (errno));
3424                   exit (EXIT_FAILURE);
3425                 }
3426               if (setgid (nobody->pw_gid))
3427                 {
3428                   g_warning ("%s (child): setgid: %s",
3429                               __func__,
3430                               strerror (errno));
3431                   exit (EXIT_FAILURE);
3432                 }
3433               if (setuid (nobody->pw_uid))
3434                 {
3435                   g_warning ("%s (child): setuid: %s",
3436                               __func__,
3437                               strerror (errno));
3438                   exit (EXIT_FAILURE);
3439                 }
3440 
3441               ret = system (command);
3442               /* Report scripts should return 0 since version 21.04 */
3443               if (ret == -1 || WIFEXITED(ret) == 0 || WEXITSTATUS(ret))
3444                 {
3445                   g_warning ("%s (child):"
3446                               " system failed with ret %i, %i, %s",
3447                               __func__,
3448                               ret,
3449                               WEXITSTATUS (ret),
3450                               command);
3451                   exit (EXIT_FAILURE);
3452                 }
3453 
3454               exit (EXIT_SUCCESS);
3455             }
3456 
3457           case -1:
3458             /* Parent when error. */
3459 
3460             g_warning ("%s: Failed to fork: %s",
3461                         __func__,
3462                         strerror (errno));
3463             if (chdir (previous_dir))
3464               g_warning ("%s: and chdir failed",
3465                           __func__);
3466             g_free (previous_dir);
3467             g_free (command);
3468             return -1;
3469             break;
3470 
3471           default:
3472             {
3473               int status;
3474 
3475               /* Parent on success.  Wait for child, and check result. */
3476 
3477 
3478               while (waitpid (pid, &status, 0) < 0)
3479                 {
3480                   if (errno == ECHILD)
3481                     {
3482                       g_warning ("%s: Failed to get child exit status",
3483                                   __func__);
3484                       if (chdir (previous_dir))
3485                         g_warning ("%s: and chdir failed",
3486                                     __func__);
3487                       g_free (previous_dir);
3488                       return -1;
3489                     }
3490                   if (errno == EINTR)
3491                     continue;
3492                   g_warning ("%s: wait: %s",
3493                               __func__,
3494                               strerror (errno));
3495                   if (chdir (previous_dir))
3496                     g_warning ("%s: and chdir failed",
3497                                 __func__);
3498                   g_free (previous_dir);
3499                   return -1;
3500                 }
3501               if (WIFEXITED (status))
3502                 switch (WEXITSTATUS (status))
3503                   {
3504                     case EXIT_SUCCESS:
3505                       break;
3506                     case EXIT_FAILURE:
3507                     default:
3508                       g_warning ("%s: child failed, %s",
3509                                   __func__,
3510                                   command);
3511                       if (chdir (previous_dir))
3512                         g_warning ("%s: and chdir failed",
3513                                     __func__);
3514                       g_free (previous_dir);
3515                       g_free (command);
3516                       return -1;
3517                   }
3518               else
3519                 {
3520                   g_warning ("%s: child failed, %s",
3521                               __func__,
3522                               command);
3523                   if (chdir (previous_dir))
3524                     g_warning ("%s: and chdir failed",
3525                                 __func__);
3526                   g_free (command);
3527                   g_free (previous_dir);
3528                   return -1;
3529                 }
3530               g_free (command);
3531 
3532               /* Child succeeded, continue to process result. */
3533 
3534               break;
3535             }
3536         }
3537     }
3538   else
3539     {
3540       /* Just run the command as the current user. */
3541 
3542       ret = system (command);
3543       /* Report scripts should return 0 since version 21.04 */
3544       if (ret == -1 || WIFEXITED(ret) == 0 || WEXITSTATUS(ret))
3545         {
3546           g_warning ("%s: system failed with ret %i, %i, %s",
3547                       __func__,
3548                       ret,
3549                       WEXITSTATUS (ret),
3550                       command);
3551           if (chdir (previous_dir))
3552             g_warning ("%s: and chdir failed",
3553                         __func__);
3554           g_free (previous_dir);
3555           g_free (command);
3556           return -1;
3557         }
3558 
3559       g_free (command);
3560     }
3561 
3562   /* Change back to the previous directory. */
3563 
3564   if (chdir (previous_dir))
3565     {
3566       g_warning ("%s: Failed to chdir back: %s",
3567                   __func__,
3568                   strerror (errno));
3569       g_free (previous_dir);
3570       return -1;
3571     }
3572   g_free (previous_dir);
3573 
3574   return 0;
3575 }
3576 
3577 /**
3578  * @brief Completes a report by adding report format info.
3579  *
3580  * @param[in]   xml_start      Path of file containing start of report.
3581  * @param[in]   xml_full       Path to file to print full report to.
3582  * @param[in]   report_format  Format of report that will be created from XML.
3583  *
3584  * @return 0 success, -1 error.
3585  */
3586 int
print_report_xml_end(gchar * xml_start,gchar * xml_full,report_format_t report_format)3587 print_report_xml_end (gchar *xml_start, gchar *xml_full,
3588                       report_format_t report_format)
3589 {
3590   FILE *out;
3591 
3592   if (gvm_file_copy (xml_start, xml_full) == FALSE)
3593     {
3594       g_warning ("%s: failed to copy xml_start file", __func__);
3595       return -1;
3596     }
3597 
3598   out = fopen (xml_full, "a");
3599   if (out == NULL)
3600     {
3601       g_warning ("%s: fopen failed: %s",
3602                  __func__,
3603                  strerror (errno));
3604       return -1;
3605     }
3606 
3607   /* A bit messy having report XML here, but simplest for now. */
3608 
3609   if (report_format > 0)
3610     {
3611       iterator_t params;
3612       PRINT (out, "<report_format>");
3613       init_report_format_param_iterator (&params, report_format, 0, 1, NULL);
3614       while (next (&params))
3615         PRINT (out,
3616                "<param><name>%s</name><value>%s</value></param>",
3617                report_format_param_iterator_name (&params),
3618                report_format_param_iterator_value (&params));
3619       cleanup_iterator (&params);
3620 
3621       PRINT (out, "</report_format>");
3622     }
3623 
3624   PRINT (out, "</report>");
3625 
3626   if (fclose (out))
3627     {
3628       g_warning ("%s: fclose failed: %s",
3629                  __func__,
3630                  strerror (errno));
3631       return -1;
3632     }
3633 
3634   return 0;
3635 }
3636 
3637 /**
3638  * @brief Applies a report format to an XML report.
3639  *
3640  * @param[in]  report_format_id   Report format to apply.
3641  * @param[in]  xml_start          Path to the main part of the report XML.
3642  * @param[in]  xml_file           Path to the report XML file.
3643  * @param[in]  xml_dir            Path to the temporary dir.
3644  * @param[in]  used_rfps          List of already applied report formats.
3645  *
3646  * @return Path to the generated file or NULL.
3647  */
3648 gchar*
apply_report_format(gchar * report_format_id,gchar * xml_start,gchar * xml_file,gchar * xml_dir,GList ** used_rfps)3649 apply_report_format (gchar *report_format_id,
3650                      gchar *xml_start,
3651                      gchar *xml_file,
3652                      gchar *xml_dir,
3653                      GList **used_rfps)
3654 {
3655   report_format_t report_format;
3656   GHashTable *subreports;
3657   GList *temp_dirs, *temp_files;
3658   gchar *rf_dependencies_string, *output_file, *out_file_part, *out_file_ext;
3659   gchar *files_xml;
3660   int output_fd;
3661 
3662   assert (report_format_id);
3663   assert (xml_start);
3664   assert (xml_file);
3665   assert (xml_dir);
3666   assert (used_rfps);
3667 
3668   /* Check if there would be an infinite recursion loop. */
3669   if (*used_rfps
3670       && g_list_find_custom (*used_rfps, report_format_id,
3671                              (GCompareFunc) strcmp))
3672     {
3673       g_message ("%s: Recursion loop for report_format '%s'",
3674                  __func__, report_format_id);
3675       return NULL;
3676     }
3677 
3678   /* Check if report format is available. */
3679   if (find_report_format_with_permission (report_format_id, &report_format,
3680                                           "get_report_formats")
3681       || report_format == 0)
3682     {
3683       g_message ("%s: Report format '%s' not found",
3684                  __func__, report_format_id);
3685       return NULL;
3686     }
3687 
3688   /* Check if report format is active */
3689   if (report_format_active (report_format) == 0)
3690     {
3691       g_message ("%s: Report format '%s' is not active",
3692                  __func__, report_format_id);
3693       return NULL;
3694     }
3695 
3696   /* Get subreports. */
3697   temp_dirs = NULL;
3698   temp_files = NULL;
3699   subreports = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
3700 
3701   rf_dependencies_string
3702     = sql_string ("SELECT value"
3703                   "  FROM report_format_params"
3704                   " WHERE report_format = %llu"
3705                   "   AND type = %i",
3706                   report_format,
3707                   REPORT_FORMAT_PARAM_TYPE_REPORT_FORMAT_LIST);
3708 
3709   if (rf_dependencies_string)
3710     {
3711       gchar **rf_dependencies, **current_rf_dependency;
3712       GString *files_xml_buf;
3713       GHashTableIter files_iter;
3714       gchar *key, *value;
3715 
3716       *used_rfps = g_list_append (*used_rfps, report_format_id);
3717 
3718       /* Recursively create subreports for dependencies. */
3719       rf_dependencies = g_strsplit (rf_dependencies_string, ",", -1);
3720       current_rf_dependency = rf_dependencies;
3721 
3722       while (*current_rf_dependency)
3723         {
3724           gchar *subreport_dir, *subreport_xml, *subreport_file;
3725           subreport_file = NULL;
3726 
3727           subreport_dir = g_strdup ("/tmp/gvmd_XXXXXX");
3728 
3729           if (mkdtemp (subreport_dir) == NULL)
3730             {
3731               g_warning ("%s: mkdtemp failed", __func__);
3732               g_free (subreport_dir);
3733               break;
3734             }
3735           subreport_xml = g_build_filename (subreport_dir, "report.xml", NULL);
3736           temp_dirs = g_list_append (temp_dirs, subreport_dir);
3737           temp_files = g_list_append (temp_files, subreport_xml);
3738 
3739           if (g_hash_table_contains (subreports, *current_rf_dependency)
3740               == FALSE)
3741             {
3742               subreport_file = apply_report_format (*current_rf_dependency,
3743                                                     xml_start,
3744                                                     subreport_xml,
3745                                                     subreport_dir,
3746                                                     used_rfps);
3747               if (subreport_file)
3748                 {
3749                   g_hash_table_insert (subreports,
3750                                        g_strdup (*current_rf_dependency),
3751                                        subreport_file);
3752                 }
3753             }
3754 
3755           current_rf_dependency ++;
3756         }
3757 
3758       g_strfreev (rf_dependencies);
3759 
3760       *used_rfps = g_list_remove (*used_rfps, report_format_id);
3761 
3762       /* Build dependencies XML. */
3763       files_xml_buf = g_string_new ("<files>");
3764       xml_string_append (files_xml_buf,
3765                          "<basedir>%s</basedir>",
3766                          xml_dir);
3767 
3768       g_hash_table_iter_init (&files_iter, subreports);
3769       while (g_hash_table_iter_next (&files_iter,
3770                                      (void**)&key, (void**)&value))
3771         {
3772           get_data_t report_format_get;
3773           iterator_t file_format_iter;
3774 
3775           memset (&report_format_get, '\0', sizeof (report_format_get));
3776           report_format_get.id = key;
3777 
3778           init_report_format_iterator (&file_format_iter, &report_format_get);
3779           if (next (&file_format_iter))
3780             {
3781               xml_string_append (files_xml_buf,
3782                                  "<file id=\"%s\""
3783                                  " content_type=\"%s\""
3784                                  " report_format_name=\"%s\">"
3785                                  "%s"
3786                                  "</file>",
3787                                  key,
3788                                  report_format_iterator_content_type
3789                                   (&file_format_iter),
3790                                  get_iterator_name (&file_format_iter),
3791                                  value);
3792             }
3793           else
3794             {
3795               xml_string_append (files_xml_buf,
3796                                  "<file id=\"%s\">%s</file>",
3797                                  key, value);
3798             }
3799           cleanup_iterator (&file_format_iter);
3800         }
3801 
3802       g_string_append (files_xml_buf, "</files>");
3803       files_xml = g_string_free (files_xml_buf, FALSE);
3804     }
3805   else
3806     {
3807       GString *files_xml_buf;
3808       /* Build dependencies XML. */
3809       files_xml_buf = g_string_new ("<files>");
3810       xml_string_append (files_xml_buf,
3811                          "<basedir>%s</basedir>",
3812                          xml_dir);
3813       g_string_append (files_xml_buf, "</files>");
3814       files_xml = g_string_free (files_xml_buf, FALSE);
3815     }
3816 
3817   /* Generate output file. */
3818   out_file_ext = report_format_extension (report_format);
3819   out_file_part = g_strdup_printf ("%s-XXXXXX.%s",
3820                                    report_format_id, out_file_ext);
3821   output_file = g_build_filename (xml_dir, out_file_part, NULL);
3822   output_fd = mkstemps (output_file, strlen (out_file_ext) + 1);
3823   if (output_fd == -1)
3824     {
3825       g_warning ("%s: mkstemps failed: %s", __func__, strerror (errno));
3826       g_free (output_file);
3827       output_file = NULL;
3828       goto cleanup;
3829     }
3830   g_free (out_file_ext);
3831   g_free (out_file_part);
3832 
3833   /* Add second half of input XML */
3834 
3835   if (print_report_xml_end (xml_start, xml_file, report_format))
3836     {
3837       g_free (output_file);
3838       output_file = NULL;
3839       goto cleanup;
3840     }
3841 
3842   run_report_format_script (report_format_id,
3843                             xml_file, xml_dir, files_xml, output_file);
3844 
3845   /* Clean up and return filename. */
3846  cleanup:
3847   while (temp_dirs)
3848     {
3849       gvm_file_remove_recurse (temp_dirs->data);
3850       gpointer data = temp_dirs->data;
3851       temp_dirs = g_list_remove (temp_dirs, data);
3852       g_free (data);
3853     }
3854   while (temp_files)
3855     {
3856       gpointer data = temp_files->data;
3857       temp_files = g_list_remove (temp_files, data);
3858       g_free (data);
3859     }
3860   g_free (files_xml);
3861   g_hash_table_destroy (subreports);
3862   if (close (output_fd))
3863     {
3864       g_warning ("%s: close of output_fd failed: %s",
3865                  __func__, strerror (errno));
3866       g_free (output_file);
3867       return NULL;
3868     }
3869 
3870   return output_file;
3871 }
3872 
3873 /**
3874  * @brief Empty trashcan.
3875  *
3876  * @return 0 success, -1 error.
3877  */
3878 int
empty_trashcan_report_formats()3879 empty_trashcan_report_formats ()
3880 {
3881   GArray *report_formats;
3882   int index, length;
3883   iterator_t rows;
3884 
3885   sql ("DELETE FROM report_format_param_options_trash"
3886        " WHERE report_format_param"
3887        "       IN (SELECT id from report_format_params_trash"
3888        "           WHERE report_format"
3889        "                 IN (SELECT id FROM report_formats_trash"
3890        "                     WHERE owner = (SELECT id FROM users"
3891        "                                    WHERE uuid = '%s')));",
3892        current_credentials.uuid);
3893   sql ("DELETE FROM report_format_params_trash"
3894        " WHERE report_format IN (SELECT id from report_formats_trash"
3895        "                         WHERE owner = (SELECT id FROM users"
3896        "                                        WHERE uuid = '%s'));",
3897        current_credentials.uuid);
3898 
3899   init_iterator (&rows,
3900                  "SELECT id FROM report_formats_trash"
3901                  " WHERE owner = (SELECT id FROM users WHERE uuid = '%s');",
3902                  current_credentials.uuid);
3903   report_formats = g_array_new (FALSE, FALSE, sizeof (report_format_t));
3904   length = 0;
3905   while (next (&rows))
3906     {
3907       report_format_t id;
3908       id = iterator_int64 (&rows, 0);
3909       g_array_append_val (report_formats, id);
3910       length++;
3911     }
3912   cleanup_iterator (&rows);
3913 
3914   sql ("DELETE FROM report_formats_trash"
3915        " WHERE owner = (SELECT id FROM users WHERE uuid = '%s');",
3916        current_credentials.uuid);
3917 
3918   /* Remove the report formats dirs last, in case any SQL rolls back. */
3919 
3920   for (index = 0; index < length; index++)
3921     {
3922       gchar *dir, *name;
3923 
3924       name = g_strdup_printf ("%llu",
3925                               g_array_index (report_formats,
3926                                              report_format_t,
3927                                              index));
3928       dir = report_format_trash_dir (name);
3929       g_free (name);
3930 
3931       if (gvm_file_exists (dir) && gvm_file_remove_recurse (dir))
3932         {
3933           g_warning ("%s: failed to remove trash dir %s", __func__, dir);
3934           g_free (dir);
3935           return -1;
3936         }
3937 
3938       g_free (dir);
3939     }
3940 
3941   g_array_free (report_formats, TRUE);
3942   return 0;
3943 }
3944 
3945 /**
3946  * @brief Change ownership of report formats, for user deletion.
3947  *
3948  * @param[in]  report_format_id  UUID of report format.
3949  * @param[in]  user_id           UUID of current owner.
3950  * @param[in]  inheritor         New owner.
3951  */
3952 void
inherit_report_format_dir(const gchar * report_format_id,const gchar * user_id,user_t inheritor)3953 inherit_report_format_dir (const gchar *report_format_id, const gchar *user_id,
3954                            user_t inheritor)
3955 {
3956   gchar *inheritor_id, *old_dir, *new_dir;
3957 
3958   g_debug ("%s: %s from %s to %llu", __func__, report_format_id, user_id,
3959            inheritor);
3960 
3961   inheritor_id = user_uuid (inheritor);
3962   if (inheritor_id == NULL)
3963     {
3964       g_warning ("%s: inheritor_id NULL, skipping report format dir", __func__);
3965       return;
3966     }
3967 
3968   old_dir = g_build_filename (GVMD_STATE_DIR,
3969                               "report_formats",
3970                               user_id,
3971                               report_format_id,
3972                               NULL);
3973 
3974   new_dir = g_build_filename (GVMD_STATE_DIR,
3975                               "report_formats",
3976                               inheritor_id,
3977                               report_format_id,
3978                               NULL);
3979 
3980   g_free (inheritor_id);
3981 
3982   if (move_report_format_dir (old_dir, new_dir))
3983     g_warning ("%s: failed to move %s dir, but will try the rest",
3984                __func__,
3985                report_format_id);
3986 
3987   g_free (old_dir);
3988   g_free (new_dir);
3989 }
3990 
3991 /**
3992  * @brief Change ownership of report formats, for user deletion.
3993  *
3994  * @param[in]  user       Current owner.
3995  * @param[in]  inheritor  New owner.
3996  * @param[in]  rows       Iterator for inherited report formats, with next
3997  *                        already called.
3998  *
3999  * @return TRUE if there is a row available, else FALSE.
4000  */
4001 gboolean
inherit_report_formats(user_t user,user_t inheritor,iterator_t * rows)4002 inherit_report_formats (user_t user, user_t inheritor, iterator_t *rows)
4003 {
4004   sql ("UPDATE report_formats_trash SET owner = %llu WHERE owner = %llu;",
4005        inheritor, user);
4006 
4007   init_iterator (rows,
4008                  "UPDATE report_formats SET owner = %llu"
4009                  " WHERE owner = %llu"
4010                  " RETURNING uuid;",
4011                  inheritor, user);
4012 
4013   /* This executes the SQL. */
4014   return next (rows);
4015 }
4016 
4017 /**
4018  * @brief Delete all report formats owned by a user.
4019  *
4020  * @param[in]  user  The user.
4021  * @param[in]  rows  Trash report format ids.
4022  *
4023  * @return TRUE if there are rows in rows, else FALSE.
4024  */
4025 gboolean
delete_report_formats_user(user_t user,iterator_t * rows)4026 delete_report_formats_user (user_t user, iterator_t *rows)
4027 {
4028   /* Remove report formats from db. */
4029 
4030   sql ("DELETE FROM report_format_param_options"
4031        " WHERE report_format_param"
4032        "       IN (SELECT id FROM report_format_params"
4033        "           WHERE report_format IN (SELECT id"
4034        "                                   FROM report_formats"
4035        "                                   WHERE owner = %llu));",
4036        user);
4037   sql ("DELETE FROM report_format_param_options_trash"
4038        " WHERE report_format_param"
4039        "       IN (SELECT id FROM report_format_params_trash"
4040        "           WHERE report_format IN (SELECT id"
4041        "                                   FROM report_formats_trash"
4042        "                                   WHERE owner = %llu));",
4043        user);
4044   sql ("DELETE FROM report_format_params"
4045        " WHERE report_format IN (SELECT id FROM report_formats"
4046        "                         WHERE owner = %llu);",
4047        user);
4048   sql ("DELETE FROM report_format_params_trash"
4049        " WHERE report_format IN (SELECT id"
4050        "                         FROM report_formats_trash"
4051        "                         WHERE owner = %llu);",
4052        user);
4053   sql ("DELETE FROM report_formats WHERE owner = %llu;", user);
4054   init_iterator (rows,
4055                  "DELETE FROM report_formats_trash WHERE owner = %llu"
4056                  " RETURNING id;",
4057                  user);
4058 
4059   /* This executes the SQL. */
4060   return next (rows);
4061 }
4062 
4063 /**
4064  * @brief Delete all report formats owned by a user.
4065  *
4066  * @param[in]  user_id  UUID of user.
4067  * @param[in]  rows     Trash report format ids if any, else NULL.  Cleaned up
4068  *                      before returning.
4069  */
4070 void
delete_report_format_dirs_user(const gchar * user_id,iterator_t * rows)4071 delete_report_format_dirs_user (const gchar *user_id, iterator_t *rows)
4072 {
4073   gchar *dir;
4074 
4075   /* Remove trash report formats from trash directory. */
4076 
4077   if (rows)
4078     {
4079       do
4080       {
4081         gchar *id;
4082 
4083         id = g_strdup_printf ("%llu", iterator_int64 (rows, 0));
4084         dir = report_format_trash_dir (id);
4085         g_free (id);
4086         if (gvm_file_remove_recurse (dir))
4087           g_warning ("%s: failed to remove dir %s, continuing anyway",
4088                      __func__, dir);
4089         g_free (dir);
4090       } while (next (rows));
4091       cleanup_iterator (rows);
4092     }
4093 
4094   /* Remove user's regular report formats directory. */
4095 
4096   dir = g_build_filename (GVMD_STATE_DIR,
4097                           "report_formats",
4098                           user_id,
4099                           NULL);
4100 
4101   if (gvm_file_exists (dir) && gvm_file_remove_recurse (dir))
4102     g_warning ("%s: failed to remove dir %s, continuing anyway",
4103                __func__, dir);
4104   g_free (dir);
4105 }
4106 
4107 
4108 /* Feed report formats. */
4109 
4110 /**
4111  * @brief Update a report format from an XML file.
4112  *
4113  * @param[in]  report_format    Existing report format.
4114  * @param[in]  report_id        UUID of report format.
4115  * @param[in]  name             New name.
4116  * @param[in]  content_type     New content type.
4117  * @param[in]  extension        New extension.
4118  * @param[in]  summary          New summary.
4119  * @param[in]  description      New description.
4120  * @param[in]  signature        New signature.
4121  * @param[in]  files            New files.
4122  * @param[in]  params           New params.
4123  * @param[in]  params_options   Options for new params.
4124  */
4125 void
update_report_format(report_format_t report_format,const gchar * report_id,const gchar * name,const gchar * content_type,const gchar * extension,const gchar * summary,const gchar * description,const gchar * signature,array_t * files,array_t * params,array_t * params_options)4126 update_report_format (report_format_t report_format, const gchar *report_id, const gchar *name,
4127                       const gchar *content_type, const gchar *extension,
4128                       const gchar *summary, const gchar *description,
4129                       const gchar *signature, array_t *files, array_t *params,
4130                       array_t *params_options)
4131 {
4132   int ret;
4133   gchar *quoted_name, *quoted_content_type, *quoted_extension, *quoted_summary;
4134   gchar *quoted_description, *quoted_signature;
4135 
4136   sql_begin_immediate ();
4137 
4138   quoted_name = sql_quote (name ? name : "");
4139   quoted_content_type = sql_quote (content_type ? content_type : "");
4140   quoted_extension = sql_quote (extension ? extension : "");
4141   quoted_summary = sql_quote (summary ? summary : "");
4142   quoted_description = sql_quote (description ? description : "");
4143   quoted_signature = sql_quote (signature ? signature : "");
4144   sql ("UPDATE report_formats"
4145        " SET name = '%s', content_type = '%s', extension = '%s',"
4146        "     summary = '%s', description = '%s', signature = '%s',"
4147        "     predefined = 1, modification_time = m_now ()"
4148        " WHERE id = %llu;",
4149        quoted_name,
4150        quoted_content_type,
4151        quoted_extension,
4152        quoted_summary,
4153        quoted_description,
4154        quoted_signature,
4155        report_format);
4156   g_free (quoted_name);
4157   g_free (quoted_content_type);
4158   g_free (quoted_extension);
4159   g_free (quoted_summary);
4160   g_free (quoted_description);
4161   g_free (quoted_signature);
4162 
4163   /* Replace the params. */
4164 
4165   sql ("DELETE FROM report_format_param_options"
4166        " WHERE report_format_param IN (SELECT id FROM report_format_params"
4167        "                               WHERE report_format = %llu);",
4168        report_format);
4169   sql ("DELETE FROM report_format_params WHERE report_format = %llu;",
4170        report_format);
4171 
4172   ret = add_report_format_params (report_format, params, params_options);
4173   if (ret)
4174     {
4175       if (ret == 3)
4176         g_warning ("%s: Parameter value validation failed", __func__);
4177       else if (ret == 4)
4178         g_warning ("%s: Parameter default validation failed", __func__);
4179       else if (ret == 5)
4180         g_warning ("%s: PARAM requires a DEFAULT element", __func__);
4181       else if (ret == 6)
4182         g_warning ("%s: PARAM MIN or MAX out of range", __func__);
4183       else if (ret == 7)
4184         g_warning ("%s: PARAM requires a TYPE element", __func__);
4185       else if (ret == 8)
4186         g_warning ("%s: Duplicate PARAM name", __func__);
4187       else if (ret == 9)
4188         g_warning ("%s: Bogus PARAM type", __func__);
4189       else if (ret)
4190         g_warning ("%s: Internal error", __func__);
4191 
4192       sql_rollback ();
4193       return;
4194     }
4195 
4196   /* Replace the files. */
4197 
4198   save_report_format_files (report_id, files, NULL);
4199 
4200   sql_commit ();
4201 }
4202 
4203 /**
4204  * @brief Check if a report format has been updated in the feed.
4205  *
4206  * @param[in]  path           Full path to report format XML in feed.
4207  * @param[in]  report_format  Report Format.
4208  *
4209  * @return 1 if updated in feed, else 0.
4210  */
4211 int
report_format_updated_in_feed(report_format_t report_format,const gchar * path)4212 report_format_updated_in_feed (report_format_t report_format, const gchar *path)
4213 {
4214   GStatBuf state;
4215   int last_update;
4216 
4217   last_update = sql_int ("SELECT modification_time FROM report_formats"
4218                          " WHERE id = %llu;",
4219                          report_format);
4220 
4221   if (g_stat (path, &state))
4222     {
4223       g_warning ("%s: Failed to stat feed report_format file: %s",
4224                  __func__,
4225                  strerror (errno));
4226       return 0;
4227     }
4228 
4229   if (state.st_mtime <= last_update)
4230     return 0;
4231 
4232   return 1;
4233 }
4234 
4235 /**
4236  * @brief Migrate old ownerless report formats to the Feed Owner.
4237  *
4238  * @return 0 success, -1 error.
4239  */
4240 int
migrate_predefined_report_formats()4241 migrate_predefined_report_formats ()
4242 {
4243   iterator_t rows;
4244   gchar *owner_uuid, *quoted_owner_uuid;
4245 
4246   setting_value (SETTING_UUID_FEED_IMPORT_OWNER, &owner_uuid);
4247 
4248   if (owner_uuid == NULL)
4249     return 0;
4250 
4251   if (strlen (owner_uuid) == 0)
4252     {
4253       g_free (owner_uuid);
4254       return 0;
4255     }
4256 
4257   quoted_owner_uuid = sql_quote (owner_uuid);
4258   init_iterator (&rows,
4259                  "UPDATE report_formats"
4260                  " SET owner = (SELECT id FROM users"
4261                  "              WHERE uuid = '%s')"
4262                  " WHERE owner is NULL"
4263                  " RETURNING uuid;",
4264                  quoted_owner_uuid);
4265   g_free (quoted_owner_uuid);
4266 
4267   /* Move report format files to the Feed Owner's report format dir. */
4268 
4269   while (next (&rows))
4270     {
4271       gchar *old, *new;
4272 
4273       if (iterator_string (&rows, 0) == NULL)
4274         continue;
4275 
4276       old = g_build_filename (GVMD_DATA_DIR,
4277                               "report_formats",
4278                               iterator_string (&rows, 0),
4279                               NULL);
4280 
4281       new = g_build_filename (GVMD_STATE_DIR,
4282                               "report_formats",
4283                               owner_uuid,
4284                               NULL);
4285 
4286       if (copy_report_format_dir (old, new, iterator_string (&rows, 0)))
4287         {
4288           g_warning ("%s: failed at report format %s", __func__,
4289                      iterator_string (&rows, 0));
4290           g_free (old);
4291           g_free (new);
4292           cleanup_iterator (&rows);
4293           g_free (owner_uuid);
4294           return -1;
4295         }
4296 
4297       g_free (old);
4298       g_free (new);
4299     }
4300   cleanup_iterator (&rows);
4301   g_free (owner_uuid);
4302   return 0;
4303 }
4304 
4305 
4306 /* Startup. */
4307 
4308 /**
4309  * @brief Ensure every report format has a unique UUID.
4310  *
4311  * @return 0 success, -1 error.
4312  */
4313 static int
make_report_format_uuids_unique()4314 make_report_format_uuids_unique ()
4315 {
4316   iterator_t rows;
4317 
4318   sql ("CREATE TEMPORARY TABLE duplicates"
4319        " AS SELECT id, uuid, make_uuid () AS new_uuid, owner,"
4320        "           (SELECT uuid FROM users"
4321        "            WHERE users.id = outer_report_formats.owner)"
4322        "           AS owner_uuid,"
4323        "           (SELECT owner from report_formats"
4324        "                              WHERE uuid = outer_report_formats.uuid"
4325        "                              ORDER BY id ASC LIMIT 1)"
4326        "           AS original_owner,"
4327        "           (SELECT uuid FROM users"
4328        "            WHERE users.id = (SELECT owner from report_formats"
4329        "                              WHERE uuid = outer_report_formats.uuid"
4330        "                              ORDER BY id ASC LIMIT 1))"
4331        "           AS original_owner_uuid"
4332        "    FROM report_formats AS outer_report_formats"
4333        "    WHERE id > (SELECT id from report_formats"
4334        "                WHERE uuid = outer_report_formats.uuid"
4335        "                ORDER BY id ASC LIMIT 1);");
4336 
4337   sql ("UPDATE alert_method_data"
4338        " SET data = (SELECT new_uuid FROM duplicates"
4339        "             WHERE duplicates.id = alert_method_data.alert)"
4340        " WHERE alert IN (SELECT id FROM duplicates);");
4341 
4342   /* Update UUIDs on disk. */
4343   init_iterator (&rows,
4344                  "SELECT id, uuid, new_uuid, owner, owner_uuid, original_owner,"
4345                  "       original_owner_uuid"
4346                  " FROM duplicates;");
4347   while (next (&rows))
4348     {
4349       gchar *dir, *new_dir;
4350       const char *old_uuid, *new_uuid;
4351       int copy;
4352 
4353       old_uuid = iterator_string (&rows, 1);
4354       new_uuid = iterator_string (&rows, 2);
4355 
4356       if (iterator_int64 (&rows, 3) == 0)
4357         {
4358           /* Old-style "global" report format.  I don't think this is possible
4359            * with any released version, so ignore. */
4360           continue;
4361         }
4362       else if (iterator_int64 (&rows, 5) == 0)
4363         {
4364           const char *owner_uuid;
4365           /* Dedicated subdir in user dir, but must be renamed. */
4366           copy = 0;
4367           owner_uuid = iterator_string (&rows, 4);
4368           dir = g_build_filename (GVMD_STATE_DIR,
4369                                   "report_formats",
4370                                   owner_uuid,
4371                                   old_uuid,
4372                                   NULL);
4373           new_dir = g_build_filename (GVMD_STATE_DIR,
4374                                       "report_formats",
4375                                       owner_uuid,
4376                                       new_uuid,
4377                                       NULL);
4378         }
4379       else
4380         {
4381           const char *owner_uuid, *original_owner_uuid;
4382 
4383           /* Two user-owned report formats, may be the same user. */
4384 
4385           owner_uuid = iterator_string (&rows, 4);
4386           original_owner_uuid = iterator_string (&rows, 6);
4387 
4388           /* Copy the subdir if both report formats owned by one user. */
4389           copy = owner_uuid
4390                  && original_owner_uuid
4391                  && (strcmp (owner_uuid, original_owner_uuid) == 0);
4392 
4393           dir = g_build_filename (GVMD_STATE_DIR,
4394                                   "report_formats",
4395                                   owner_uuid,
4396                                   old_uuid,
4397                                   NULL);
4398           new_dir = g_build_filename (GVMD_STATE_DIR,
4399                                       "report_formats",
4400                                       owner_uuid,
4401                                       new_uuid,
4402                                       NULL);
4403         }
4404 
4405       if (copy)
4406         {
4407           gchar *command;
4408           int ret;
4409 
4410           command = g_strdup_printf ("cp -a %s %s > /dev/null 2>&1",
4411                                      dir,
4412                                      new_dir);
4413           g_debug ("   command: %s", command);
4414           ret = system (command);
4415           g_free (command);
4416 
4417           if (ret == -1 || WEXITSTATUS (ret))
4418             {
4419               /* Presume dir missing, just log a warning. */
4420               g_warning ("%s: cp %s to %s failed",
4421                          __func__, dir, new_dir);
4422             }
4423           else
4424             g_debug ("%s: copied %s to %s", __func__, dir, new_dir);
4425         }
4426       else
4427         {
4428           if (rename (dir, new_dir))
4429             {
4430               g_warning ("%s: rename %s to %s: %s",
4431                          __func__, dir, new_dir, strerror (errno));
4432               if (errno != ENOENT)
4433                 {
4434                   g_free (dir);
4435                   g_free (new_dir);
4436                   sql_rollback ();
4437                   return -1;
4438                 }
4439             }
4440           else
4441             g_debug ("%s: moved %s to %s", __func__, dir, new_dir);
4442         }
4443       g_free (dir);
4444       g_free (new_dir);
4445     }
4446   cleanup_iterator (&rows);
4447 
4448   sql ("UPDATE report_formats"
4449        " SET uuid = (SELECT new_uuid FROM duplicates"
4450        "             WHERE duplicates.id = report_formats.id)"
4451        " WHERE id IN (SELECT id FROM duplicates);");
4452 
4453   if (sql_changes () > 0)
4454     g_debug ("%s: gave %d report format(s) new UUID(s) to keep UUIDs unique.",
4455              __func__, sql_changes ());
4456 
4457   sql ("DROP TABLE duplicates;");
4458 
4459   return 0;
4460 }
4461 
4462 /**
4463  * @brief Check that trash report formats are correct.
4464  *
4465  * @return 0 success, -1 error.
4466  */
4467 static int
check_db_trash_report_formats()4468 check_db_trash_report_formats ()
4469 {
4470   gchar *dir;
4471   struct stat state;
4472 
4473   dir = g_build_filename (GVMD_STATE_DIR,
4474                           "report_formats_trash",
4475                           NULL);
4476 
4477   if (g_lstat (dir, &state))
4478     {
4479       iterator_t report_formats;
4480       int count;
4481 
4482       if (errno != ENOENT)
4483         {
4484           g_warning ("%s: g_lstat (%s) failed: %s",
4485                      __func__, dir, g_strerror (errno));
4486           g_free (dir);
4487           return -1;
4488         }
4489 
4490       /* Remove all trash report formats. */
4491 
4492       count = 0;
4493       init_iterator (&report_formats, "SELECT id FROM report_formats_trash;");
4494       while (next (&report_formats))
4495         {
4496           report_format_t report_format;
4497 
4498           report_format = iterator_int64 (&report_formats, 0);
4499 
4500           sql ("DELETE FROM alert_method_data_trash"
4501                " WHERE data = (SELECT original_uuid"
4502                "               FROM report_formats_trash"
4503                "               WHERE id = %llu)"
4504                " AND (name = 'notice_attach_format'"
4505                "      OR name = 'notice_report_format');",
4506                report_format);
4507 
4508           permissions_set_orphans ("report_format", report_format,
4509                                    LOCATION_TRASH);
4510           tags_remove_resource ("report_format", report_format, LOCATION_TRASH);
4511 
4512           sql ("DELETE FROM report_format_param_options_trash"
4513                " WHERE report_format_param"
4514                " IN (SELECT id from report_format_params_trash"
4515                "     WHERE report_format = %llu);",
4516                report_format);
4517           sql ("DELETE FROM report_format_params_trash"
4518                " WHERE report_format = %llu;",
4519                report_format);
4520           sql ("DELETE FROM report_formats_trash WHERE id = %llu;",
4521                report_format);
4522 
4523           count++;
4524         }
4525       cleanup_iterator (&report_formats);
4526 
4527       if (count)
4528         g_message ("Trash report format directory was missing."
4529                    " Removed all %i trash report formats.",
4530                    count);
4531     }
4532 
4533   g_free (dir);
4534   return 0;
4535 }
4536 
4537 /**
4538  * @brief Ensure the predefined report formats exist.
4539  *
4540  * @return 0 success, -1 error.
4541  */
4542 int
check_db_report_formats()4543 check_db_report_formats ()
4544 {
4545   if (migrate_predefined_report_formats ())
4546     return -1;
4547 
4548   if (sync_report_formats_with_feed (FALSE) <= -1)
4549     g_warning ("%s: Failed to sync report formats with feed", __func__);
4550 
4551   if (check_db_trash_report_formats ())
4552     return -1;
4553 
4554   if (make_report_format_uuids_unique ())
4555     return -1;
4556 
4557   /* Warn about feed resources in the trash. */
4558   if (sql_int ("SELECT EXISTS (SELECT * FROM report_formats_trash"
4559                "               WHERE predefined = 1);"))
4560     {
4561       g_warning ("%s: There are feed report formats in the trash."
4562                  " These will be excluded from the sync.",
4563                  __func__);
4564     }
4565 
4566   return 0;
4567 }
4568 
4569 /**
4570  * @brief Ensure that the report formats trash directory matches the database.
4571  *
4572  * @return -1 if error, 0 if success.
4573  */
4574 int
check_db_report_formats_trash()4575 check_db_report_formats_trash ()
4576 {
4577   gchar *dir;
4578   GError *error;
4579   GDir *directory;
4580   const gchar *entry;
4581 
4582   dir = report_format_trash_dir (NULL);
4583   error = NULL;
4584   directory = g_dir_open (dir, 0, &error);
4585 
4586   if (directory == NULL)
4587     {
4588       assert (error);
4589       if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
4590         {
4591           g_warning ("g_dir_open (%s) failed - %s", dir, error->message);
4592           g_error_free (error);
4593           g_free (dir);
4594           return -1;
4595         }
4596     }
4597   else
4598     {
4599       entry = NULL;
4600       while ((entry = g_dir_read_name (directory)) != NULL)
4601         {
4602           gchar *end;
4603           if (strtol (entry, &end, 10) < 0)
4604             /* Only interested in positive numbers. */
4605             continue;
4606           if (*end != '\0')
4607             /* Only interested in numbers. */
4608             continue;
4609 
4610           /* Check whether the db has a report format with this ID. */
4611           if (sql_int ("SELECT count(*) FROM report_formats_trash"
4612                        " WHERE id = %s;",
4613                        entry)
4614               == 0)
4615             {
4616               int ret;
4617               gchar *entry_path;
4618 
4619               /* Remove the directory. */
4620 
4621               entry_path = g_build_filename (dir, entry, NULL);
4622               ret = gvm_file_remove_recurse (entry_path);
4623               g_free (entry_path);
4624               if (ret)
4625                 {
4626                   g_warning ("%s: failed to remove %s from %s",
4627                              __func__, entry, dir);
4628                   g_dir_close (directory);
4629                   g_free (dir);
4630                   return -1;
4631                 }
4632             }
4633         }
4634       g_dir_close (directory);
4635     }
4636   g_free (dir);
4637   return 0;
4638 }
4639