comm.c 15 KB
Newer Older
Lock Lin's avatar
Lock Lin committed
1
 /* OpenVAS
2
  * $Id: comm.c 23992 2015-12-16 23:40:29Z kroosec $
Lock Lin's avatar
Lock Lin committed
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
  * Description: Communication manager; it manages the NTP Protocol version 1.0 and 1.1.
  *
  * Authors: - Renaud Deraison <deraison@nessus.org> (Original pre-fork develoment)
  *          - Tim Brown <mailto:timb@openvas.org> (Initial fork)
  *          - Laban Mwangi <mailto:labanm@openvas.org> (Renaming work)
  *          - Tarik El-Yassem <mailto:tarik@openvas.org> (Headers section)
  *
  * Copyright:
  * Portions Copyright (C) 2006 Software in the Public Interest, Inc.
  * Based on work Copyright (C) 1998 - 2006 Tenable Network Security, Inc.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2,
  * as published by the Free Software Foundation
  *
  * This program is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  */

#include <string.h> /* for strchr() */
#include <stdlib.h> /* for atoi() */

#include <stdarg.h>

#include <glib.h>

#include <openvas/nasl/nasl.h>
#include <openvas/misc/nvt_categories.h>/* for ACT_FIRST */
37
#include <openvas/misc/plugutils.h>
Lock Lin's avatar
Lock Lin committed
38
#include <openvas/misc/network.h>       /* for recv_line */
39
#include <openvas/misc/prefs.h>         /* for preferences_get() */
Lock Lin's avatar
Lock Lin committed
40

41
#include <openvas/base/nvticache.h>     /* for nvticache_t */
Lock Lin's avatar
Lock Lin committed
42 43

#include "comm.h"
44
#include "ntp.h"
Lock Lin's avatar
Lock Lin committed
45 46
#include "log.h"
#include "pluginscheduler.h"    /* for define LAUNCH_DISABLED */
47
#include "pluginload.h"    /* for current_loading_plugins */
Lock Lin's avatar
Lock Lin committed
48 49 50
#include "sighand.h"
#include "utils.h"

51 52
extern struct arglist *global_plugins;

Lock Lin's avatar
Lock Lin committed
53 54
/**
 * @brief Initializes the communication between the scanner (us) and the client.
55 56
 *
 * @return 0 if success, -1 if error.
Lock Lin's avatar
Lock Lin committed
57 58 59 60 61 62 63 64 65 66 67
 */
int
comm_init (int soc)
{
  char buf[1024];
  int n;

  /* We must read the version of the OTP the client
     wants us to use */
  n = recv_line (soc, buf, sizeof (buf) - 1);
  if (n <= 0)
68 69 70 71
    {
      log_write ("Failed reading client-requested OTP version.");
      return -1;
    }
Lock Lin's avatar
Lock Lin committed
72 73

  buf[sizeof (buf) - 1] = '\0';
74
  if (strncmp (buf, "< OTP/2.0 >", 11))
Lock Lin's avatar
Lock Lin committed
75
    {
76 77
      log_write ("Unknown client-requested OTP version: %s.", buf);
      return -1;
Lock Lin's avatar
Lock Lin committed
78
    }
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  nsend (soc, "< OTP/2.0 >\n", 12, 0);
  return 0;
}

/**
 * @brief Informs the client that the scanner is still loading.
 *
 * @param[in]   soc Socket to send and receive from.
 *
 * @return 0 if success, -1 if error.
 */
int
comm_loading (int soc)
{
  int n;
  size_t len;
  char buf[256];
  n = recv_line (soc, buf, sizeof (buf) - 1);
  if (n <= 0)
Lock Lin's avatar
Lock Lin committed
98
    {
99 100
      log_write ("Failed reading client input.");
      return -1;
Lock Lin's avatar
Lock Lin committed
101
    }
102 103 104 105 106 107 108 109 110 111 112
  /* Always respond with SCANNER_LOADING. */
  g_snprintf (buf, sizeof (buf), "SCANNER_LOADING <|> %d <|> %d\n",
              current_loading_plugins (), total_loading_plugins ());
  len = strlen (buf);
  n = nsend (soc, buf, len, 0);
  if (n != len)
    return -1;
  while (n > 0)
    n = recv_line (soc, buf, sizeof (buf) - 1);

  return 0;
Lock Lin's avatar
Lock Lin committed
113 114
}

115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
/**
 * Determines if the client is still connected.
 * @return 1 if the client is here, 0 if it's not.
 */
static int
is_client_present (int soc)
{
  fd_set rd;
  struct timeval tv;
  int m, e;

  stream_zero (&rd);
  m = stream_set (soc, &rd);
again:
  tv.tv_sec = 2;
  tv.tv_usec = 0;
  errno = 0;
  e = select (m + 1, &rd, NULL, NULL, &tv);
  if (e < 0)
    {
      if (errno == EINTR)
        goto again;
      return 0;
    }

  if (e > 0 && !data_left (openvas_get_socket_from_connection (soc)))
    return 0;
  return 1;
}
Lock Lin's avatar
Lock Lin committed
144 145 146 147 148

/**
 * @brief This function must be called at the end of a session.
 */
void
149
comm_terminate (int soc)
Lock Lin's avatar
Lock Lin committed
150
{
151 152 153 154 155
  send_printf (soc, "SERVER <|> BYE <|> BYE <|> SERVER\n");
  while (is_client_present (soc))
    {
      char buffer[4096];
      int n;
Lock Lin's avatar
Lock Lin committed
156

157 158 159 160 161
      n = recv_line (soc, buffer, sizeof (buffer) - 1);
      if (n < 0 || *buffer == '\0')
        return;
    }
}
Lock Lin's avatar
Lock Lin committed
162 163 164 165 166

/**
 * @brief Sends a plugin info.
 */
void
167
send_plug_info (int soc, struct arglist *plugins)
Lock Lin's avatar
Lock Lin committed
168
{
169
  int j, ignored = 0;
Lock Lin's avatar
Lock Lin committed
170 171
  static const char *categories[] = { ACT_STRING_LIST_ALL };
#define CAT_MAX	(sizeof(categories) / sizeof(categories[0]))
172 173
  const char *name, *copyright, *summary, *version, *family;
  nvti_t *nvti = nvticache_get_by_oid_full (plugins->name);
Lock Lin's avatar
Lock Lin committed
174

175
  if (!nvti)
Lock Lin's avatar
Lock Lin committed
176
    {
177
      log_write ("NVTI not found for OID %s. Will not be sent.", plugins->name);
Lock Lin's avatar
Lock Lin committed
178 179 180
      return;
    }

181
  j = nvti_category (nvti);
Lock Lin's avatar
Lock Lin committed
182 183 184
  if (j >= CAT_MAX || j < ACT_FIRST)
    j = CAT_MAX - 1;

185 186 187
  version = nvti_version (nvti);
  if (!version)
    version = "?";
Lock Lin's avatar
Lock Lin committed
188

189
  if ((name = nvti_name (nvti)) == NULL)
Lock Lin's avatar
Lock Lin committed
190
    {
191 192
      log_write ("Inconsistent data (no name): %s - not applying this plugin",
                 nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
193 194
      ignored = 1;
    }
195
  else if (strchr (name, '\n') != NULL)
Lock Lin's avatar
Lock Lin committed
196
    {
197
      log_write ("%s: Newline in name\n", nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
198 199 200 201
      ignored = 1;
    }


202
  if ((copyright = nvti_copyright (nvti)) == NULL)
Lock Lin's avatar
Lock Lin committed
203 204
    {
      log_write
205 206
        ("Inconsistent data (no copyright): %s - not applying this plugin",
         name ? name : nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
207 208 209
      ignored = 1;
    }

210 211 212 213 214
  if (nvti_tag (nvti) && strstr (nvti_tag (nvti), "summary="))
    summary = "NOSUMMARY";
  else
    summary = nvti_summary (nvti);
  if (summary == NULL)
Lock Lin's avatar
Lock Lin committed
215
    {
216 217 218
      log_write
        ("Inconsistent data (no summary): %s - not applying this plugin",
         name ? name : nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
219 220
      ignored = 1;
    }
221
  else if (strchr (summary, '\n'))
Lock Lin's avatar
Lock Lin committed
222
    {
223
      log_write ("%s: Newline in summary\n", nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
224 225 226
      ignored = 1;
    }

227
  if ((family = nvti_family (nvti)) == NULL)
Lock Lin's avatar
Lock Lin committed
228
    {
229 230 231
      log_write
        ("Inconsistent data (no family): %s - not applying this plugin",
         name ? name : nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
232 233 234
      ignored = 1;
    }

235
  if (strchr (copyright, '\n') != NULL)
Lock Lin's avatar
Lock Lin committed
236
    {
237
      log_write ("%s: Newline in copyright\n", nvti_oid (nvti));
Lock Lin's avatar
Lock Lin committed
238 239 240 241 242
      ignored = 1;
    }

  if (!ignored)
    {
243
      char *cve_id, *bid, *xref, *tag;
Lock Lin's avatar
Lock Lin committed
244

245 246 247
      cve_id = nvti_cve (nvti);
      if (cve_id == NULL || strcmp (cve_id, "") == 0)
        cve_id = "NOCVE";
Lock Lin's avatar
Lock Lin committed
248

249 250 251
      bid = nvti_bid (nvti);
      if (bid == NULL || strcmp (bid, "") == 0)
        bid = "NOBID";
Lock Lin's avatar
Lock Lin committed
252

253 254 255
      xref = nvti_xref (nvti);
      if (xref == NULL || strcmp (xref, "") == 0)
        xref = "NOXREF";
Lock Lin's avatar
Lock Lin committed
256 257

      {
258 259 260
        char *index;
        tag = g_strdup (nvti_tag (nvti));
        index = tag;
Lock Lin's avatar
Lock Lin committed
261 262
        if (tag == NULL || strcmp (tag, "") == 0)
          tag = "NOTAG";
263 264 265 266 267 268 269
        else
          while (*index)
            {
              if (*index == '\n')
                *index = ';';
              index++;
            }
Lock Lin's avatar
Lock Lin committed
270 271
      }

272 273 274 275 276 277
      send_printf
       (soc, "%s <|> %s <|> %s <|> %s <|> %s <|> %s <|> %s <|> %s <|> %s <|> "
        "%s <|> %s\n", nvti_oid (nvti), name, categories[j], copyright,
        summary, family, version, cve_id, bid, xref, tag);
      if (tag != NULL && strcmp (tag, "NOTAG"))
        g_free (tag);
Lock Lin's avatar
Lock Lin committed
278 279
    }

280
  nvti_free (nvti);
Lock Lin's avatar
Lock Lin committed
281 282 283 284
}

/**
 * @brief Sends the plugin info for a single plugin.
285
 * @param soc Socket to use to send plugin info.
Lock Lin's avatar
Lock Lin committed
286 287 288 289
 * @param oid OID of the plugin to send.
 * @see send_plug_info
 */
void
290
plugin_send_infos (int soc, char *oid)
Lock Lin's avatar
Lock Lin committed
291
{
292
  struct arglist *plugins = global_plugins;
Lock Lin's avatar
Lock Lin committed
293 294 295 296 297 298 299 300 301

  if (!oid)
    return;
  if (!plugins)
    return;

  while (plugins)
    {
      struct arglist *args = plugins->value;
302
      if (args && !strcmp (oid, plugins->name))
Lock Lin's avatar
Lock Lin committed
303
        {
304
          send_plug_info (soc, plugins);
Lock Lin's avatar
Lock Lin committed
305 306 307 308 309 310 311 312 313 314
          return;
        }
      plugins = plugins->next;
    }
}


/**
 * @brief Sends the list of plugins that the scanner could load to the client,
 * @brief using the OTP format (calls send_plug_info for each).
315
 * @param socket    Socket to use for sending list of plugins.
Lock Lin's avatar
Lock Lin committed
316 317 318
 * @see send_plug_info
 */
void
319
comm_send_pluginlist (int soc)
Lock Lin's avatar
Lock Lin committed
320
{
321
  struct arglist *plugins = global_plugins;
Lock Lin's avatar
Lock Lin committed
322

323
  send_printf (soc, "SERVER <|> PLUGIN_LIST <|>\n");
Lock Lin's avatar
Lock Lin committed
324 325
  while (plugins && plugins->next)
    {
326
      send_plug_info (soc, plugins);
Lock Lin's avatar
Lock Lin committed
327 328
      plugins = plugins->next;
    }
329
  send_printf (soc, "<|> SERVER\n");
Lock Lin's avatar
Lock Lin committed
330 331 332 333
}

/**
 * @brief Sends the preferences of the scanner.
334
 * @param soc Socket to use for sending.
Lock Lin's avatar
Lock Lin committed
335 336
 */
void
337
comm_send_preferences (int soc)
Lock Lin's avatar
Lock Lin committed
338
{
339
  struct arglist *prefs = preferences_get ();
Lock Lin's avatar
Lock Lin committed
340 341

  /* We have to be backward compatible with the NTP/1.0 */
342
  send_printf (soc, "SERVER <|> PREFERENCES <|>\n");
Lock Lin's avatar
Lock Lin committed
343 344 345

  while (prefs && prefs->next)
    {
346 347 348
      if (prefs->type == ARG_STRING && !is_scanner_only_pref (prefs->name))
        send_printf (soc, "%s <|> %s\n", prefs->name,
                     (const char *) prefs->value);
Lock Lin's avatar
Lock Lin committed
349 350
      prefs = prefs->next;
    }
351
  send_printf (soc, "<|> SERVER\n");
Lock Lin's avatar
Lock Lin committed
352 353 354 355 356 357 358
}


/**
 * @brief This function waits for the attack order of the client.
 * Meanwhile, it processes all the messages the client could send.
 */
359
int
Lock Lin's avatar
Lock Lin committed
360 361
comm_wait_order (struct arglist *globals)
{
362
  int soc = arg_get_value_int (globals, "global_socket");
Lock Lin's avatar
Lock Lin committed
363 364 365 366 367 368 369 370 371

  for (;;)
    {
      static char str[2048];
      int n;

      n = recv_line (soc, str, sizeof (str) - 1);
      if (n < 0)
        {
372 373
          log_write ("Client closed the communication");
          return -1;
Lock Lin's avatar
Lock Lin committed
374 375 376
        }
      if (str[0] == '\0')
        if (!is_client_present (soc))
377 378 379 380 381 382 383 384 385 386 387 388 389
          {
            log_write ("Client not present");
            return -1;
          }

      n = ntp_parse_input (globals, str);
      if (n == 0)
        return 0;
      else if (n == -1)
        {
          log_write ("Client input parsing error: %s", str);
          return -1;
        }
Lock Lin's avatar
Lock Lin committed
390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
    }
}

/*-------------------------------------------------------------------------------*/

/** @TODO Consolidate sorting mechanisms spread over the openvas project.
 *        Rename function (qsort_oid?). */

/**
 * Q-Sort comparison function.
 * @param a An arglist** to compare against b.
 * @param b An arglist** to compare against a.
 */
static int
qsort_cmp (const void *a, const void *b)
{
  struct arglist **plugin_a = (struct arglist **) a;
  struct arglist **plugin_b = (struct arglist **) b;

409
  return (strcmp ((*plugin_a)->name, (*plugin_b)->name));
Lock Lin's avatar
Lock Lin committed
410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428
}

/**
 * Retrieves a plugin defined by its OID from a range within a sorted plugin
 * array.
 * Recursively defined, uses divide and conquer approach.
 */
static struct arglist *
_get_plug_by_oid (struct arglist **array, char *oid, int start, int end,
                  int rend)
{
  int mid;
  char *plugin_oid;

  if (start >= rend)
    return NULL;

  if (start == end)
    {
429
      plugin_oid = array[start]->name;
Lock Lin's avatar
Lock Lin committed
430 431 432 433 434 435 436
      if (strcmp (plugin_oid, oid) == 0)
        return array[start];
      else
        return NULL;
    }

  mid = (start + end) / 2;
437
  plugin_oid = array[mid]->name;
Lock Lin's avatar
Lock Lin committed
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464
  if (strcmp (plugin_oid, oid) > 0)
    return _get_plug_by_oid (array, oid, start, mid, rend);
  else if (strcmp (plugin_oid, oid) < 0)
    return _get_plug_by_oid (array, oid, mid + 1, end, rend);

  return array[mid];
}

/**
 * @brief Retrieves a plugin defined by its OID from a plugin arrray.
 */
static struct arglist *
get_plug_by_oid (struct arglist **array, char *oid, int num_plugins)
{
  return _get_plug_by_oid (array, oid, 0, num_plugins, num_plugins);
}

/*-------------------------------------------------------------------------------*/


/**
 * Enable the plugins which have been selected by the user, or all if
 * list == NULL or list == "-1;";
 * @param list A user (client) defined semicolon delimited list, of plugin(oids)
 *             that shall be enabled. If NULL or "-1;" all plugins are enabled!
 */
void
465
comm_setup_plugins (char *list)
Lock Lin's avatar
Lock Lin committed
466 467
{
  int num_plugins = 0;
468
  struct arglist *plugins = global_plugins;
Lock Lin's avatar
Lock Lin committed
469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496
  struct arglist *p = plugins;
  struct arglist **array;
  char *t;
  char *oid;
  int i;
  int enable = LAUNCH_DISABLED;

  if (p == NULL)
    return;
  if (list == NULL)
    list = "-1;";

  if (atoi (list) == -1)
    enable = LAUNCH_RUN;
  /* Disable every plugin */
  while (p->next != NULL)
    {
      num_plugins++;
      plug_set_launch (p->value, enable);
      p = p->next;
    }

  if (num_plugins == 0 || enable != 0)
    return;

  /* Store the plugins in an array for quick access */
  p = plugins;
  i = 0;
497
  array = g_malloc0 (num_plugins * sizeof (struct arglist **));
Lock Lin's avatar
Lock Lin committed
498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516
  while (p->next != NULL)
    {
      array[i++] = p;
      p = p->next;
    }

  qsort (array, num_plugins, sizeof (struct arglist *), qsort_cmp);

  t = list;
  oid = strtok (t, ";");

  /* Read the list provided by the user and enable the plugins accordingly */
  while (oid != NULL)
    {
      p = get_plug_by_oid (array, oid, num_plugins);
      if (p != NULL)
        plug_set_launch (p->value, LAUNCH_RUN);
#ifdef DEBUG
      else
517
        log_write ("PLUGIN ID %s NOT FOUND!!!", oid);
Lock Lin's avatar
Lock Lin committed
518 519 520 521
#endif
      oid = strtok (NULL, ";");
    }

522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555
  g_free (array);
}


/**
 * @brief Determine the version of the NVT feed.
 * @param[out] feed_version Buffer to contain feed_version.
 * @param[in]  feed_size    Size of feed_version buffer.
 *
 * @return Feed version. Free on caller.
 */
static int
nvt_feed_version (char *feed_version, int feed_size)
{
  FILE *foutput;
  gchar *command, *info_file;
  info_file = g_build_filename (OPENVAS_NVT_DIR, "plugin_feed_info.inc", NULL);
  command = g_strdup_printf ("grep PLUGIN_SET %s | sed -e 's/[^0-9]//g'",
                             info_file);

  foutput = popen (command, "r");
  if (fgets (feed_version, feed_size, foutput) == NULL)
    {
      pclose (foutput);
      g_free (info_file);
      g_free (command);
      return 1;
    }

  feed_version[strlen (feed_version) - 1] = '\0';
  pclose (foutput);
  g_free (info_file);
  g_free (command);
  return 0;
Lock Lin's avatar
Lock Lin committed
556 557 558
}

/**
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579
 * @brief Determine whether a buffer contains a valid feed version.
 *
 * @param[in] feed_version Buffer containing feed_version.
 *
 * @return 1 is valid feed_version, 0 otherwise.
 */
static int
is_valid_feed_version (const char *feed_version)
{
  if (feed_version == NULL)
    return 0;

  while (*feed_version)
    if (!g_ascii_isdigit (*feed_version++))
      return 0;
  return 1;
}

/**
 * @brief Send the OTP NVT_INFO message and then handle any COMPLETE_LIST
 * and PLUGIN_INFO commands.
Lock Lin's avatar
Lock Lin committed
580 581
 */
void
582
comm_send_nvt_info (int soc)
Lock Lin's avatar
Lock Lin committed
583 584
{
  char buf[2048];
585 586
  gchar *feed_version;
  int feed_size = 32;
Lock Lin's avatar
Lock Lin committed
587

588 589 590 591 592 593
  feed_version = g_malloc0 (feed_size);
  nvt_feed_version (feed_version, feed_size);

  send_printf (soc, "SERVER <|> NVT_INFO <|> %s <|> SERVER\n",
               is_valid_feed_version (feed_version)
                ? feed_version : "NOVERSION");
Lock Lin's avatar
Lock Lin committed
594

595
  g_free (feed_version);
Lock Lin's avatar
Lock Lin committed
596 597 598 599

  for (;;)
    {
      bzero (buf, sizeof (buf));
600
      recv_line (soc, buf, sizeof (buf) - 1);
Lock Lin's avatar
Lock Lin committed
601
      if (strstr (buf, "COMPLETE_LIST"))
602
        comm_send_pluginlist (soc);
Lock Lin's avatar
Lock Lin committed
603 604 605 606 607 608 609 610 611 612 613 614 615 616
      else if (strstr (buf, "PLUGIN_INFO"))
        {
          char *t = strstr (buf, " <|> ");
          char *s;
          if (!t)
            continue;
          t = strstr (t + 5, " <|> ");
          if (!t)
            continue;
          s = t + 5;
          t = strchr (s, ' ');
          if (!t)
            continue;
          t[0] = '\0';
617
          plugin_send_infos (soc, s);
Lock Lin's avatar
Lock Lin committed
618 619 620 621 622
        }
      else
        break;
    }
}