1 /* Copyright (C) 2014-2021 Greenbone Networks GmbH
2  *
3  * SPDX-License-Identifier: GPL-2.0-or-later
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the 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 General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 /**
21  * @file
22  * @brief API for Open Scanner Protocol communication.
23  */
24 
25 #include "osp.h"
26 
27 #include "../base/hosts.h"       /* for gvm_get_host_type */
28 #include "../util/serverutils.h" /* for gvm_server_close, gvm_server_open_w... */
29 
30 #include <assert.h>        /* for assert */
31 #include <gnutls/gnutls.h> /* for gnutls_session_int, gnutls_session_t */
32 #include <stdarg.h>        /* for va_list */
33 #include <stdio.h>         /* for FILE, fprintf and related functions */
34 #include <stdlib.h>        /* for NULL, atoi */
35 #include <string.h>        /* for strcmp, strlen, strncpy */
36 #include <sys/socket.h>    /* for AF_UNIX, connect, socket, SOCK_STREAM */
37 #include <sys/un.h>        /* for sockaddr_un, sa_family_t */
38 #include <unistd.h>        /* for close */
39 
40 #undef G_LOG_DOMAIN
41 /**
42  * @brief GLib log domain.
43  */
44 #define G_LOG_DOMAIN "libgvm osp"
45 
46 /**
47  * @brief Struct holding options for OSP connection.
48  */
49 struct osp_connection
50 {
51   gnutls_session_t session; /**< Pointer to GNUTLS Session. */
52   int socket;               /**< Socket. */
53   char *host;               /**< Host. */
54   int port;                 /**< Port. */
55 };
56 
57 /**
58  * @brief Struct holding options for OSP parameters.
59  */
60 struct osp_param
61 {
62   char *id;              /**< Parameter id. */
63   char *name;            /**< Parameter name. */
64   char *desc;            /**< Parameter description. */
65   char *def;             /**< Default value. */
66   osp_param_type_t type; /**< Parameter type. */
67   int mandatory;         /**< If mandatory or not. */
68 };
69 
70 /**
71  * @brief Struct credential information for OSP.
72  */
73 struct osp_credential
74 {
75   gchar *type;           /**< Credential type */
76   gchar *service;        /**< Service the credential is for */
77   gchar *port;           /**< Port the credential is for */
78   GHashTable *auth_data; /**< Authentication data (username, password, etc.)*/
79 };
80 
81 /**
82  * @brief Struct holding target information.
83  */
84 struct osp_target
85 {
86   GSList *credentials;   /** Credentials to use in the scan */
87   gchar *exclude_hosts;  /** String defining one or many hosts to exclude */
88   gchar *hosts;          /** String defining one or many hosts to scan */
89   gchar *ports;          /** String defining the ports to scan */
90   gchar *finished_hosts; /** String defining hosts to exclude as finished */
91   /* Alive test methods can be specified either as bitfield or via selection of
92   individual methods */
93   int alive_test; /** Value defining an alive test method */
94   gboolean icmp;
95   gboolean tcp_syn;
96   gboolean tcp_ack;
97   gboolean arp;
98   gboolean consider_alive;
99   int reverse_lookup_unify; /** Value defining reverse_lookup_unify opt */
100   int reverse_lookup_only;  /** Value defining reverse_lookup_only opt */
101 };
102 
103 /**
104  * @brief Struct holding vt_group information
105  */
106 struct osp_vt_group
107 {
108   gchar *filter;
109 };
110 
111 /**
112  * @brief Struct holding vt_group information
113  */
114 struct osp_vt_single
115 {
116   gchar *vt_id;
117   GHashTable *vt_values;
118 };
119 
120 static int
121 osp_send_command (osp_connection_t *, entity_t *, const char *, ...)
122   __attribute__ ((__format__ (__printf__, 3, 4)));
123 
124 /**
125  * @brief Open a new connection to an OSP server.
126  *
127  * @param[in]   host    Host of OSP server.
128  * @param[in]   port    Port of OSP server.
129  * @param[in]   cacert  CA public key.
130  * @param[in]   cert    Client public key.
131  * @param[in]   key     Client private key.
132  *
133  * @return New osp connection, NULL if error.
134  */
135 osp_connection_t *
osp_connection_new(const char * host,int port,const char * cacert,const char * cert,const char * key)136 osp_connection_new (const char *host, int port, const char *cacert,
137                     const char *cert, const char *key)
138 {
139   osp_connection_t *connection;
140 
141   if (host && *host == '/')
142     {
143       struct sockaddr_un addr;
144 
145       connection = g_malloc0 (sizeof (*connection));
146       connection->socket = socket (AF_UNIX, SOCK_STREAM, 0);
147       if (connection->socket == -1)
148         {
149           g_free (connection);
150           return NULL;
151         }
152 
153       addr.sun_family = AF_UNIX;
154       strcpy (addr.sun_path, host);
155       if (connect (connection->socket, (struct sockaddr *) &addr, sizeof(struct sockaddr_un)) == -1)
156         {
157           close (connection->socket);
158           g_free (connection);
159           return NULL;
160         }
161     }
162   else
163     {
164       if (port <= 0 || port > 65535)
165         return NULL;
166       if (!host || gvm_get_host_type (host) == -1)
167         return NULL;
168       if (!cert || !key || !cacert)
169         return NULL;
170 
171       connection = g_malloc0 (sizeof (*connection));
172       connection->socket = gvm_server_open_with_cert (
173         &connection->session, host, port, cacert, cert, key);
174     }
175   if (connection->socket == -1)
176     {
177       g_free (connection);
178       return NULL;
179     }
180 
181   connection->host = g_strdup (host);
182   connection->port = port;
183   return connection;
184 }
185 
186 /**
187  * @brief Send a command to an OSP server.
188  *
189  * @param[in]   connection  Connection to OSP server.
190  * @param[out]  response    Response from OSP server.
191  * @param[in]   fmt         OSP Command to send.
192  *
193  * @return 0 and response, 1 if error.
194  */
195 int
osp_send_command(osp_connection_t * connection,entity_t * response,const char * fmt,...)196 osp_send_command (osp_connection_t *connection, entity_t *response,
197                   const char *fmt, ...)
198 {
199   va_list ap;
200   int rc = 1;
201 
202   va_start (ap, fmt);
203 
204   if (!connection || !fmt || !response)
205     goto out;
206 
207   if (*connection->host == '/')
208     {
209       if (gvm_socket_vsendf (connection->socket, fmt, ap) == -1)
210         goto out;
211       if (read_entity_s (connection->socket, response))
212         goto out;
213     }
214   else
215     {
216       if (gvm_server_vsendf (&connection->session, fmt, ap) == -1)
217         goto out;
218       if (read_entity (&connection->session, response))
219         goto out;
220     }
221 
222   rc = 0;
223 
224 out:
225   va_end (ap);
226 
227   return rc;
228 }
229 
230 /**
231  * @brief Close a connection to an OSP server.
232  *
233  * @param[in]   connection  Connection to OSP server to close.
234  */
235 void
osp_connection_close(osp_connection_t * connection)236 osp_connection_close (osp_connection_t *connection)
237 {
238   if (!connection)
239     return;
240 
241   if (*connection->host == '/')
242     close (connection->socket);
243   else
244     gvm_server_close (connection->socket, connection->session);
245   g_free (connection->host);
246   g_free (connection);
247 }
248 
249 /**
250  * @brief Get the scanner version from an OSP server.
251  *
252  * @param[in]   connection  Connection to an OSP server.
253  * @param[out]  s_name      Parsed scanner name.
254  * @param[out]  s_version   Parsed scanner version.
255  * @param[out]  d_name      Parsed scanner name.
256  * @param[out]  d_version   Parsed scanner version.
257  * @param[out]  p_name      Parsed scanner name.
258  * @param[out]  p_version   Parsed scanner version.
259  *
260  * @return 0 if success, 1 if error.
261  */
262 int
osp_get_version(osp_connection_t * connection,char ** s_name,char ** s_version,char ** d_name,char ** d_version,char ** p_name,char ** p_version)263 osp_get_version (osp_connection_t *connection, char **s_name, char **s_version,
264                  char **d_name, char **d_version, char **p_name,
265                  char **p_version)
266 {
267   entity_t entity, child, gchild;
268 
269   if (!connection)
270     return 1;
271 
272   if (osp_send_command (connection, &entity, "<get_version/>"))
273     return 1;
274 
275   child = entity_child (entity, "scanner");
276   if (!child)
277     goto err_get_version;
278   gchild = entity_child (child, "name");
279   if (!gchild)
280     goto err_get_version;
281   if (s_name)
282     *s_name = g_strdup (entity_text (gchild));
283   gchild = entity_child (child, "version");
284   if (!gchild)
285     goto err_get_version;
286   if (s_version)
287     *s_version = g_strdup (entity_text (gchild));
288 
289   child = entity_child (entity, "daemon");
290   if (!child)
291     goto err_get_version;
292   gchild = entity_child (child, "name");
293   if (!gchild)
294     goto err_get_version;
295   if (d_name)
296     *d_name = g_strdup (entity_text (gchild));
297   gchild = entity_child (child, "version");
298   if (!gchild)
299     goto err_get_version;
300   if (d_version)
301     *d_version = g_strdup (entity_text (gchild));
302 
303   child = entity_child (entity, "protocol");
304   if (!child)
305     goto err_get_version;
306   gchild = entity_child (child, "name");
307   if (!gchild)
308     goto err_get_version;
309   if (p_name)
310     *p_name = g_strdup (entity_text (gchild));
311   gchild = entity_child (child, "version");
312   if (!gchild)
313     goto err_get_version;
314   if (p_version)
315     *p_version = g_strdup (entity_text (gchild));
316 
317   free_entity (entity);
318   return 0;
319 
320 err_get_version:
321   g_warning ("Erroneous OSP <get_version/> response.");
322   if (s_name)
323     g_free (*s_name);
324   if (s_version)
325     g_free (*s_version);
326   if (d_name)
327     g_free (*d_name);
328   if (d_version)
329     g_free (*d_version);
330   if (p_name)
331     g_free (*p_name);
332   if (p_version)
333     g_free (*p_version);
334   free_entity (entity);
335   return 1;
336 }
337 
338 /**
339  * @brief Get the VTs version from an OSP server.
340  *
341  * @param[in]   connection    Connection to an OSP server.
342  * @param[out]  vts_version   Parsed scanner version.
343  * @param[out]  error         Pointer to error, if any.
344  *
345  * @return 0 if success, 1 if error.
346  */
347 int
osp_get_vts_version(osp_connection_t * connection,char ** vts_version,char ** error)348 osp_get_vts_version (osp_connection_t *connection, char **vts_version,
349                      char **error)
350 {
351   entity_t entity, vts;
352   const char *version;
353   const char *status, *status_text;
354   osp_get_vts_opts_t get_vts_opts;
355 
356   if (!connection)
357     return 1;
358 
359   get_vts_opts = osp_get_vts_opts_default;
360   get_vts_opts.version_only = 1;
361   if (osp_get_vts_ext (connection, get_vts_opts, &entity))
362     return 1;
363 
364   status = entity_attribute (entity, "status");
365 
366   if (status != NULL && !strcmp (status, "400"))
367     {
368       status_text = entity_attribute (entity, "status_text");
369       g_debug ("%s: %s - %s.", __func__, status, status_text);
370       if (error)
371         *error = g_strdup (status_text);
372       free_entity (entity);
373       return 1;
374     }
375 
376   vts = entity_child (entity, "vts");
377   if (!vts)
378     {
379       g_warning ("%s: element VTS missing.", __func__);
380       free_entity (entity);
381       return 1;
382     }
383 
384   version = entity_attribute (vts, "vts_version");
385 
386   if (vts_version)
387     *vts_version = g_strdup (version);
388 
389   free_entity (entity);
390   return 0;
391 }
392 
393 /**
394  * @brief Get all VTs from an OSP server.
395  *
396  * @param[in]   connection    Connection to an OSP server.
397  * @param[out]  vts           VTs.
398  *
399  * @return 0 if success, 1 if error.
400  */
401 int
osp_get_vts(osp_connection_t * connection,entity_t * vts)402 osp_get_vts (osp_connection_t *connection, entity_t *vts)
403 {
404   if (!connection)
405     return 1;
406 
407   if (vts == NULL)
408     return 1;
409 
410   if (osp_send_command (connection, vts, "<get_vts/>"))
411     return 1;
412 
413   return 0;
414 }
415 
416 /**
417  * @brief Get filtered set of VTs from an OSP server.
418  *
419  * @param[in]   connection  Connection to an OSP server.
420  * @param[in]   opts        Struct containing the options to apply.
421  * @param[out]  vts         VTs.
422  *
423  * @return 0 if success, 1 if error.
424  */
425 int
osp_get_vts_ext(osp_connection_t * connection,osp_get_vts_opts_t opts,entity_t * vts)426 osp_get_vts_ext (osp_connection_t *connection, osp_get_vts_opts_t opts,
427                  entity_t *vts)
428 {
429   if (!connection)
430     return 1;
431 
432   if (vts == NULL)
433     return 1;
434 
435   if (opts.version_only == 1)
436     {
437       if (osp_send_command (connection, vts, "<get_vts version_only='1'/>"))
438         return 1;
439       return 0;
440     }
441 
442   if (opts.filter)
443     {
444       if (osp_send_command (connection, vts, "<get_vts filter='%s'/>",
445                             opts.filter))
446         return 1;
447       return 0;
448     }
449 
450   if (osp_send_command (connection, vts, "<get_vts/>"))
451     return 1;
452   return 0;
453 }
454 
455 /**
456  * @brief Delete a scan from an OSP server.
457  *
458  * @param[in]   connection  Connection to an OSP server.
459  * @param[in]   scan_id     ID of scan to delete.
460  *
461  * @return 0 if success, 1 if error.
462  */
463 int
osp_delete_scan(osp_connection_t * connection,const char * scan_id)464 osp_delete_scan (osp_connection_t *connection, const char *scan_id)
465 {
466   entity_t entity;
467   int ret = 0;
468   const char *status;
469 
470   if (!connection)
471     return 1;
472 
473   ret = osp_send_command (connection, &entity, "<delete_scan scan_id='%s'/>",
474                           scan_id);
475   if (ret)
476     return 1;
477 
478   /* Check response status. */
479   status = entity_attribute (entity, "status");
480   assert (status);
481   if (strcmp (status, "200"))
482     ret = 1;
483 
484   free_entity (entity);
485   return ret;
486 }
487 
488 /**
489  * @brief Get performance graphics from an OSP server.
490  *
491  * @param[in]   connection  Connection to an OSP server.
492  * @param[in]   opts        Struct containing the options to apply.
493  * @param[out]  graph       Graphic base64 encoded.
494  * @param[out]  error       Pointer to error, if any.
495  *
496  * @return 0 if success, -1 if error.
497  */
498 int
osp_get_performance_ext(osp_connection_t * connection,osp_get_performance_opts_t opts,char ** graph,char ** error)499 osp_get_performance_ext (osp_connection_t *connection,
500                          osp_get_performance_opts_t opts, char **graph,
501                          char **error)
502 {
503   entity_t entity;
504   int rc;
505   time_t now;
506 
507   if (!connection)
508     {
509       if (error)
510         *error = g_strdup ("Couldn't send get_performance command "
511                            "to scanner. Not valid connection");
512       return -1;
513     }
514 
515   time (&now);
516 
517   if (!opts.titles || !strcmp (opts.titles, "") || opts.start < 0
518       || opts.start > now || opts.end < 0 || opts.end > now)
519     {
520       if (error)
521         *error = g_strdup ("Couldn't send get_performance command "
522                            "to scanner. Bad or missing parameters.");
523       return -1;
524     }
525 
526   rc = osp_send_command (connection, &entity,
527                          "<get_performance start='%d' "
528                          "end='%d' titles='%s'/>",
529                          opts.start, opts.end, opts.titles);
530 
531   if (rc)
532     {
533       if (error)
534         *error = g_strdup ("Couldn't send get_performance command to scanner");
535       return -1;
536     }
537 
538   if (graph && entity_text (entity) && strcmp (entity_text (entity), "\0"))
539     *graph = g_strdup (entity_text (entity));
540   else
541     {
542       const char *text = entity_attribute (entity, "status_text");
543 
544       assert (text);
545       if (error)
546         *error = g_strdup (text);
547       free_entity (entity);
548       return -1;
549     }
550 
551   free_entity (entity);
552   return 0;
553 }
554 
555 /**
556  * @brief Get a scan status from an OSP server
557  *
558  * @param[in]   connection  Connection to an OSP server.
559  * @param[in]   scan_id     ID of scan to get.
560  * @param[out]  error       Pointer to error, if any.
561  *
562  * @return Osp scan status
563  */
564 osp_scan_status_t
osp_get_scan_status_ext(osp_connection_t * connection,osp_get_scan_status_opts_t opts,char ** error)565 osp_get_scan_status_ext (osp_connection_t *connection,
566                          osp_get_scan_status_opts_t opts, char **error)
567 {
568   entity_t entity, child;
569   int rc;
570   osp_scan_status_t status = OSP_SCAN_STATUS_ERROR;
571 
572   if (!connection)
573     {
574       if (error)
575         *error = g_strdup ("Couldn't send get_scans command "
576                            "to scanner. Not valid connection");
577       return status;
578     }
579 
580   assert (opts.scan_id);
581   rc = osp_send_command (connection, &entity,
582                          "<get_scans scan_id='%s'"
583                          " details='0'"
584                          " pop_results='0'/>",
585                          opts.scan_id);
586 
587   if (rc)
588     {
589       if (error)
590         *error = g_strdup ("Couldn't send get_scans command to scanner");
591       return status;
592     }
593 
594   child = entity_child (entity, "scan");
595   if (!child)
596     {
597       const char *text = entity_attribute (entity, "status_text");
598 
599       assert (text);
600       if (error)
601         *error = g_strdup (text);
602       free_entity (entity);
603       return status;
604     }
605 
606   if (!strcmp (entity_attribute (child, "status"), "queued"))
607     status = OSP_SCAN_STATUS_QUEUED;
608   else if (!strcmp (entity_attribute (child, "status"), "init"))
609     status = OSP_SCAN_STATUS_INIT;
610   else if (!strcmp (entity_attribute (child, "status"), "running"))
611     status = OSP_SCAN_STATUS_RUNNING;
612   else if (!strcmp (entity_attribute (child, "status"), "stopped"))
613     status = OSP_SCAN_STATUS_STOPPED;
614   else if (!strcmp (entity_attribute (child, "status"), "finished"))
615     status = OSP_SCAN_STATUS_FINISHED;
616   else if (!strcmp (entity_attribute (child, "status"), "interrupted"))
617     status = OSP_SCAN_STATUS_INTERRUPTED;
618 
619   free_entity (entity);
620   return status;
621 }
622 
623 /**
624  * @brief Get a scan from an OSP server, optionally removing the results.
625  *
626  * @param[in]   connection  Connection to an OSP server.
627  * @param[in]   scan_id     ID of scan to get.
628  * @param[out]  report_xml  Scans report.
629  * @param[in]   details     0 for no scan details, 1 otherwise.
630  * @param[in]   pop_results 0 to leave results, 1 to pop results from scanner.
631  * @param[out]  error       Pointer to error, if any.
632  *
633  * @return Scan progress if success, -1 if error.
634  */
635 int
osp_get_scan_pop(osp_connection_t * connection,const char * scan_id,char ** report_xml,int details,int pop_results,char ** error)636 osp_get_scan_pop (osp_connection_t *connection, const char *scan_id,
637                   char **report_xml, int details, int pop_results, char **error)
638 {
639   entity_t entity, child;
640   int progress;
641   int rc;
642 
643   if (!connection)
644     {
645       if (error)
646         *error = g_strdup ("Couldn't send get_scan command "
647                            "to scanner. Not valid connection");
648       return -1;
649     }
650   assert (scan_id);
651   rc = osp_send_command (connection, &entity,
652                          "<get_scans scan_id='%s'"
653                          " details='%d'"
654                          " pop_results='%d'/>",
655                          scan_id, pop_results ? 1 : 0, details ? 1 : 0);
656   if (rc)
657     {
658       if (error)
659         *error = g_strdup ("Couldn't send get_scans command to scanner");
660       return -1;
661     }
662 
663   child = entity_child (entity, "scan");
664   if (!child)
665     {
666       const char *text = entity_attribute (entity, "status_text");
667 
668       assert (text);
669       if (error)
670         *error = g_strdup (text);
671       free_entity (entity);
672       return -1;
673     }
674   progress = atoi (entity_attribute (child, "progress"));
675   if (report_xml)
676     {
677       GString *string;
678 
679       string = g_string_new ("");
680       print_entity_to_string (child, string);
681       *report_xml = g_string_free (string, FALSE);
682     }
683   free_entity (entity);
684   return progress;
685 }
686 
687 /**
688  * @brief Get a scan from an OSP server.
689  *
690  * @param[in]   connection  Connection to an OSP server.
691  * @param[in]   scan_id     ID of scan to get.
692  * @param[out]  report_xml  Scans report.
693  * @param[in]   details     0 for no scan details, 1 otherwise.
694  * @param[out]  error       Pointer to error, if any.
695  *
696  * @return Scan progress if success, -1 if error.
697  */
698 int
osp_get_scan(osp_connection_t * connection,const char * scan_id,char ** report_xml,int details,char ** error)699 osp_get_scan (osp_connection_t *connection, const char *scan_id,
700               char **report_xml, int details, char **error)
701 {
702   return osp_get_scan_pop (connection, scan_id, report_xml, details, 0, error);
703 }
704 
705 /**
706  * @brief Stop a scan on an OSP server.
707  *
708  * @param[in]   connection  Connection to an OSP server.
709  * @param[in]   scan_id     ID of scan to delete.
710  * @param[out]  error       Pointer to error, if any.
711  *
712  * @return Scan progress if success, -1 if error.
713  */
714 int
osp_stop_scan(osp_connection_t * connection,const char * scan_id,char ** error)715 osp_stop_scan (osp_connection_t *connection, const char *scan_id, char **error)
716 {
717   entity_t entity;
718   int rc;
719 
720   if (!connection)
721     {
722       if (error)
723         *error = g_strdup ("Couldn't send stop_scan command "
724                            "to scanner. Not valid connection");
725       return -1;
726     }
727   assert (scan_id);
728   rc = osp_send_command (connection, &entity, "<stop_scan scan_id='%s'/>",
729                          scan_id);
730   if (rc)
731     {
732       if (error)
733         *error = g_strdup ("Couldn't send stop_scan command to scanner");
734       return -1;
735     }
736 
737   rc = atoi (entity_attribute (entity, "status"));
738   if (rc == 200)
739     {
740       free_entity (entity);
741       return 0;
742     }
743   else
744     {
745       const char *text = entity_attribute (entity, "status_text");
746 
747       assert (text);
748       if (error)
749         *error = g_strdup (text);
750       free_entity (entity);
751       return -1;
752     }
753 }
754 
755 /**
756  * @brief Concatenate options as xml.
757  *
758  * @param[in]     key      Tag name for xml element.
759  * @param[in]     value    Text for xml element.
760  * @param[in,out] pstr     Parameters as xml concatenated xml elements.
761  *
762  */
763 static void
option_concat_as_xml(gpointer key,gpointer value,gpointer pstr)764 option_concat_as_xml (gpointer key, gpointer value, gpointer pstr)
765 {
766   char *options_str, *tmp, *key_escaped, *value_escaped;
767 
768   options_str = *(char **) pstr;
769 
770   key_escaped = g_markup_escape_text ((char *) key, -1);
771   value_escaped = g_markup_escape_text ((char *) value, -1);
772   tmp = g_strdup_printf ("%s<%s>%s</%s>", options_str ? options_str : "",
773                          key_escaped, value_escaped, key_escaped);
774 
775   g_free (options_str);
776   g_free (key_escaped);
777   g_free (value_escaped);
778   *(char **) pstr = tmp;
779 }
780 
781 /**
782  * @brief Start an OSP scan against a target.
783  *
784  * @param[in]   connection  Connection to an OSP server.
785  * @param[in]   target      Target host to scan.
786  * @param[in]   ports       List of ports to scan.
787  * @param[in]   options     Table of scan options.
788  * @param[in]   scan_id     uuid to set for scan, null otherwise.
789  * @param[out]  error       Pointer to error, if any.
790  *
791  * @return 0 on success, -1 otherwise.
792  */
793 int
osp_start_scan(osp_connection_t * connection,const char * target,const char * ports,GHashTable * options,const char * scan_id,char ** error)794 osp_start_scan (osp_connection_t *connection, const char *target,
795                 const char *ports, GHashTable *options, const char *scan_id,
796                 char **error)
797 {
798   entity_t entity;
799   char *options_str = NULL;
800   int status;
801   int rc;
802 
803   if (!connection)
804     {
805       if (error)
806         *error = g_strdup ("Couldn't send start_scan command "
807                            "to scanner. Not valid connection");
808       return -1;
809     }
810 
811   assert (target);
812   /* Construct options string. */
813   if (options)
814     g_hash_table_foreach (options, option_concat_as_xml, &options_str);
815 
816   rc = osp_send_command (connection, &entity,
817                          "<start_scan target='%s' ports='%s' scan_id='%s'>"
818                          "<scanner_params>%s</scanner_params></start_scan>",
819                          target, ports ? ports : "", scan_id ? scan_id : "",
820                          options_str ? options_str : "");
821   g_free (options_str);
822   if (rc)
823     {
824       if (error)
825         *error = g_strdup ("Couldn't send start_scan command to scanner");
826       return -1;
827     }
828 
829   status = atoi (entity_attribute (entity, "status"));
830   if (status == 200)
831     {
832       free_entity (entity);
833       return 0;
834     }
835   else
836     {
837       const char *text = entity_attribute (entity, "status_text");
838 
839       assert (text);
840       if (error)
841         *error = g_strdup (text);
842       free_entity (entity);
843       return -1;
844     }
845 }
846 
847 /**
848  * @brief Concatenate a credential as XML.
849  *
850  * @param[in]     credential  Credential data.
851  * @param[in,out] xml_string  XML string buffer to append to.
852  *
853  */
854 static void
credential_append_as_xml(osp_credential_t * credential,GString * xml_string)855 credential_append_as_xml (osp_credential_t *credential, GString *xml_string)
856 
857 {
858   GHashTableIter auth_data_iter;
859   gchar *auth_data_name, *auth_data_value;
860 
861   xml_string_append (xml_string,
862                      "<credential type=\"%s\" service=\"%s\" port=\"%s\">",
863                      credential->type ? credential->type : "",
864                      credential->service ? credential->service : "",
865                      credential->port ? credential->port : "");
866 
867   g_hash_table_iter_init (&auth_data_iter, credential->auth_data);
868   while (g_hash_table_iter_next (&auth_data_iter, (gpointer *) &auth_data_name,
869                                  (gpointer *) &auth_data_value))
870     {
871       xml_string_append (xml_string, "<%s>%s</%s>", auth_data_name,
872                          auth_data_value, auth_data_name);
873     }
874 
875   xml_string_append (xml_string, "</credential>");
876 }
877 
878 /**
879  * @brief Concatenate a target as XML.
880  *
881  * @param[in]     target      Target data.
882  * @param[in,out] xml_string  XML string buffer to append to.
883  *
884  */
885 static void
target_append_as_xml(osp_target_t * target,GString * xml_string)886 target_append_as_xml (osp_target_t *target, GString *xml_string)
887 {
888   xml_string_append (xml_string,
889                      "<target>"
890                      "<hosts>%s</hosts>"
891                      "<exclude_hosts>%s</exclude_hosts>"
892                      "<finished_hosts>%s</finished_hosts>"
893                      "<ports>%s</ports>",
894                      target->hosts ? target->hosts : "",
895                      target->exclude_hosts ? target->exclude_hosts : "",
896                      target->finished_hosts ? target->finished_hosts : "",
897                      target->ports ? target->ports : "");
898 
899   /* Alive test specified as bitfield */
900   if (target->alive_test > 0)
901     xml_string_append (xml_string, "<alive_test>%d</alive_test>",
902                        target->alive_test);
903   /* Alive test specified via dedicated methods. Dedicted methods are ignored if
904    * alive test was already specified as bitfield.*/
905   else if (target->icmp == TRUE || target->tcp_syn == TRUE
906            || target->tcp_ack == TRUE || target->arp == TRUE
907            || target->consider_alive == TRUE)
908     {
909       xml_string_append (xml_string,
910                          "<alive_test_methods>"
911                          "<icmp>%d</icmp>"
912                          "<tcp_syn>%d</tcp_syn>"
913                          "<tcp_ack>%d</tcp_ack>"
914                          "<arp>%d</arp>"
915                          "<consider_alive>%d</consider_alive>"
916                          "</alive_test_methods>",
917                          target->icmp, target->tcp_syn, target->tcp_ack,
918                          target->arp, target->consider_alive);
919     }
920 
921   if (target->reverse_lookup_unify == 1)
922     xml_string_append (xml_string,
923                        "<reverse_lookup_unify>%d</reverse_lookup_unify>",
924                        target->reverse_lookup_unify);
925   if (target->reverse_lookup_only == 1)
926     xml_string_append (xml_string,
927                        "<reverse_lookup_only>%d</reverse_lookup_only>",
928                        target->reverse_lookup_only);
929 
930   if (target->credentials)
931     {
932       g_string_append (xml_string, "<credentials>");
933       g_slist_foreach (target->credentials, (GFunc) credential_append_as_xml,
934                        xml_string);
935       g_string_append (xml_string, "</credentials>");
936     }
937   xml_string_append (xml_string, "</target>");
938 }
939 
940 /**
941  * @brief Append VT groups as XML to a string buffer.
942  *
943  * @param[in]     vt_group    VT group data.
944  * @param[in,out] xml_string  XML string buffer to append to.
945  */
946 static void
vt_group_append_as_xml(osp_vt_group_t * vt_group,GString * xml_string)947 vt_group_append_as_xml (osp_vt_group_t *vt_group, GString *xml_string)
948 {
949   xml_string_append (xml_string, "<vt_group filter=\"%s\"/>", vt_group->filter);
950 }
951 
952 /**
953  * @brief Append VT values as XML to a string buffer.
954  *
955  * @param[in]     id          Identifier of the vt_value.
956  * @param[in]     value       The value of the vt_value.
957  * @param[in,out] xml_string  XML string buffer to append to.
958  *
959  */
960 static void
vt_value_append_as_xml(gpointer id,gchar * value,GString * xml_string)961 vt_value_append_as_xml (gpointer id, gchar *value, GString *xml_string)
962 {
963   xml_string_append (xml_string, "<vt_value id=\"%s\">%s</vt_value>",
964                      id ? id : "", value ? value : "");
965 }
966 
967 /**
968  * @brief Append single VTs as XML to a string buffer.
969  *
970  * @param[in]     vt_single   Single VT data.
971  * @param[in,out] xml_string  XML string buffer to append to.
972  */
973 static void
vt_single_append_as_xml(osp_vt_single_t * vt_single,GString * xml_string)974 vt_single_append_as_xml (osp_vt_single_t *vt_single, GString *xml_string)
975 {
976   xml_string_append (xml_string, "<vt_single id=\"%s\">", vt_single->vt_id);
977   g_hash_table_foreach (vt_single->vt_values, (GHFunc) vt_value_append_as_xml,
978                         xml_string);
979   xml_string_append (xml_string, "</vt_single>");
980 }
981 
982 /**
983  * @brief Start an OSP scan against a target.
984  *
985  * @param[in]   connection  Connection to an OSP server.
986  * @param[in]   opts        Struct containing the options to apply.
987  * @param[out]  error       Pointer to error, if any.
988  *
989  * @return 0 on success, -1 otherwise.
990  */
991 int
osp_start_scan_ext(osp_connection_t * connection,osp_start_scan_opts_t opts,char ** error)992 osp_start_scan_ext (osp_connection_t *connection, osp_start_scan_opts_t opts,
993                     char **error)
994 {
995   gchar *scanner_params_xml = NULL;
996   GString *xml;
997   GSList *list_item;
998   int list_count;
999   int rc, status;
1000   entity_t entity;
1001   gchar *cmd;
1002   char filename[] = "/tmp/osp-cmd-XXXXXX";
1003   int fd;
1004 
1005   if (!connection)
1006     {
1007       if (error)
1008         *error = g_strdup ("Couldn't send start_scan command "
1009                            "to scanner. Not valid connection");
1010       return -1;
1011     }
1012 
1013   fd = mkstemp (filename);
1014   FILE *file = fdopen (fd, "w");
1015 
1016   xml = g_string_sized_new (10240);
1017   g_string_append (xml, "<start_scan");
1018   xml_string_append (xml, " scan_id=\"%s\">", opts.scan_id ? opts.scan_id : "");
1019 
1020   g_string_append (xml, "<targets>");
1021   g_slist_foreach (opts.targets, (GFunc) target_append_as_xml, xml);
1022   g_string_append (xml, "</targets>");
1023 
1024   g_string_append (xml, "<scanner_params>");
1025   if (opts.scanner_params)
1026     {
1027       scanner_params_xml = NULL;
1028       g_hash_table_foreach (opts.scanner_params, (GHFunc) option_concat_as_xml,
1029                             &scanner_params_xml);
1030       if (scanner_params_xml)
1031         g_string_append (xml, scanner_params_xml);
1032       g_free (scanner_params_xml);
1033     }
1034   g_string_append (xml, "</scanner_params>");
1035 
1036   g_string_append (xml, "<vt_selection>");
1037   g_slist_foreach (opts.vt_groups, (GFunc) vt_group_append_as_xml, xml);
1038 
1039   fprintf (file, "%s", xml->str);
1040 
1041   g_string_free (xml, TRUE);
1042 
1043   xml = g_string_new ("");
1044   list_item = opts.vts;
1045   list_count = 0;
1046   while (list_item)
1047     {
1048       list_count++;
1049       vt_single_append_as_xml (list_item->data, xml);
1050 
1051       list_item = list_item->next;
1052 
1053       if (list_count == 1000)
1054         {
1055           fprintf (file, "%s", xml->str);
1056 
1057           g_string_free (xml, TRUE);
1058           xml = g_string_new ("");
1059           list_count = 0;
1060         }
1061     }
1062 
1063   g_string_append (xml, "</vt_selection>");
1064   g_string_append (xml, "</start_scan>");
1065 
1066   fprintf (file, "%s", xml->str);
1067   fflush (file);
1068   fclose (file);
1069   g_string_free (xml, TRUE);
1070 
1071   g_file_get_contents (filename, &cmd, NULL, NULL);
1072 
1073   rc = osp_send_command (connection, &entity, "%s", cmd);
1074 
1075   g_free (cmd);
1076   unlink (filename);
1077 
1078   if (rc)
1079     {
1080       if (error)
1081         *error = g_strdup ("Could not send start_scan command to scanner");
1082       return -1;
1083     }
1084 
1085   status = atoi (entity_attribute (entity, "status"));
1086   if (status == 200)
1087     {
1088       free_entity (entity);
1089       return 0;
1090     }
1091   else
1092     {
1093       const char *text = entity_attribute (entity, "status_text");
1094 
1095       assert (text);
1096       if (error)
1097         *error = g_strdup (text);
1098       free_entity (entity);
1099       return -1;
1100     }
1101 
1102   if (error)
1103     *error = NULL;
1104   free_entity (entity);
1105   return 0;
1106 }
1107 
1108 /**
1109  * @brief Get an OSP parameter's type from its string format.
1110  *
1111  * @param[in]   str     OSP parameter in string format.
1112  *
1113  * @return OSP parameter type.
1114  */
1115 static osp_param_type_t
osp_param_str_to_type(const char * str)1116 osp_param_str_to_type (const char *str)
1117 {
1118   assert (str);
1119   if (!strcmp (str, "integer"))
1120     return OSP_PARAM_TYPE_INT;
1121   else if (!strcmp (str, "string"))
1122     return OSP_PARAM_TYPE_STR;
1123   else if (!strcmp (str, "password"))
1124     return OSP_PARAM_TYPE_PASSWORD;
1125   else if (!strcmp (str, "file"))
1126     return OSP_PARAM_TYPE_FILE;
1127   else if (!strcmp (str, "boolean"))
1128     return OSP_PARAM_TYPE_BOOLEAN;
1129   else if (!strcmp (str, "ovaldef_file"))
1130     return OSP_PARAM_TYPE_OVALDEF_FILE;
1131   else if (!strcmp (str, "selection"))
1132     return OSP_PARAM_TYPE_SELECTION;
1133   else if (!strcmp (str, "credential_up"))
1134     return OSP_PARAM_TYPE_CRD_UP;
1135   assert (0);
1136   return 0;
1137 }
1138 
1139 /**
1140  * @brief Get an OSP parameter in string format form its type.
1141  *
1142  * @param[in]   param     OSP parameter.
1143  *
1144  * @return OSP parameter in string format.
1145  */
1146 const char *
osp_param_type_str(const osp_param_t * param)1147 osp_param_type_str (const osp_param_t *param)
1148 {
1149   osp_param_type_t type;
1150 
1151   assert (param);
1152   type = param->type;
1153   if (type == OSP_PARAM_TYPE_INT)
1154     return "integer";
1155   else if (type == OSP_PARAM_TYPE_STR)
1156     return "string";
1157   else if (type == OSP_PARAM_TYPE_PASSWORD)
1158     return "password";
1159   else if (type == OSP_PARAM_TYPE_FILE)
1160     return "file";
1161   else if (type == OSP_PARAM_TYPE_BOOLEAN)
1162     return "boolean";
1163   else if (type == OSP_PARAM_TYPE_OVALDEF_FILE)
1164     return "ovaldef_file";
1165   else if (type == OSP_PARAM_TYPE_SELECTION)
1166     return "selection";
1167   else if (type == OSP_PARAM_TYPE_CRD_UP)
1168     return "credential_up";
1169   assert (0);
1170   return NULL;
1171 }
1172 
1173 /**
1174  * @brief Get an OSP scanner's details.
1175  *
1176  * @param[in]   connection  Connection to an OSP server.
1177  * @param[out]  desc        Scanner's description.
1178  * @param[out]  params      Scanner's parameters.
1179  *
1180  * @return 0 if success, 1 if failure.
1181  */
1182 int
osp_get_scanner_details(osp_connection_t * connection,char ** desc,GSList ** params)1183 osp_get_scanner_details (osp_connection_t *connection, char **desc,
1184                          GSList **params)
1185 {
1186   entity_t entity, child;
1187   entities_t entities;
1188 
1189   assert (connection);
1190 
1191   if (osp_send_command (connection, &entity, "<get_scanner_details/>"))
1192     return 1;
1193   if (params)
1194     {
1195       child = entity_child (entity, "scanner_params");
1196       if (!child)
1197         {
1198           free_entity (entity);
1199           return 1;
1200         }
1201       entities = child->entities;
1202       while (entities)
1203         {
1204           osp_param_t *param;
1205 
1206           child = entities->data;
1207           param = osp_param_new ();
1208           param->id = g_strdup (entity_attribute (child, "id"));
1209           param->type =
1210             osp_param_str_to_type (entity_attribute (child, "type"));
1211           param->name = g_strdup (entity_text (entity_child (child, "name")));
1212           param->desc =
1213             g_strdup (entity_text (entity_child (child, "description")));
1214           param->def = g_strdup (entity_text (entity_child (child, "default")));
1215           if (entity_child (child, "mandatory"))
1216             param->mandatory =
1217               atoi (entity_text (entity_child (child, "mandatory")));
1218           *params = g_slist_append (*params, param);
1219           entities = next_entities (entities);
1220         }
1221     }
1222   if (desc)
1223     {
1224       child = entity_child (entity, "description");
1225       assert (child);
1226       *desc = g_strdup (entity_text (child));
1227     }
1228 
1229   free_entity (entity);
1230   return 0;
1231 }
1232 
1233 /**
1234  * @brief Create a new OSP parameter.
1235  *
1236  * @return New OSP parameter.
1237  */
1238 osp_param_t *
osp_param_new(void)1239 osp_param_new (void)
1240 {
1241   return g_malloc0 (sizeof (osp_param_t));
1242 }
1243 
1244 /**
1245  * @brief Get an OSP parameter's id.
1246  *
1247  * @param[in]   param   OSP parameter.
1248  *
1249  * @return ID of OSP parameter.
1250  */
1251 const char *
osp_param_id(const osp_param_t * param)1252 osp_param_id (const osp_param_t *param)
1253 {
1254   assert (param);
1255 
1256   return param->id;
1257 }
1258 
1259 /**
1260  * @brief Get an OSP parameter's name.
1261  *
1262  * @param[in]   param   OSP parameter.
1263  *
1264  * @return Name of OSP parameter.
1265  */
1266 const char *
osp_param_name(const osp_param_t * param)1267 osp_param_name (const osp_param_t *param)
1268 {
1269   assert (param);
1270 
1271   return param->name;
1272 }
1273 
1274 /**
1275  * @brief Get an OSP parameter's description.
1276  *
1277  * @param[in]   param   OSP parameter.
1278  *
1279  * @return Description of OSP parameter.
1280  */
1281 const char *
osp_param_desc(const osp_param_t * param)1282 osp_param_desc (const osp_param_t *param)
1283 {
1284   assert (param);
1285 
1286   return param->desc;
1287 }
1288 
1289 /**
1290  * @brief Get an OSP parameter's default value.
1291  *
1292  * @param[in]   param   OSP parameter.
1293  *
1294  * @return Default value of OSP parameter.
1295  */
1296 const char *
osp_param_default(const osp_param_t * param)1297 osp_param_default (const osp_param_t *param)
1298 {
1299   assert (param);
1300 
1301   return param->def;
1302 }
1303 
1304 /**
1305  * @brief Get an OSP parameter's mandatory value.
1306  *
1307  * @param[in]   param   OSP parameter.
1308  *
1309  * @return Mandatory value of OSP parameter.
1310  */
1311 int
osp_param_mandatory(const osp_param_t * param)1312 osp_param_mandatory (const osp_param_t *param)
1313 {
1314   assert (param);
1315 
1316   return param->mandatory;
1317 }
1318 
1319 /**
1320  * @brief Free an OSP parameter.
1321  *
1322  * @param[in] param OSP parameter to destroy.
1323  */
1324 void
osp_param_free(osp_param_t * param)1325 osp_param_free (osp_param_t *param)
1326 {
1327   if (!param)
1328     return;
1329   g_free (param->id);
1330   g_free (param->name);
1331   g_free (param->desc);
1332   g_free (param->def);
1333   g_free (param);
1334 }
1335 
1336 /**
1337  * @brief Allocate and initialize a new OSP credential.
1338  *
1339  * @param[in]   type      The credential type.
1340  * @param[in]   service   The service the credential is for.
1341  * @param[in]   port      The port.
1342  *
1343  * @return New osp credential.
1344  */
1345 osp_credential_t *
osp_credential_new(const char * type,const char * service,const char * port)1346 osp_credential_new (const char *type, const char *service, const char *port)
1347 {
1348   osp_credential_t *new_credential;
1349 
1350   new_credential = g_malloc0 (sizeof (osp_credential_t));
1351 
1352   new_credential->type = type ? g_strdup (type) : NULL;
1353   new_credential->service = service ? g_strdup (service) : NULL;
1354   new_credential->port = port ? g_strdup (port) : NULL;
1355   new_credential->auth_data =
1356     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1357 
1358   return new_credential;
1359 }
1360 
1361 /**
1362  * @brief Free an OSP credential.
1363  *
1364  * @param[in]   credential  The credential to free.
1365  */
1366 void
osp_credential_free(osp_credential_t * credential)1367 osp_credential_free (osp_credential_t *credential)
1368 {
1369   if (!credential)
1370     return;
1371 
1372   g_free (credential->type);
1373   g_free (credential->service);
1374   g_free (credential->port);
1375   g_hash_table_destroy (credential->auth_data);
1376   g_free (credential);
1377 }
1378 
1379 /**
1380  * @brief Get authentication data from an OSP credential.
1381  *
1382  * @param[in]  credential  The credential to get the data from.
1383  * @param[in]  name        The name of the data item to get.
1384  *
1385  * @return The requested authentication data or NULL if not available.
1386  */
1387 const gchar *
osp_credential_get_auth_data(osp_credential_t * credential,const char * name)1388 osp_credential_get_auth_data (osp_credential_t *credential, const char *name)
1389 {
1390   if (credential == NULL || name == NULL)
1391     return NULL;
1392   return g_hash_table_lookup (credential->auth_data, name);
1393 }
1394 
1395 /**
1396  * @brief Get authentication data from an OSP credential.
1397  *
1398  * @param[in]  credential  The credential to get the data from.
1399  * @param[in]  name        The name of the data item to get.
1400  * @param[in]  value       The authentication data or NULL to unset.
1401  */
1402 void
osp_credential_set_auth_data(osp_credential_t * credential,const char * name,const char * value)1403 osp_credential_set_auth_data (osp_credential_t *credential, const char *name,
1404                               const char *value)
1405 {
1406   if (credential == NULL || name == NULL)
1407     return;
1408 
1409   if (g_regex_match_simple ("^[[:alpha:]][[:alnum:]_]*$", name, 0, 0))
1410     {
1411       if (value)
1412         g_hash_table_replace (credential->auth_data, g_strdup (name),
1413                               g_strdup (value));
1414       else
1415         g_hash_table_remove (credential->auth_data, name);
1416     }
1417   else
1418     {
1419       g_warning ("%s: Invalid auth data name: %s", __func__, name);
1420     }
1421 }
1422 
1423 /**
1424  * @brief Create a new OSP target.
1425  *
1426  * @param[in]  hosts          The hostnames of the target.
1427  * @param[in]  ports          The ports of the target.
1428  * @param[in]  exclude_hosts  The excluded hosts of the target.
1429  * @param[in]  alive_test     The alive test method of the target.
1430  *
1431  * @return The newly allocated osp_target_t.
1432  */
1433 osp_target_t *
osp_target_new(const char * hosts,const char * ports,const char * exclude_hosts,int alive_test,int reverse_lookup_unify,int reverse_lookup_only)1434 osp_target_new (const char *hosts, const char *ports, const char *exclude_hosts,
1435                 int alive_test, int reverse_lookup_unify,
1436                 int reverse_lookup_only)
1437 {
1438   osp_target_t *new_target;
1439   new_target = g_malloc0 (sizeof (osp_target_t));
1440 
1441   new_target->exclude_hosts = exclude_hosts ? g_strdup (exclude_hosts) : NULL;
1442   new_target->hosts = hosts ? g_strdup (hosts) : NULL;
1443   new_target->ports = ports ? g_strdup (ports) : NULL;
1444   new_target->finished_hosts = NULL;
1445   new_target->alive_test = alive_test ? alive_test : 0;
1446   new_target->reverse_lookup_unify =
1447     reverse_lookup_unify ? reverse_lookup_unify : 0;
1448   new_target->reverse_lookup_only =
1449     reverse_lookup_only ? reverse_lookup_only : 0;
1450 
1451   return new_target;
1452 }
1453 
1454 /**
1455  * @brief Set the finished hosts of an OSP target.
1456  *
1457  * @param[in]  target         The OSP target to modify.
1458  * @param[in]  finished_hosts The hostnames to consider finished.
1459  */
1460 void
osp_target_set_finished_hosts(osp_target_t * target,const char * finished_hosts)1461 osp_target_set_finished_hosts (osp_target_t *target, const char *finished_hosts)
1462 {
1463   g_free (target->finished_hosts);
1464   target->finished_hosts = finished_hosts ? g_strdup (finished_hosts) : NULL;
1465 }
1466 
1467 /**
1468  * @brief Free an OSP target, including all added credentials.
1469  *
1470  * @param[in]  target  The OSP target to free.
1471  */
1472 void
osp_target_free(osp_target_t * target)1473 osp_target_free (osp_target_t *target)
1474 {
1475   if (!target)
1476     return;
1477 
1478   g_slist_free_full (target->credentials, (GDestroyNotify) osp_credential_free);
1479   g_free (target->exclude_hosts);
1480   g_free (target->hosts);
1481   g_free (target->ports);
1482   g_free (target);
1483 }
1484 
1485 /**
1486  * @brief Add alive test methods to OSP target.
1487  *
1488  * @param[in]  target           The OSP target to add the methods to.
1489  * @param[in]  icmp             Use ICMP ping.
1490  * @param[in]  tcp_syn          Use TCP-SYN ping.
1491  * @param[in]  tcp_ack          Use TCP-ACK ping.
1492  * @param[in]  arp              Use ARP ping.
1493  * @param[in]  consider_alive   Consider host to be alive.
1494  */
1495 void
osp_target_add_alive_test_methods(osp_target_t * target,gboolean icmp,gboolean tcp_syn,gboolean tcp_ack,gboolean arp,gboolean consider_alive)1496 osp_target_add_alive_test_methods (osp_target_t *target, gboolean icmp,
1497                                    gboolean tcp_syn, gboolean tcp_ack,
1498                                    gboolean arp, gboolean consider_alive)
1499 {
1500   if (!target)
1501     return;
1502 
1503   target->icmp = icmp;
1504   target->tcp_syn = tcp_syn;
1505   target->tcp_ack = tcp_ack;
1506   target->arp = arp;
1507   target->consider_alive = consider_alive;
1508 }
1509 
1510 /**
1511  * @brief Add a credential to an OSP target.
1512  *
1513  * @param[in]  target       The OSP target to add the credential to.
1514  * @param[in]  credential   The credential to add. Will be freed with target.
1515  */
1516 void
osp_target_add_credential(osp_target_t * target,osp_credential_t * credential)1517 osp_target_add_credential (osp_target_t *target, osp_credential_t *credential)
1518 {
1519   if (!target || !credential)
1520     return;
1521 
1522   target->credentials = g_slist_prepend (target->credentials, credential);
1523 }
1524 
1525 /**
1526  * @brief Create a new OSP VT group.
1527  *
1528  * @param[in]  filter  The filter string for the VT group.
1529  *
1530  * @return  The newly allocated VT group.
1531  */
1532 osp_vt_group_t *
osp_vt_group_new(const char * filter)1533 osp_vt_group_new (const char *filter)
1534 {
1535   osp_vt_group_t *new_vt_group;
1536   new_vt_group = g_malloc0 (sizeof (osp_vt_group_t));
1537 
1538   new_vt_group->filter = filter ? g_strdup (filter) : NULL;
1539 
1540   return new_vt_group;
1541 }
1542 
1543 /**
1544  * @brief Free a OSP VT group.
1545  *
1546  * @param[in]  vt_group  The VT group to free.
1547  */
1548 void
osp_vt_group_free(osp_vt_group_t * vt_group)1549 osp_vt_group_free (osp_vt_group_t *vt_group)
1550 {
1551   if (!vt_group)
1552     return;
1553 
1554   g_free (vt_group->filter);
1555   g_free (vt_group);
1556 }
1557 
1558 /**
1559  * @brief Create a new single OSP VT.
1560  *
1561  * @param[in]  vt_id  The id of the VT.
1562  *
1563  * @return  The newly allocated single VT.
1564  */
1565 osp_vt_single_t *
osp_vt_single_new(const char * vt_id)1566 osp_vt_single_new (const char *vt_id)
1567 {
1568   osp_vt_single_t *new_vt_single;
1569   new_vt_single = g_malloc0 (sizeof (osp_vt_single_t));
1570 
1571   new_vt_single->vt_id = vt_id ? g_strdup (vt_id) : NULL;
1572   new_vt_single->vt_values =
1573     g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1574 
1575   return new_vt_single;
1576 }
1577 
1578 /**
1579  * @brief Free a single OSP VT, including all preference values.
1580  *
1581  * @param[in]  vt_single  The OSP VT to free.
1582  */
1583 void
osp_vt_single_free(osp_vt_single_t * vt_single)1584 osp_vt_single_free (osp_vt_single_t *vt_single)
1585 {
1586   if (!vt_single)
1587     return;
1588 
1589   g_hash_table_destroy (vt_single->vt_values);
1590 
1591   g_free (vt_single->vt_id);
1592   g_free (vt_single);
1593 }
1594 
1595 /**
1596  * @brief Add a preference value to an OSP VT.
1597  * This creates a copy of the name and value.
1598  *
1599  * @param[in]  vt_single  The VT to add the preference to.
1600  * @param[in]  name       The name / identifier of the preference.
1601  * @param[in]  value      The value of the preference.
1602  */
1603 void
osp_vt_single_add_value(osp_vt_single_t * vt_single,const char * name,const char * value)1604 osp_vt_single_add_value (osp_vt_single_t *vt_single, const char *name,
1605                          const char *value)
1606 {
1607   g_hash_table_replace (vt_single->vt_values, g_strdup (name),
1608                         g_strdup (value));
1609 }
1610