"Fossies" - the Fresh Open Source Software Archive

Member "gvm-libs-11.0.1/util/kb.c" (12 May 2020, 37906 Bytes) of package /linux/misc/openvas/gvm-libs-11.0.1.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "kb.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 11.0.0_vs_11.0.1.

    1 /* Copyright (C) 2014-2019 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 Knowledge base management API - Redis backend.
   23  */
   24 
   25 #define _GNU_SOURCE
   26 
   27 #include "kb.h"
   28 
   29 #include <errno.h> /* for ENOMEM, EINVAL, EPROTO, EALREADY, ECONN... */
   30 #include <glib.h>  /* for g_log, g_free */
   31 #include <hiredis/hiredis.h> /* for redisReply, freeReplyObject, redisCommand */
   32 #include <stdbool.h>         /* for bool, true, false */
   33 #include <stdio.h>
   34 #include <stdlib.h> /* for atoi */
   35 #include <string.h> /* for strlen, strerror, strncpy, memset */
   36 
   37 #undef G_LOG_DOMAIN
   38 #define G_LOG_DOMAIN "lib  kb"
   39 
   40 /**
   41  * @file kb.c
   42  *
   43  * @brief Contains specialized structures and functions to use redis as a KB
   44  *        server.
   45  */
   46 
   47 /**
   48  * @brief Name of the namespace usage bitmap in redis.
   49  */
   50 #define GLOBAL_DBINDEX_NAME "GVM.__GlobalDBIndex"
   51 
   52 static const struct kb_operations KBRedisOperations;
   53 
   54 /**
   55  * @brief Subclass of struct kb, it contains the redis-specific fields, such as
   56  *        the redis context, current DB (namespace) id and the server socket
   57  *        path.
   58  */
   59 struct kb_redis
   60 {
   61   struct kb kb;        /**< Parent KB handle. */
   62   unsigned int max_db; /**< Max # of databases. */
   63   unsigned int db;     /**< Namespace ID number, 0 if uninitialized. */
   64   redisContext *rctx;  /**< Redis client context. */
   65   char path[0];        /**< Path to the server socket. */
   66 };
   67 #define redis_kb(__kb) ((struct kb_redis *) (__kb))
   68 
   69 static int
   70 redis_delete_all (struct kb_redis *);
   71 static int redis_lnk_reset (kb_t);
   72 static int
   73 redis_flush_all (kb_t, const char *);
   74 static redisReply *
   75 redis_cmd (struct kb_redis *kbr, const char *fmt, ...);
   76 
   77 /**
   78  * @brief Attempt to atomically acquire ownership of a database.
   79  *
   80  * @return 0 on success, negative integer otherwise.
   81  */
   82 static int
   83 try_database_index (struct kb_redis *kbr, int index)
   84 {
   85   redisContext *ctx = kbr->rctx;
   86   redisReply *rep;
   87   int rc = 0;
   88 
   89   rep = redisCommand (ctx, "HSETNX %s %d 1", GLOBAL_DBINDEX_NAME, index);
   90   if (rep == NULL)
   91     return -ENOMEM;
   92 
   93   if (rep->type != REDIS_REPLY_INTEGER)
   94     rc = -EPROTO;
   95   else if (rep->integer == 0)
   96     rc = -EALREADY;
   97   else
   98     kbr->db = index;
   99 
  100   freeReplyObject (rep);
  101 
  102   return rc;
  103 }
  104 
  105 /**
  106  * @brief Set the number of databases have been configured
  107  *        into kbr struct.
  108  *
  109  * @param[in] kbr Subclass of struct kb where to save the max db index founded.
  110  *
  111  * @return 0 on success, -1 on error.
  112  */
  113 static int
  114 fetch_max_db_index (struct kb_redis *kbr)
  115 {
  116   int rc = 0;
  117   redisContext *ctx = kbr->rctx;
  118   redisReply *rep = NULL;
  119 
  120   rep = redisCommand (ctx, "CONFIG GET databases");
  121   if (rep == NULL)
  122     {
  123       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  124              "%s: redis command failed with '%s'", __func__, ctx->errstr);
  125       rc = -1;
  126       goto err_cleanup;
  127     }
  128 
  129   if (rep->type != REDIS_REPLY_ARRAY)
  130     {
  131       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  132              "%s: cannot retrieve max DB number: %s", __func__, rep->str);
  133       rc = -1;
  134       goto err_cleanup;
  135     }
  136 
  137   if (rep->elements == 2)
  138     {
  139       kbr->max_db = (unsigned) atoi (rep->element[1]->str);
  140     }
  141   else
  142     {
  143       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  144              "%s: unexpected reply length (%zd)", __func__, rep->elements);
  145       rc = -1;
  146       goto err_cleanup;
  147     }
  148 
  149   g_debug ("%s: maximum DB number: %u", __func__, kbr->max_db);
  150 
  151 err_cleanup:
  152   if (rep != NULL)
  153     freeReplyObject (rep);
  154 
  155   return rc;
  156 }
  157 
  158 /**
  159  * @brief Select DB.
  160  *
  161  * WARNING: do not call redis_cmd in here, since our context is not fully
  162  * acquired yet!
  163  *
  164  * @param[in] kbr Subclass of struct kb where to save the db index.
  165  *
  166  * @return 0 on success, -1 on error.
  167  */
  168 static int
  169 select_database (struct kb_redis *kbr)
  170 {
  171   int rc;
  172   redisContext *ctx = kbr->rctx;
  173   redisReply *rep = NULL;
  174 
  175   if (kbr->db == 0)
  176     {
  177       unsigned i;
  178 
  179       if (kbr->max_db == 0)
  180         fetch_max_db_index (kbr);
  181 
  182       for (i = 1; i < kbr->max_db; i++)
  183         {
  184           rc = try_database_index (kbr, i);
  185           if (rc == 0)
  186             break;
  187         }
  188     }
  189 
  190   /* No DB available, give up. */
  191   if (kbr->db == 0)
  192     {
  193       rc = -1;
  194       goto err_cleanup;
  195     }
  196 
  197   rep = redisCommand (ctx, "SELECT %u", kbr->db);
  198   if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
  199     {
  200       rc = -1;
  201       goto err_cleanup;
  202     }
  203 
  204   rc = 0;
  205 
  206 err_cleanup:
  207   if (rep != NULL)
  208     freeReplyObject (rep);
  209 
  210   return rc;
  211 }
  212 
  213 /**
  214  * @brief Release DB.
  215  *
  216  * @param[in] kbr Subclass of struct kb.
  217  *
  218  * @return 0 on success, -1 on error.
  219  */
  220 static int
  221 redis_release_db (struct kb_redis *kbr)
  222 {
  223   int rc;
  224   redisContext *ctx = kbr->rctx;
  225   redisReply *rep;
  226 
  227   if (ctx == NULL)
  228     return -EINVAL;
  229 
  230   rep = redisCommand (ctx, "SELECT 0"); /* Management database*/
  231   if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
  232     {
  233       rc = -1;
  234       goto err_cleanup;
  235     }
  236   freeReplyObject (rep);
  237 
  238   rep = redisCommand (ctx, "HDEL %s %d", GLOBAL_DBINDEX_NAME, kbr->db);
  239   if (rep == NULL || rep->type != REDIS_REPLY_INTEGER)
  240     {
  241       rc = -1;
  242       goto err_cleanup;
  243     }
  244 
  245   rc = 0;
  246 
  247 err_cleanup:
  248   if (rep != NULL)
  249     freeReplyObject (rep);
  250 
  251   return rc;
  252 }
  253 
  254 /**
  255  * @brief Get redis context if it is already connected or do a
  256  *        a connection.
  257  *
  258  * @param[in] kbr Subclass of struct kb where to fetch the context.
  259  *                or where it is saved in case of a new connection.
  260  *
  261  * @return 0 on success, -1 on connection error, -2 on unavailable DB slot.
  262  */
  263 static int
  264 get_redis_ctx (struct kb_redis *kbr)
  265 {
  266   int rc;
  267 
  268   if (kbr->rctx != NULL)
  269     return 0;
  270 
  271   kbr->rctx = redisConnectUnix (kbr->path);
  272   if (kbr->rctx == NULL || kbr->rctx->err)
  273     {
  274       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  275              "%s: redis connection error to %s: %s", __func__, kbr->path,
  276              kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
  277       redisFree (kbr->rctx);
  278       kbr->rctx = NULL;
  279       return -1;
  280     }
  281 
  282   rc = select_database (kbr);
  283   if (rc)
  284     {
  285       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, "No redis DB available");
  286       redisFree (kbr->rctx);
  287       kbr->rctx = NULL;
  288       return -2;
  289     }
  290 
  291   g_debug ("%s: connected to redis://%s/%d", __func__, kbr->path, kbr->db);
  292   return 0;
  293 }
  294 
  295 /**
  296  * @brief Test redis connection.
  297  *
  298  * @param[in] kbr Subclass of struct kb to test.
  299  *
  300  * @return 0 on success, negative integer on error.
  301  */
  302 static int
  303 redis_test_connection (struct kb_redis *kbr)
  304 {
  305   int rc = 0;
  306   redisReply *rep;
  307 
  308   rep = redis_cmd (kbr, "PING");
  309   if (rep == NULL)
  310     {
  311       /* not 100% relevant but hiredis doesn't provide us with proper error
  312        * codes. */
  313       rc = -ECONNREFUSED;
  314       goto out;
  315     }
  316 
  317   if (rep->type != REDIS_REPLY_STATUS)
  318     {
  319       rc = -EINVAL;
  320       goto out;
  321     }
  322 
  323   if (g_ascii_strcasecmp (rep->str, "PONG"))
  324     {
  325       rc = -EPROTO;
  326       goto out;
  327     }
  328 
  329 out:
  330   if (rep != NULL)
  331     freeReplyObject (rep);
  332 
  333   return rc;
  334 }
  335 
  336 /**
  337  * @brief Delete all entries and release ownership on the namespace.
  338  *
  339  * @param[in] kb KB handle to release.
  340  *
  341  * @return 0 on success, non-null on error.
  342  */
  343 static int
  344 redis_delete (kb_t kb)
  345 {
  346   struct kb_redis *kbr;
  347 
  348   kbr = redis_kb (kb);
  349 
  350   redis_delete_all (kbr);
  351   redis_release_db (kbr);
  352 
  353   if (kbr->rctx != NULL)
  354     {
  355       redisFree (kbr->rctx);
  356       kbr->rctx = NULL;
  357     }
  358 
  359   g_free (kb);
  360   return 0;
  361 }
  362 
  363 /**
  364  * @brief Return the kb index
  365  *
  366  * @param[in] kb KB handle.
  367  *
  368  * @return kb_index on success, null on error.
  369  */
  370 static int
  371 redis_get_kb_index (kb_t kb)
  372 {
  373   int i;
  374   i = ((struct kb_redis *) kb)->db;
  375   if (i > 0)
  376     return i;
  377   return -1;
  378 }
  379 
  380 /**
  381  * @brief Initialize a new Knowledge Base object.
  382  *
  383  * @param[in] kb  Reference to a kb_t to initialize.
  384  * @param[in] kb_path   Path to KB.
  385  *
  386  * @return 0 on success, -1 on connection error, -2 when no DB is available.
  387  */
  388 static int
  389 redis_new (kb_t *kb, const char *kb_path)
  390 {
  391   struct kb_redis *kbr;
  392   int rc = 0;
  393 
  394   kbr = g_malloc0 (sizeof (struct kb_redis) + strlen (kb_path) + 1);
  395   kbr->kb.kb_ops = &KBRedisOperations;
  396   strncpy (kbr->path, kb_path, strlen (kb_path));
  397 
  398   if ((rc = get_redis_ctx (kbr)) < 0)
  399     return rc;
  400   if (redis_test_connection (kbr))
  401     {
  402       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  403              "%s: cannot access redis at '%s'", __func__, kb_path);
  404       redis_delete ((kb_t) kbr);
  405       kbr = NULL;
  406       rc = -1;
  407     }
  408 
  409   *kb = (kb_t) kbr;
  410   return rc;
  411 }
  412 
  413 /**
  414  * @brief Connect to a Knowledge Base object with the given kb_index.
  415  *
  416  * @param[in] kb_path   Path to KB.
  417  * @param[in] kb_index       DB index
  418  *
  419  * @return Knowledge Base object, NULL otherwise.
  420  */
  421 static kb_t
  422 redis_direct_conn (const char *kb_path, const int kb_index)
  423 {
  424   struct kb_redis *kbr;
  425   redisReply *rep;
  426 
  427   kbr = g_malloc0 (sizeof (struct kb_redis) + strlen (kb_path) + 1);
  428   kbr->kb.kb_ops = &KBRedisOperations;
  429   strncpy (kbr->path, kb_path, strlen (kb_path));
  430 
  431   kbr->rctx = redisConnectUnix (kbr->path);
  432   if (kbr->rctx == NULL || kbr->rctx->err)
  433     {
  434       g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  435              "%s: redis connection error to %s: %s", __func__, kbr->path,
  436              kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
  437       redisFree (kbr->rctx);
  438       g_free (kbr);
  439       return NULL;
  440     }
  441   kbr->db = kb_index;
  442   rep = redisCommand (kbr->rctx, "SELECT %d", kb_index);
  443   if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
  444     {
  445       if (rep != NULL)
  446         freeReplyObject (rep);
  447       redisFree (kbr->rctx);
  448       kbr->rctx = NULL;
  449       return NULL;
  450     }
  451   freeReplyObject (rep);
  452   return (kb_t) kbr;
  453 }
  454 
  455 /**
  456  * @brief Find an existing Knowledge Base object with key.
  457  *
  458  * @param[in] kb_path   Path to KB.
  459  * @param[in] key       Marker key to search for in KB objects.
  460  *
  461  * @return Knowledge Base object, NULL otherwise.
  462  */
  463 static kb_t
  464 redis_find (const char *kb_path, const char *key)
  465 {
  466   struct kb_redis *kbr;
  467   unsigned int i = 1;
  468 
  469   kbr = g_malloc0 (sizeof (struct kb_redis) + strlen (kb_path) + 1);
  470   kbr->kb.kb_ops = &KBRedisOperations;
  471   strncpy (kbr->path, kb_path, strlen (kb_path));
  472 
  473   do
  474     {
  475       redisReply *rep;
  476 
  477       kbr->rctx = redisConnectUnix (kbr->path);
  478       if (kbr->rctx == NULL || kbr->rctx->err)
  479         {
  480           g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
  481                  "%s: redis connection error to %s: %s", __func__, kbr->path,
  482                  kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
  483           redisFree (kbr->rctx);
  484           g_free (kbr);
  485           return NULL;
  486         }
  487 
  488       if (kbr->max_db == 0)
  489         fetch_max_db_index (kbr);
  490 
  491       kbr->db = i;
  492       rep = redisCommand (kbr->rctx, "HEXISTS %s %d", GLOBAL_DBINDEX_NAME, i);
  493       if (rep == NULL || rep->type != REDIS_REPLY_INTEGER || rep->integer != 1)
  494         {
  495           if (rep != NULL)
  496             freeReplyObject (rep);
  497           i++;
  498           redisFree (kbr->rctx);
  499           kbr->rctx = NULL;
  500           continue;
  501         }
  502       freeReplyObject (rep);
  503       rep = redisCommand (kbr->rctx, "SELECT %u", i);
  504       if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
  505         {
  506           redisFree (kbr->rctx);
  507           kbr->rctx = NULL;
  508         }
  509       else
  510         {
  511           freeReplyObject (rep);
  512           if (key)
  513             {
  514               char *tmp = kb_item_get_str (&kbr->kb, key);
  515               if (tmp)
  516                 {
  517                   g_free (tmp);
  518                   return (kb_t) kbr;
  519                 }
  520             }
  521           redisFree (kbr->rctx);
  522         }
  523       i++;
  524     }
  525   while (i < kbr->max_db);
  526 
  527   g_free (kbr);
  528   return NULL;
  529 }
  530 
  531 /**
  532  * @brief Release a KB item (or a list).
  533  *
  534  * @param[in] item Item or list to be release
  535  */
  536 void
  537 kb_item_free (struct kb_item *item)
  538 {
  539   while (item != NULL)
  540     {
  541       struct kb_item *next;
  542 
  543       next = item->next;
  544       if (item->type == KB_TYPE_STR && item->v_str != NULL)
  545         g_free (item->v_str);
  546       g_free (item);
  547       item = next;
  548     }
  549 }
  550 
  551 /**
  552  * @brief Give a single KB item.
  553  *
  554  * @param[in] name Name of the item.
  555  * @param[in] elt A redisReply element where to fetch the item.
  556  * @param[in] force_int To force string to integer conversion.
  557  *
  558  * @return Single retrieve kb_item on success, NULL otherwise.
  559  */
  560 static struct kb_item *
  561 redis2kbitem_single (const char *name, const redisReply *elt, int force_int)
  562 {
  563   struct kb_item *item;
  564   size_t namelen;
  565 
  566   if (elt->type != REDIS_REPLY_STRING && elt->type != REDIS_REPLY_INTEGER)
  567     return NULL;
  568 
  569   namelen = strlen (name) + 1;
  570 
  571   item = g_malloc0 (sizeof (struct kb_item) + namelen);
  572   if (elt->type == REDIS_REPLY_INTEGER)
  573     {
  574       item->type = KB_TYPE_INT;
  575       item->v_int = elt->integer;
  576     }
  577   else if (force_int)
  578     {
  579       item->type = KB_TYPE_INT;
  580       item->v_int = atoi (elt->str);
  581     }
  582   else
  583     {
  584       item->type = KB_TYPE_STR;
  585       item->v_str = g_memdup (elt->str, elt->len + 1);
  586       item->len = elt->len;
  587     }
  588 
  589   item->next = NULL;
  590   item->namelen = namelen;
  591   strncpy (item->name, name, namelen);
  592 
  593   return item;
  594 }
  595 
  596 /**
  597  * @brief Fetch a KB item or list from a redis Reply.
  598  *
  599  * @param[in] name Name of the item.
  600  * @param[in] rep A redisReply element where to fetch the item.
  601  *
  602  * @return kb_item or list on success, NULL otherwise.
  603  */
  604 static struct kb_item *
  605 redis2kbitem (const char *name, const redisReply *rep)
  606 {
  607   struct kb_item *kbi;
  608 
  609   kbi = NULL;
  610 
  611   switch (rep->type)
  612     {
  613       unsigned int i;
  614 
  615     case REDIS_REPLY_STRING:
  616     case REDIS_REPLY_INTEGER:
  617       kbi = redis2kbitem_single (name, rep, 0);
  618       break;
  619 
  620     case REDIS_REPLY_ARRAY:
  621       for (i = 0; i < rep->elements; i++)
  622         {
  623           struct kb_item *tmpitem;
  624 
  625           tmpitem = redis2kbitem_single (name, rep->element[i], 0);
  626           if (tmpitem == NULL)
  627             break;
  628 
  629           if (kbi != NULL)
  630             {
  631               tmpitem->next = kbi;
  632               kbi = tmpitem;
  633             }
  634           else
  635             kbi = tmpitem;
  636         }
  637       break;
  638 
  639     case REDIS_REPLY_NIL:
  640     case REDIS_REPLY_STATUS:
  641     case REDIS_REPLY_ERROR:
  642     default:
  643       break;
  644     }
  645 
  646   return kbi;
  647 }
  648 
  649 /**
  650  * @brief Execute a redis command and get a redis reply.
  651  *
  652  * @param[in] kbr Subclass of struct kb to connect to.
  653  * @param[in] fmt Formatted variable argument list with the cmd to be executed.
  654  *
  655  * @return Redis reply on success, NULL otherwise.
  656  */
  657 static redisReply *
  658 redis_cmd (struct kb_redis *kbr, const char *fmt, ...)
  659 {
  660   redisReply *rep;
  661   va_list ap, aq;
  662   int retry = 0;
  663 
  664   va_start (ap, fmt);
  665   do
  666     {
  667       if (get_redis_ctx (kbr) < 0)
  668         {
  669           va_end (ap);
  670           return NULL;
  671         }
  672 
  673       va_copy (aq, ap);
  674       rep = redisvCommand (kbr->rctx, fmt, aq);
  675       va_end (aq);
  676 
  677       if (kbr->rctx->err)
  678         {
  679           if (rep != NULL)
  680             freeReplyObject (rep);
  681 
  682           redis_lnk_reset ((kb_t) kbr);
  683           retry = !retry;
  684         }
  685       else
  686         retry = 0;
  687     }
  688   while (retry);
  689 
  690   va_end (ap);
  691 
  692   return rep;
  693 }
  694 
  695 /**
  696  * @brief Get a single KB element.
  697  *
  698  * @param[in] kb KB handle where to fetch the item.
  699  * @param[in] name  Name of the element to retrieve.
  700  * @param[in] type Desired element type.
  701  *
  702  * @return A struct kb_item to be freed with kb_item_free() or NULL if no
  703  *         element was found or on error.
  704  */
  705 static struct kb_item *
  706 redis_get_single (kb_t kb, const char *name, enum kb_item_type type)
  707 {
  708   struct kb_item *kbi;
  709   struct kb_redis *kbr;
  710   redisReply *rep;
  711 
  712   kbr = redis_kb (kb);
  713   kbi = NULL;
  714 
  715   rep = redis_cmd (kbr, "LINDEX %s -1", name);
  716   if (rep == NULL || rep->type != REDIS_REPLY_STRING)
  717     {
  718       kbi = NULL;
  719       goto out;
  720     }
  721 
  722   kbi = redis2kbitem_single (name, rep, type == KB_TYPE_INT);
  723 
  724 out:
  725   if (rep != NULL)
  726     freeReplyObject (rep);
  727 
  728   return kbi;
  729 }
  730 
  731 /**
  732  * @brief Get a single KB string item.
  733  *
  734  * @param[in] kb  KB handle where to fetch the item.
  735  * @param[in] name  Name of the element to retrieve.
  736  *
  737  * @return A struct kb_item to be freed with kb_item_free() or NULL if no
  738  *         element was found or on error.
  739  */
  740 static char *
  741 redis_get_str (kb_t kb, const char *name)
  742 {
  743   struct kb_item *kbi;
  744 
  745   kbi = redis_get_single (kb, name, KB_TYPE_STR);
  746   if (kbi != NULL)
  747     {
  748       char *res;
  749 
  750       res = kbi->v_str;
  751       kbi->v_str = NULL;
  752       kb_item_free (kbi);
  753       return res;
  754     }
  755   return NULL;
  756 }
  757 
  758 /**
  759  * @brief Push a new entry under a given key.
  760  *
  761  * @param[in] kb  KB handle where to store the item.
  762  * @param[in] name  Key to push to.
  763  * @param[in] value Value to push.
  764  *
  765  * @return 0 on success, non-null on error.
  766  */
  767 static int
  768 redis_push_str (kb_t kb, const char *name, const char *value)
  769 {
  770   struct kb_redis *kbr;
  771   redisReply *rep = NULL;
  772   int rc = 0;
  773 
  774   kbr = redis_kb (kb);
  775   rep = redis_cmd (kbr, "LPUSH %s %s", name, value);
  776   if (!rep || rep->type == REDIS_REPLY_ERROR)
  777     rc = -1;
  778 
  779   if (rep)
  780     freeReplyObject (rep);
  781 
  782   return rc;
  783 }
  784 
  785 /**
  786  * @brief Pops a single KB string item.
  787  *
  788  * @param[in] kb  KB handle where to fetch the item.
  789  * @param[in] name  Name of the key from where to retrieve.
  790  *
  791  * @return A string to be freed or NULL if list is empty or on error.
  792  */
  793 static char *
  794 redis_pop_str (kb_t kb, const char *name)
  795 {
  796   struct kb_redis *kbr;
  797   redisReply *rep;
  798   char *value = NULL;
  799 
  800   kbr = redis_kb (kb);
  801   rep = redis_cmd (kbr, "RPOP %s", name);
  802   if (!rep)
  803     return NULL;
  804 
  805   if (rep->type == REDIS_REPLY_STRING)
  806     value = g_strdup (rep->str);
  807   freeReplyObject (rep);
  808 
  809   return value;
  810 }
  811 
  812 /**
  813  * @brief Get a single KB integer item.
  814  *
  815  * @param[in] kb  KB handle where to fetch the item.
  816  * @param[in] name  Name of the element to retrieve.
  817  *
  818  * @return A struct kb_item to be freed with kb_item_free() or NULL if no
  819  *         element was found or on error.
  820  */
  821 static int
  822 redis_get_int (kb_t kb, const char *name)
  823 {
  824   struct kb_item *kbi;
  825 
  826   kbi = redis_get_single (kb, name, KB_TYPE_INT);
  827   if (kbi != NULL)
  828     {
  829       int res;
  830 
  831       res = kbi->v_int;
  832       kb_item_free (kbi);
  833       return res;
  834     }
  835   return -1;
  836 }
  837 
  838 /**
  839  * @brief Get field of a NVT.
  840  *
  841  * @param[in] kb        KB handle where to store the nvt.
  842  * @param[in] oid       OID of NVT to get from.
  843  * @param[in] position  Position of field to get.
  844  *
  845  * @return Value of field, NULL otherwise.
  846  */
  847 static char *
  848 redis_get_nvt (kb_t kb, const char *oid, enum kb_nvt_pos position)
  849 {
  850   struct kb_redis *kbr;
  851   redisReply *rep;
  852   char *res = NULL;
  853 
  854   kbr = redis_kb (kb);
  855   if (position >= NVT_TIMESTAMP_POS)
  856     rep = redis_cmd (kbr, "LINDEX filename:%s %d", oid,
  857                      position - NVT_TIMESTAMP_POS);
  858   else
  859     rep = redis_cmd (kbr, "LINDEX nvt:%s %d", oid, position);
  860   if (!rep)
  861     return NULL;
  862   if (rep->type == REDIS_REPLY_INTEGER)
  863     res = g_strdup_printf ("%lld", rep->integer);
  864   else if (rep->type == REDIS_REPLY_STRING)
  865     res = g_strdup (rep->str);
  866   freeReplyObject (rep);
  867 
  868   return res;
  869 }
  870 
  871 /**
  872  * @brief Get a full NVT.
  873  *
  874  * @param[in] kb        KB handle where to store the nvt.
  875  * @param[in] oid       OID of NVT to get.
  876  *
  877  * @return nvti_t of NVT, NULL otherwise.
  878  */
  879 static nvti_t *
  880 redis_get_nvt_all (kb_t kb, const char *oid)
  881 {
  882   struct kb_redis *kbr;
  883   redisReply *rep;
  884 
  885   kbr = redis_kb (kb);
  886   rep =
  887     redis_cmd (kbr, "LRANGE nvt:%s %d %d", oid, NVT_FILENAME_POS, NVT_NAME_POS);
  888   if (!rep)
  889     return NULL;
  890   if (rep->type != REDIS_REPLY_ARRAY || rep->elements != NVT_NAME_POS + 1)
  891     {
  892       freeReplyObject (rep);
  893       return NULL;
  894     }
  895   else
  896     {
  897       nvti_t *nvti = nvti_new ();
  898 
  899       nvti_set_oid (nvti, oid);
  900       nvti_set_required_keys (nvti, rep->element[NVT_REQUIRED_KEYS_POS]->str);
  901       nvti_set_mandatory_keys (nvti, rep->element[NVT_MANDATORY_KEYS_POS]->str);
  902       nvti_set_excluded_keys (nvti, rep->element[NVT_EXCLUDED_KEYS_POS]->str);
  903       nvti_set_required_udp_ports (
  904         nvti, rep->element[NVT_REQUIRED_UDP_PORTS_POS]->str);
  905       nvti_set_required_ports (nvti, rep->element[NVT_REQUIRED_PORTS_POS]->str);
  906       nvti_set_dependencies (nvti, rep->element[NVT_DEPENDENCIES_POS]->str);
  907       nvti_set_tag (nvti, rep->element[NVT_TAGS_POS]->str);
  908       nvti_add_refs (nvti, "cve", rep->element[NVT_CVES_POS]->str, "");
  909       nvti_add_refs (nvti, "bid", rep->element[NVT_BIDS_POS]->str, "");
  910       nvti_add_refs (nvti, NULL, rep->element[NVT_XREFS_POS]->str, "");
  911       nvti_set_category (nvti, atoi (rep->element[NVT_CATEGORY_POS]->str));
  912       nvti_set_timeout (nvti, atoi (rep->element[NVT_TIMEOUT_POS]->str));
  913       nvti_set_family (nvti, rep->element[NVT_FAMILY_POS]->str);
  914       nvti_set_name (nvti, rep->element[NVT_NAME_POS]->str);
  915 
  916       freeReplyObject (rep);
  917       return nvti;
  918     }
  919 }
  920 
  921 /**
  922  * @brief Get all items stored under a given name.
  923  *
  924  * @param[in] kb  KB handle where to fetch the items.
  925  * @param[in] name  Name of the elements to retrieve.
  926  *
  927  * @return Linked struct kb_item instances to be freed with kb_item_free() or
  928  *         NULL if no element was found or on error.
  929  */
  930 static struct kb_item *
  931 redis_get_all (kb_t kb, const char *name)
  932 {
  933   struct kb_redis *kbr;
  934   struct kb_item *kbi;
  935   redisReply *rep;
  936 
  937   kbr = redis_kb (kb);
  938 
  939   rep = redis_cmd (kbr, "LRANGE %s 0 -1", name);
  940   if (rep == NULL)
  941     return NULL;
  942 
  943   kbi = redis2kbitem (name, rep);
  944 
  945   freeReplyObject (rep);
  946 
  947   return kbi;
  948 }
  949 
  950 /**
  951  * @brief Get all items stored under a given pattern.
  952  *
  953  * @param[in] kb  KB handle where to fetch the items.
  954  * @param[in] pattern  '*' pattern of the elements to retrieve.
  955  *
  956  * @return Linked struct kb_item instances to be freed with kb_item_free() or
  957  *         NULL if no element was found or on error.
  958  */
  959 static struct kb_item *
  960 redis_get_pattern (kb_t kb, const char *pattern)
  961 {
  962   struct kb_redis *kbr;
  963   struct kb_item *kbi = NULL;
  964   redisReply *rep;
  965   unsigned int i;
  966 
  967   kbr = redis_kb (kb);
  968   rep = redis_cmd (kbr, "KEYS %s", pattern);
  969   if (!rep)
  970     return NULL;
  971   if (rep->type != REDIS_REPLY_ARRAY)
  972     {
  973       freeReplyObject (rep);
  974       return NULL;
  975     }
  976 
  977   if (get_redis_ctx (kbr) < 0)
  978     return NULL;
  979   for (i = 0; i < rep->elements; i++)
  980     redisAppendCommand (kbr->rctx, "LRANGE %s 0 -1", rep->element[i]->str);
  981 
  982   for (i = 0; i < rep->elements; i++)
  983     {
  984       struct kb_item *tmp;
  985       redisReply *rep_range;
  986 
  987       redisGetReply (kbr->rctx, (void **) &rep_range);
  988       if (!rep)
  989         continue;
  990       tmp = redis2kbitem (rep->element[i]->str, rep_range);
  991       if (!tmp)
  992         {
  993           freeReplyObject (rep_range);
  994           continue;
  995         }
  996 
  997       if (kbi)
  998         {
  999           struct kb_item *tmp2;
 1000 
 1001           tmp2 = tmp;
 1002           while (tmp->next)
 1003             tmp = tmp->next;
 1004           tmp->next = kbi;
 1005           kbi = tmp2;
 1006         }
 1007       else
 1008         kbi = tmp;
 1009       freeReplyObject (rep_range);
 1010     }
 1011 
 1012   freeReplyObject (rep);
 1013   return kbi;
 1014 }
 1015 
 1016 /**
 1017  * @brief Get all NVT OIDs.
 1018  *
 1019  * @param[in] kb  KB handle where to fetch the items.
 1020  *
 1021  * @return Linked list of all OIDs or NULL.
 1022  */
 1023 static GSList *
 1024 redis_get_oids (kb_t kb)
 1025 {
 1026   struct kb_redis *kbr;
 1027   redisReply *rep;
 1028   GSList *list = NULL;
 1029   size_t i;
 1030 
 1031   kbr = redis_kb (kb);
 1032   rep = redis_cmd (kbr, "KEYS nvt:*");
 1033   if (!rep)
 1034     return NULL;
 1035 
 1036   if (rep->type != REDIS_REPLY_ARRAY)
 1037     {
 1038       freeReplyObject (rep);
 1039       return NULL;
 1040     }
 1041 
 1042   /* Fetch OID values from key names nvt:OID. */
 1043   for (i = 0; i < rep->elements; i++)
 1044     list = g_slist_prepend (list, g_strdup (rep->element[i]->str + 4));
 1045   freeReplyObject (rep);
 1046 
 1047   return list;
 1048 }
 1049 
 1050 /**
 1051  * @brief Count all items stored under a given pattern.
 1052  *
 1053  * @param[in] kb  KB handle where to count the items.
 1054  * @param[in] pattern  '*' pattern of the elements to count.
 1055  *
 1056  * @return Count of items.
 1057  */
 1058 static size_t
 1059 redis_count (kb_t kb, const char *pattern)
 1060 {
 1061   struct kb_redis *kbr;
 1062   redisReply *rep;
 1063   size_t count;
 1064 
 1065   kbr = redis_kb (kb);
 1066 
 1067   rep = redis_cmd (kbr, "KEYS %s", pattern);
 1068   if (rep == NULL)
 1069     return 0;
 1070 
 1071   if (rep->type != REDIS_REPLY_ARRAY)
 1072     {
 1073       freeReplyObject (rep);
 1074       return 0;
 1075     }
 1076 
 1077   count = rep->elements;
 1078   freeReplyObject (rep);
 1079   return count;
 1080 }
 1081 
 1082 /**
 1083  * @brief Delete all entries under a given name.
 1084  *
 1085  * @param[in] kb  KB handle where to store the item.
 1086  * @param[in] name  Item name.
 1087  *
 1088  * @return 0 on success, non-null on error.
 1089  */
 1090 static int
 1091 redis_del_items (kb_t kb, const char *name)
 1092 {
 1093   struct kb_redis *kbr;
 1094   redisReply *rep;
 1095   int rc = 0;
 1096 
 1097   kbr = redis_kb (kb);
 1098 
 1099   rep = redis_cmd (kbr, "DEL %s", name);
 1100   if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
 1101     rc = -1;
 1102 
 1103   if (rep != NULL)
 1104     freeReplyObject (rep);
 1105 
 1106   return rc;
 1107 }
 1108 
 1109 /**
 1110  * @brief Insert (append) a new unique entry under a given name.
 1111  *
 1112  * @param[in] kb  KB handle where to store the item.
 1113  * @param[in] name  Item name.
 1114  * @param[in] str  Item value.
 1115  * @param[in] len  Value length. Used for blobs.
 1116  *
 1117  * @return 0 on success, non-null on error.
 1118  */
 1119 static int
 1120 redis_add_str_unique (kb_t kb, const char *name, const char *str, size_t len)
 1121 {
 1122   struct kb_redis *kbr;
 1123   redisReply *rep = NULL;
 1124   int rc = 0;
 1125   redisContext *ctx;
 1126 
 1127   kbr = redis_kb (kb);
 1128   if (get_redis_ctx (kbr) < 0)
 1129     return -1;
 1130   ctx = kbr->rctx;
 1131 
 1132   /* Some VTs still rely on values being unique (ie. a value inserted multiple
 1133    * times, will only be present once.)
 1134    * Once these are fixed, the LREM becomes redundant and should be removed.
 1135    */
 1136   if (len == 0)
 1137     {
 1138       redisAppendCommand (ctx, "LREM %s 1 %s", name, str);
 1139       redisAppendCommand (ctx, "RPUSH %s %s", name, str);
 1140       redisGetReply (ctx, (void **) &rep);
 1141       if (rep && rep->type == REDIS_REPLY_INTEGER && rep->integer == 1)
 1142         g_debug ("Key '%s' already contained value '%s'", name, str);
 1143       freeReplyObject (rep);
 1144       redisGetReply (ctx, (void **) &rep);
 1145     }
 1146   else
 1147     {
 1148       redisAppendCommand (ctx, "LREM %s 1 %b", name, str, len);
 1149       redisAppendCommand (ctx, "RPUSH %s %b", name, str, len);
 1150       redisGetReply (ctx, (void **) &rep);
 1151       if (rep && rep->type == REDIS_REPLY_INTEGER && rep->integer == 1)
 1152         g_debug ("Key '%s' already contained string '%s'", name, str);
 1153       freeReplyObject (rep);
 1154       redisGetReply (ctx, (void **) &rep);
 1155     }
 1156   if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
 1157     rc = -1;
 1158 
 1159   if (rep != NULL)
 1160     freeReplyObject (rep);
 1161 
 1162   return rc;
 1163 }
 1164 
 1165 /**
 1166  * @brief Insert (append) a new entry under a given name.
 1167  *
 1168  * @param[in] kb  KB handle where to store the item.
 1169  * @param[in] name  Item name.
 1170  * @param[in] str  Item value.
 1171  * @param[in] len  Value length. Used for blobs.
 1172  *
 1173  * @return 0 on success, non-null on error.
 1174  */
 1175 static int
 1176 redis_add_str (kb_t kb, const char *name, const char *str, size_t len)
 1177 {
 1178   struct kb_redis *kbr;
 1179   redisReply *rep;
 1180   int rc = 0;
 1181 
 1182   kbr = redis_kb (kb);
 1183   if (len == 0)
 1184     rep = redis_cmd (kbr, "RPUSH %s %s", name, str);
 1185   else
 1186     rep = redis_cmd (kbr, "RPUSH %s %b", name, str, len);
 1187   if (!rep || rep->type == REDIS_REPLY_ERROR)
 1188     rc = -1;
 1189 
 1190   if (rep)
 1191     freeReplyObject (rep);
 1192   return rc;
 1193 }
 1194 
 1195 /**
 1196  * @brief Set (replace) a new entry under a given name.
 1197  *
 1198  * @param[in] kb  KB handle where to store the item.
 1199  * @param[in] name  Item name.
 1200  * @param[in] val  Item value.
 1201  * @param[in] len  Value length. Used for blobs.
 1202  *
 1203  * @return 0 on success, non-null on error.
 1204  */
 1205 static int
 1206 redis_set_str (kb_t kb, const char *name, const char *val, size_t len)
 1207 {
 1208   struct kb_redis *kbr;
 1209   redisReply *rep = NULL;
 1210   redisContext *ctx;
 1211   int rc = 0, i = 4;
 1212 
 1213   kbr = redis_kb (kb);
 1214   if (get_redis_ctx (kbr) < 0)
 1215     return -1;
 1216   ctx = kbr->rctx;
 1217   redisAppendCommand (ctx, "MULTI");
 1218   redisAppendCommand (ctx, "DEL %s", name);
 1219   if (len == 0)
 1220     redisAppendCommand (ctx, "RPUSH %s %s", name, val);
 1221   else
 1222     redisAppendCommand (ctx, "RPUSH %s %b", name, val, len);
 1223   redisAppendCommand (ctx, "EXEC");
 1224   while (i--)
 1225     {
 1226       redisGetReply (ctx, (void **) &rep);
 1227       if (!rep || rep->type == REDIS_REPLY_ERROR)
 1228         rc = -1;
 1229       if (rep)
 1230         freeReplyObject (rep);
 1231     }
 1232 
 1233   return rc;
 1234 }
 1235 
 1236 /**
 1237  * @brief Insert (append) a new unique entry under a given name.
 1238  *
 1239  * @param[in] kb  KB handle where to store the item.
 1240  * @param[in] name  Item name.
 1241  * @param[in] val  Item value.
 1242  *
 1243  * @return 0 on success, non-null on error.
 1244  */
 1245 static int
 1246 redis_add_int_unique (kb_t kb, const char *name, int val)
 1247 {
 1248   struct kb_redis *kbr;
 1249   redisReply *rep;
 1250   int rc = 0;
 1251   redisContext *ctx;
 1252 
 1253   kbr = redis_kb (kb);
 1254   if (get_redis_ctx (kbr) < 0)
 1255     return -1;
 1256   ctx = kbr->rctx;
 1257   redisAppendCommand (ctx, "LREM %s 1 %d", name, val);
 1258   redisAppendCommand (ctx, "RPUSH %s %d", name, val);
 1259   redisGetReply (ctx, (void **) &rep);
 1260   if (rep && rep->type == REDIS_REPLY_INTEGER && rep->integer == 1)
 1261     g_debug ("Key '%s' already contained integer '%d'", name, val);
 1262   freeReplyObject (rep);
 1263   redisGetReply (ctx, (void **) &rep);
 1264   if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
 1265     {
 1266       rc = -1;
 1267       goto out;
 1268     }
 1269 
 1270 out:
 1271   if (rep != NULL)
 1272     freeReplyObject (rep);
 1273 
 1274   return rc;
 1275 }
 1276 
 1277 /**
 1278  * @brief Insert (append) a new entry under a given name.
 1279  *
 1280  * @param[in] kb  KB handle where to store the item.
 1281  * @param[in] name  Item name.
 1282  * @param[in] val  Item value.
 1283  *
 1284  * @return 0 on success, non-null on error.
 1285  */
 1286 static int
 1287 redis_add_int (kb_t kb, const char *name, int val)
 1288 {
 1289   redisReply *rep;
 1290   int rc = 0;
 1291 
 1292   rep = redis_cmd (redis_kb (kb), "RPUSH %s %d", name, val);
 1293   if (!rep || rep->type == REDIS_REPLY_ERROR)
 1294     rc = -1;
 1295   if (rep)
 1296     freeReplyObject (rep);
 1297 
 1298   return rc;
 1299 }
 1300 
 1301 /**
 1302  * @brief Set (replace) a new entry under a given name.
 1303  *
 1304  * @param[in] kb  KB handle where to store the item.
 1305  * @param[in] name  Item name.
 1306  * @param[in] val  Item value.
 1307  *
 1308  * @return 0 on success, non-null on error.
 1309  */
 1310 static int
 1311 redis_set_int (kb_t kb, const char *name, int val)
 1312 {
 1313   struct kb_redis *kbr;
 1314   redisReply *rep = NULL;
 1315   redisContext *ctx;
 1316   int rc = 0, i = 4;
 1317 
 1318   kbr = redis_kb (kb);
 1319   if (get_redis_ctx (redis_kb (kb)) < 0)
 1320     return -1;
 1321   ctx = kbr->rctx;
 1322   redisAppendCommand (ctx, "MULTI");
 1323   redisAppendCommand (ctx, "DEL %s", name);
 1324   redisAppendCommand (ctx, "RPUSH %s %d", name, val);
 1325   redisAppendCommand (ctx, "EXEC");
 1326   while (i--)
 1327     {
 1328       redisGetReply (ctx, (void **) &rep);
 1329       if (!rep || rep->type == REDIS_REPLY_ERROR)
 1330         rc = -1;
 1331       if (rep)
 1332         freeReplyObject (rep);
 1333     }
 1334 
 1335   return rc;
 1336 }
 1337 
 1338 /**
 1339  * @brief Insert a new nvt.
 1340  *
 1341  * @param[in] kb        KB handle where to store the nvt.
 1342  * @param[in] nvt       nvt to store.
 1343  * @param[in] filename  Path to nvt to store.
 1344  *
 1345  * @return 0 on success, non-null on error.
 1346  */
 1347 static int
 1348 redis_add_nvt (kb_t kb, const nvti_t *nvt, const char *filename)
 1349 {
 1350   struct kb_redis *kbr;
 1351   redisReply *rep = NULL;
 1352   int rc = 0;
 1353   unsigned int i;
 1354   gchar *cves, *bids, *xrefs;
 1355 
 1356   if (!nvt || !filename)
 1357     return -1;
 1358 
 1359   cves = nvti_refs (nvt, "cve", "", 0);
 1360   bids = nvti_refs (nvt, "bid", "", 0);
 1361   xrefs = nvti_refs (nvt, NULL, "cve,bid", 1);
 1362 
 1363   kbr = redis_kb (kb);
 1364   rep = redis_cmd (
 1365     kbr, "RPUSH nvt:%s %s %s %s %s %s %s %s %s %s %s %s %d %d %s %s",
 1366     nvti_oid (nvt), filename, nvti_required_keys (nvt) ?: "",
 1367     nvti_mandatory_keys (nvt) ?: "", nvti_excluded_keys (nvt) ?: "",
 1368     nvti_required_udp_ports (nvt) ?: "", nvti_required_ports (nvt) ?: "",
 1369     nvti_dependencies (nvt) ?: "", nvti_tag (nvt) ?: "", cves ?: "",
 1370     bids ?: "", xrefs ?: "", nvti_category (nvt),
 1371     nvti_timeout (nvt), nvti_family (nvt), nvti_name (nvt));
 1372   g_free (cves);
 1373   g_free (bids);
 1374   g_free (xrefs);
 1375   if (rep == NULL || rep->type == REDIS_REPLY_ERROR)
 1376     rc = -1;
 1377   if (rep != NULL)
 1378     freeReplyObject (rep);
 1379 
 1380   if (nvti_pref_len (nvt))
 1381     redis_cmd (kbr, "DEL oid:%s:prefs", nvti_oid (nvt));
 1382   for (i = 0; i < nvti_pref_len (nvt); i++)
 1383     {
 1384       const nvtpref_t *pref = nvti_pref (nvt, i);
 1385 
 1386       rep = redis_cmd (kbr, "RPUSH oid:%s:prefs %d|||%s|||%s|||%s",
 1387                        nvti_oid (nvt), nvtpref_id (pref), nvtpref_name (pref),
 1388                        nvtpref_type (pref), nvtpref_default (pref));
 1389       if (!rep || rep->type == REDIS_REPLY_ERROR)
 1390         rc = -1;
 1391       if (rep)
 1392         freeReplyObject (rep);
 1393     }
 1394   rep = redis_cmd (kbr, "RPUSH filename:%s %lu %s", filename, time (NULL),
 1395                    nvti_oid (nvt));
 1396   if (!rep || rep->type == REDIS_REPLY_ERROR)
 1397     rc = -1;
 1398   if (rep)
 1399     freeReplyObject (rep);
 1400   return rc;
 1401 }
 1402 
 1403 /**
 1404  * @brief Reset connection to the KB. This is called after each fork() to make
 1405  *        sure connections aren't shared between concurrent processes.
 1406  *
 1407  * @param[in] kb KB handle.
 1408  *
 1409  * @return 0 on success, non-null on error.
 1410  */
 1411 static int
 1412 redis_lnk_reset (kb_t kb)
 1413 {
 1414   struct kb_redis *kbr;
 1415 
 1416   kbr = redis_kb (kb);
 1417 
 1418   if (kbr->rctx != NULL)
 1419     {
 1420       redisFree (kbr->rctx);
 1421       kbr->rctx = NULL;
 1422     }
 1423 
 1424   return 0;
 1425 }
 1426 
 1427 /**
 1428  * @brief Flush all the KB's content. Delete all namespaces.
 1429  *
 1430  * @param[in] kb        KB handle.
 1431  * @param[in] except    Don't flush DB with except key.
 1432  *
 1433  * @return 0 on success, non-null on error.
 1434  */
 1435 static int
 1436 redis_flush_all (kb_t kb, const char *except)
 1437 {
 1438   unsigned int i = 1;
 1439   struct kb_redis *kbr;
 1440 
 1441   kbr = redis_kb (kb);
 1442   if (kbr->rctx)
 1443     redisFree (kbr->rctx);
 1444 
 1445   g_debug ("%s: deleting all DBs at %s except %s", __func__, kbr->path, except);
 1446   do
 1447     {
 1448       redisReply *rep;
 1449 
 1450       kbr->rctx = redisConnectUnix (kbr->path);
 1451       if (kbr->rctx == NULL || kbr->rctx->err)
 1452         {
 1453           g_log (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
 1454                  "%s: redis connection error to %s: %s", __func__, kbr->path,
 1455                  kbr->rctx ? kbr->rctx->errstr : strerror (ENOMEM));
 1456           redisFree (kbr->rctx);
 1457           kbr->rctx = NULL;
 1458           return -1;
 1459         }
 1460 
 1461       kbr->db = i;
 1462       rep = redisCommand (kbr->rctx, "HEXISTS %s %d", GLOBAL_DBINDEX_NAME, i);
 1463       if (rep == NULL || rep->type != REDIS_REPLY_INTEGER || rep->integer != 1)
 1464         {
 1465           freeReplyObject (rep);
 1466           redisFree (kbr->rctx);
 1467           i++;
 1468           continue;
 1469         }
 1470       freeReplyObject (rep);
 1471       rep = redisCommand (kbr->rctx, "SELECT %u", i);
 1472       if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
 1473         {
 1474           freeReplyObject (rep);
 1475           redisFree (kbr->rctx);
 1476           kbr->rctx = NULL;
 1477         }
 1478       else
 1479         {
 1480           freeReplyObject (rep);
 1481           /* Don't remove DB if it has "except" key. */
 1482           if (except)
 1483             {
 1484               char *tmp = kb_item_get_str (kb, except);
 1485               if (tmp)
 1486                 {
 1487                   g_free (tmp);
 1488                   i++;
 1489                   redisFree (kbr->rctx);
 1490                   continue;
 1491                 }
 1492             }
 1493           redis_delete_all (kbr);
 1494           redis_release_db (kbr);
 1495           redisFree (kbr->rctx);
 1496         }
 1497       i++;
 1498     }
 1499   while (i < kbr->max_db);
 1500 
 1501   g_free (kb);
 1502   return 0;
 1503 }
 1504 
 1505 /**
 1506  * @brief Save all the elements from the KB.
 1507  *
 1508  * @param[in] kb        KB handle.
 1509  *
 1510  * @return 0 on success, -1 on error.
 1511  */
 1512 int
 1513 redis_save (kb_t kb)
 1514 {
 1515   int rc;
 1516   redisReply *rep;
 1517   struct kb_redis *kbr;
 1518 
 1519   kbr = redis_kb (kb);
 1520   g_debug ("%s: saving all elements from KB #%u", __func__, kbr->db);
 1521   rep = redis_cmd (kbr, "SAVE");
 1522   if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
 1523     {
 1524       rc = -1;
 1525       goto err_cleanup;
 1526     }
 1527 
 1528   rc = 0;
 1529 
 1530 err_cleanup:
 1531   if (rep != NULL)
 1532     freeReplyObject (rep);
 1533 
 1534   return rc;
 1535 }
 1536 
 1537 /**
 1538  * @brief Delete all the KB's content.
 1539  *
 1540  * @param[in] kbr Subclass of struct kb.
 1541  *
 1542  * @return 0 on success, non-null on error.
 1543  */
 1544 int
 1545 redis_delete_all (struct kb_redis *kbr)
 1546 {
 1547   int rc;
 1548   redisReply *rep;
 1549   struct sigaction new_action, original_action;
 1550 
 1551   /* Ignore SIGPIPE, in case of a lost connection. */
 1552   new_action.sa_flags = 0;
 1553   if (sigemptyset (&new_action.sa_mask))
 1554     return -1;
 1555   new_action.sa_handler = SIG_IGN;
 1556   if (sigaction (SIGPIPE, &new_action, &original_action))
 1557     return -1;
 1558 
 1559   g_debug ("%s: deleting all elements from KB #%u", __func__, kbr->db);
 1560   rep = redis_cmd (kbr, "FLUSHDB");
 1561   if (rep == NULL || rep->type != REDIS_REPLY_STATUS)
 1562     {
 1563       rc = -1;
 1564       goto err_cleanup;
 1565     }
 1566 
 1567   rc = 0;
 1568 
 1569 err_cleanup:
 1570   if (sigaction (SIGPIPE, &original_action, NULL))
 1571     return -1;
 1572   if (rep != NULL)
 1573     freeReplyObject (rep);
 1574 
 1575   return rc;
 1576 }
 1577 
 1578 /**
 1579  * @brief Default KB operations.
 1580  *
 1581  * No selection mechanism is provided yet since there's only one
 1582  * implementation (redis-based).
 1583  */
 1584 static const struct kb_operations KBRedisOperations = {
 1585   .kb_new = redis_new,
 1586   .kb_find = redis_find,
 1587   .kb_delete = redis_delete,
 1588   .kb_get_single = redis_get_single,
 1589   .kb_get_str = redis_get_str,
 1590   .kb_get_int = redis_get_int,
 1591   .kb_get_nvt = redis_get_nvt,
 1592   .kb_get_nvt_all = redis_get_nvt_all,
 1593   .kb_get_nvt_oids = redis_get_oids,
 1594   .kb_push_str = redis_push_str,
 1595   .kb_pop_str = redis_pop_str,
 1596   .kb_get_all = redis_get_all,
 1597   .kb_get_pattern = redis_get_pattern,
 1598   .kb_count = redis_count,
 1599   .kb_add_str = redis_add_str,
 1600   .kb_add_str_unique = redis_add_str_unique,
 1601   .kb_set_str = redis_set_str,
 1602   .kb_add_int = redis_add_int,
 1603   .kb_add_int_unique = redis_add_int_unique,
 1604   .kb_set_int = redis_set_int,
 1605   .kb_add_nvt = redis_add_nvt,
 1606   .kb_del_items = redis_del_items,
 1607   .kb_lnk_reset = redis_lnk_reset,
 1608   .kb_save = redis_save,
 1609   .kb_flush = redis_flush_all,
 1610   .kb_direct_conn = redis_direct_conn,
 1611   .kb_get_kb_index = redis_get_kb_index,
 1612 };
 1613 
 1614 const struct kb_operations *KBDefaultOperations = &KBRedisOperations;